--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

渣翻,内容中必然出现一些文字错误和翻译错误,有一点英文基础的童鞋最好配合原文阅读;英文基础较好的童鞋更建议直接阅读原文。

原文地址:https://downloads.openwrt.org/kamikaze/docs/openwrt.html

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

正文:

Openwrt官方入门文档

目录

1 路由器

1.1 启动

1.1.1 安装

1.1.2 初始化配置

1.1.3 故障保护模式

1.2 配置OpenWrt

1.2.1 网络

1.2.2 无线

1.3 高级配置

1.3.1 热插拔

1.3.2 初始化脚本

2 开发

2.1 构建系统

2.1.1 构建一个镜像

2.1.2 创建包

2.1.3 创建内核模块包

2.1.4 惯例

2.1.5 故障排除

2.1.6 使用构建环境

2.2 附加工具

2.2.1 镜像生成器

2.2.2 SDK

2.3 添加支持平台

2.3.1 设备支持哪个操作系统?

2.3.2 查找和使用厂商SDK

2.4 调试和debricking

2.4.1 添加串行端口

2.4.2 JTAG

2.5 错误报告

2.5.1 使用Trac 标签系统

2.6 上传补丁

2.6.1 如何贡献上传

2.6.2 何处聆听和讨论

2.6.3 补丁提交进程

第一章

路由器

1.1 启动

1.1.1 安装

1.1.2 初始化配置

1.1.3 故障保护模式

1.2 配置OpenWrt

1.2.1 网络

Kamikaze的网络配置存储在/etc/config/network 文件下分多个接口配置。每个接口配置都直接映射到一个网络/无线接口(eth0wl0,···)或者桥接多个接口。格式类似如下形式:

config interface “lan”

option ifname “eth0”

option proto “static”

option ipaddr “192.168.1.1”

option netmask “255.255.255.0”

option gateway “192.168.1.254”

option dns “192.168.1.254”

Ifname 定义了Linux的接口名,如果你想要用来桥接一个或多个接口,需要添加ifname到一个接口列表并添加如下语句:

option type “bridge”

如果使用VLAN对接口进行标记,则只需要将各个接口的VLAN ID添加到列表里,e.g. th0.1 ,则它们同样能实现互相联通。

以上简单地对eth0的源指定协议进行了简单的静态配置。默认的镜像通常使用”none”,”static”,”dhcp”和”pppoe”。其他协议可以通过安装另外的包进行协议的扩充。

当使用static”方式时就像以上例子一样,IP地址(ipaddr)和掩码(netmask)都是强制性的而网关和DNS则是可选择的,你可以定义多个网关并分配不同的可用区间。

DHCP目前仅支持ipaddr(服务器分配IP地址)和hostname(作为客户端主机名识别)——这两者都是可选择的。

PPP所基于的协议支持如下操作:

·用户名

PPP用户名(通常带有PAP认证)

·密码

PPP密码

·检测死连接

LCPping PPP服务器。其返回值定义了重连接前ping失败的最大次数限制,   间隔默认为5次,但可以通过添加”,<间隔数>”来改变检测死连接的值。

·需求

使用Dial on Demand(其值指定了最大空闲时间)

·服务器(PPTP

远程服务器IP地址

所有的协议都可以使用MTU操作来定义定义MTU

设置静态路线

你可以通过给特殊接口设置静态线路来使其在配置完成后被启动。可以像如下例子一样进行添加配置节点:

config route foo

option interface lan

option target 1.1.1.0

option netmask 255.255.255.0

option gateway 192.168.1.1

线路节点的名字是可操作的,interfacetargetgateway则是强制不可操作的;如果缺少netmask则会使线路在主机路由中循环。

设置交换机(目前仅支持博通)

交换机配置是通过添加一个switch”配置节点来进行配置的。

举例如下:

config switch “eth0”

option vlan0 “1 2 3 4 5*”

option vlan1 “0 5”

在博通的硬件设备要求节点名称必须为eth0”,否则交换机驱动将无法侦测到任何物理设备。每个vlan操作必须有其名称为vlan<n>,其中<n>为交换机驱动的vlan数字。其值带有如下所列出的后缀:

·‘ * ’:将当前VLAN设置为默认VLAN(PVID)

·‘ u ’:强制端口不标记

·‘ t ’:强制端口标记

CPU端口默认为标记,其它所有端口则默认为不标记。在博通的硬件设备上CPU端口总是5,其它端口则根据不同的硬件设备而有所变化。

例如,你想要有3vlan,分配成一个3端口交换机,1端口给隔离区(DMZ),一端口给WAN接口,则使用以下配置命令:

config switch “eth0”

option vlan0 “1 2 3 5*”

option vlan1 “0 5”

option vlan2 “4 5”

有三个接口将会因为这个开关布局而被自动创建:eth0.0(vlan0)eth0.1(vlan1)eth0.2(vlan2)。之后你可以对这些接口自行命名给一个通用配置名称,诸如“lan”“wan”“dmz”等等。

IPv6连接设置

OpenWrt上的IPv6连接支持使用PPP、隧道代理和静态分配。

如果使用的是PPP,则IPv6将会被设置成IP6CP且不需要进行任何配置操作。

要设置IPv6隧道给一个隧道代理的话,你可以安装一个叫做“6scripts”的包并编辑地址为“/etc/config/6tunnel”的文件做如下设置更改:

config 6tunnel

option tnlifname ‘sixbone’

option remoteip4 ‘1.0.0.1’

option localip4 ‘1.0.0.2’

option localip6 ‘2001::DEAD::BEEF::1’

option prefix ‘/64’

·tnlifname :在IPv4隧道设置好IPv6的接口名称

·remoteip4 :通过6in4 隧道建立的远程终端IP地址,该地址由隧道代理提供

·localip4 :建立6in4隧道的路由器IP地址,它通常对应你的WANIP地址

·localip6 :由隧道代理提供的隧道另一边的IPv6地址

·prefix LAN口设置的IPv6前缀

用同一个包你也可以设置一个IPv6桥接:

config 6bridge

option bridge ‘br6’

默认的脚本桥接了WAN口和LAN口并用以太网防火墙(ebtables)滤掉了一切非IPv6部分的东西。

IPv6静态分配的前缀也支持和IPv4相似的设置形式(当IPv6静态分配可用时):

config interface “lan”

option ifname “eth0”

option proto “static”

option ip6addr “fe80::200:ff:fe00:0/64”

option ip6gw “2001::DEAF:BEF:1”

1.2.2 无线

WiFi配置文件所在地址为:/etc/config/wireless(目前支持Broadcom、Atheros和mac80211)。当首次启动路由器的时候,路由器需要侦测到你的网卡并创建一个简单的配置文件,即默认“optionnetworklan”已经写入,如此可以阻止通过无线接口的不安全网络共享连接。

每个无线驱动拥有其唯一的配置脚本指定了驱动的特殊操作和配置,位置在“/lib/wifi/driver_name.sh”。这个脚本也叫做驱动的特殊二进制文件,就如Broadcom的wlc或者Atheros的hostapd和wpa_supplicant。使用这样的结构是因为其摘自驱动配置内容。

Broadcom的通用无线配置:

configwifi-devicewl0

optiontypebroadcom

optionchannel5

configwifi-iface

option devicewl0

#optionnetworklan

optionmodeap

optionssidOpenWrt

optionhidden0

optionencryptionnone

Atheros的通用无线配置:

configwifi-devicewifi0

optiontypeatheros

optionchannel5

optionhwmode11g

configwifi-iface

option devicewifi0

#optionnetworklan

optionmodeap

optionssidOpenWrt

optionhidden0

optionencryptionnone

mac80211的通用无线配置:

configwifi-devicewifi0

optiontypemac80211

optionchannel5

configwifi-iface

option devicewlan0

#optionnetworklan

optionmodeap

optionssidOpenWrt

optionhidden0

optionencryptionnone

Atheros的多无线配置:

configwifi-devicewifi0

optiontypeatheros

optionchannel1

configwifi-iface

option devicewifi0

#optionnetworklan

optionmodeap

optionssidOpenWrt_private

optionhidden0

optionencryptionnone

configwifi-devicewifi1

optiontypeatheros

optionchannel11

configwifi-iface

option devicewifi1

#optionnetworklan

optionmodeap

optionssidOpenWrt_public

optionhidden1

optionencryptionnone

这个文件里有两个类型的配置节点,wifi-device”映射物理wifi接口;“wifi-iface”配置则于其上虚拟接口(驱动支持的话)

一个完整的无线配置文件包含:

configwifi-devicewifidevivename

optiontypebroadcom,atheros,mac80211

optioncountryus,uk,fr,de,etc.

optionchannel1-14

optionmaxassoc1-128(broadcom only)

optiondistance1-n

optionhwmode11b,11g,11a,11bg(atheros,mac80211)

optionrxantenna0,1,2(ahteros,mac80211)

optiontxantenna0,1,2(atheros,mac80211)

optiontxpowertransmission power in dBm

configwifi-iface

optionnetworkthe interface you want wifi to birdge with

optiondevicewifi0,wifi1,wifi2,wifiN

optionmodeap,ata,adhoc,monitor,or wds

optiontxpower(deprecated)transmissionpowerin dBm

optionssidssid name

optionbssidbssid address

optionencryptionnone, wep, psk, psk2, wpa, wpa2

optionkeyencryption key

optionkey1key1

optionkey2key2

optionkey3key3

optionkey4key4

optionserverip address

optionportport

optionhidden0,1

optionisolate0,1

optiondoth0,1(atheros, broadcom)

optionwmm0,1(atheros, broadcom)

Wifi-device上的操作:

·type:选择该接口的驱动。

·country:国家代码用来确定管理机构的设置。

·channel:无线信道(1-14)取决于国家的设定。

·maxassoc:可操作,为最大相关客户端数量,这个功能只支持Broadcom芯片组。

·distance:可操作,为ap到最远客户端之间的距离,这个功能仅支持Atheros芯片组。

·mode:即频带(b, g, bg, a;这个功能仅支持Atheros芯片组。

·diversity:可操作,开启多WiFi设备;这个功能仅支持Atheros芯片组。

·rxantenna:可操作,接收天线标识符;该功能仅Atheros和部分Broadcom芯片支持。

·txantenna:可操作,发送天线标识符;该功能进Atheros和部分Broadcom芯片支持。

·txpower设置了无线的传输功率大小,单位为dBm

Wifi-iface上的操作:

·network:从“etc/config/network”中选择要用的接口节点。

·device:设置wifi设备名称

·mode:可配置为如下模式:

ap:接入点模式

sta:客户端模式

adhoc:点对点模式

monitor:监听模式

wdsWDS 点对点连接

·ssid:设置wifi设备的SSID

·bssid:设置其他wds单元的mac地址

·txpower:(具体上限由wifi设备硬件决定)设置无线传输功率,单位为dBm

·encryption:加密设置,指出如下设定:

none

wep

pskpsk2

wpawpa2

· key, key1, key2, key3, key4 :(wep, wpa, psk)WEP密钥,WPA密钥或RADIUS密钥WPA  RADIUS模式)

·serverwpa):RADIUS服务器IP地址

·portwpa):RADIUS服务器端口(默认为1812

·hidden0,不隐藏SSID; 1,影藏SSID

·isolate:可操作,隔离操作最为一种模式通常设置在热点上以限制客户端仅能通AP进行连接而无法连接其他无线设备。

0,关闭AP隔离(默认);

1,开启AP隔离.

·doth:可操作,切换802.11h模式。

0,关闭802.11h(默认)

1,开启802.11h

·wmm:可操作,切换802.11e模式。

0,关闭802.11e(默认)

1,开启802.11e

无线分布系统WDSWDS是一种非标模式工作在两台Broadcom设备而无法在一个Broadcom设备和一台Atheros设备之间作用工作。

非加密WDS连接:以下例子用于展示如何设置好非加密WDS连接。可以确定BSSID应为“ca:fe:ba:be:00:01,远程WDS终端为“ca:fe:ba:be:00:02”。

例:

configwifi-devicewl0

optiontyoebroadcom

optionchannel5

configwifi-iface

optiondevicewl0

optionnetworklan

optionmodeap

optionssidOpenWrt

optionhidden0

optionencryptionnone

configwifi-iface

optiondevicewl0

optionnetworklan

optionmodewds

optionssidOpenWrt WDS

optionbssidca:fe:ba:be:00:02

加密WDS连接:对WDS连接加密也是可能实现的,pskpsk2psk+psk2模式都支持这种连接,使用SES算法的预共享密钥配置如下举例所示:

例:

configwifi-devicewl0

optiontypebroadcom

optionchannel5

configwifi-iface

optiondevicewl0

optionnetworklan

optionmodeap

optionssidOpenWrt

optionencryptionpsk2

optionkey<key for clients>

configwifi-iface

optiondevicewl0

optionnetworklan

optionmode wds

optionbssidca:fe:ba:be:00:02

optionssidOpenWrt WDS

optionencryptionpsk2

optionkey<psk for WDS>

802.1x 配置OpenWrt同时支持802.1x客户端和接入点的配置。802.1x客户端仅在Atherosmac80211驱动上工作,其配置仅支持EAPTLSTTLSPEAP类型。

EAP-TLS:

config wifi-iface

option device         "ath0"

option network        lan

option ssid           OpenWrt

option eap_type       tls

option ca_cert        "/etc/config/certs/ca.crt"

option priv_key       "/etc/config/certs/priv.crt"

option priv_key_pwd   "PKCS#12 passphrase"

EAP-PEAP:

config wifi-iface

option device         "ath0"

option network        lan

option sid           OpenWrt

option eap_type       peap

option ca_cert        "/etc/config/certs/ca.crt"

option auth           MSCHAPV2

option identity       username

option password       password

局限性:模式的组合是有局限性的,仅以下模式支持组合使用:

·Broadcom

·1x  sta 0-3x  ap

·1-4x  ap

·1x  adhoc

·1x  monitor

WDS连接仅被用于纯AP模式切无法使用WEP(当被主动设置为主接口时除外)

·Atheros

·1x  sta, 0-Nx  ap

·1-Nx  ap

·1x  adhoc

N是指模块允许的最大VAP数,默认为4,但可通过载入 maxvaps=N名来来改变值的大小。

添加一个新的驱动配置:目前仅支持对多线程的无线驱动进行配置:BroadcomAtherosmac80211,如果有兴趣可以自己尝试添加其它驱动的支持,例如Rlink RT2x00Texas Instruments ACx100/111的驱动。

驱动特定脚本必须为/lib/wifi/<驱动>.sh”,且必须包含以下函数:

·侦测当前驱动

·打开/关闭 wifi接口

·配置为可读可写可执行

·第三方程序调用(网络附属存储NAS,请求)

每个驱动脚本必须将驱动追加一个全局驱动变量:

appendDRIVERdriver name

scan_<driver>:这个函数将会解析/etc/config/wireless”并确认配置是否兼容,例如打开ad-hoc模式同时影藏SSID。如果你的驱动支持很多配置操作则会变得更加复杂。该函数不改变接口的实际状态。

例:

scan_dummy()

{

local device="$1"

config_get vifs "$device" vifs

for vif in $vifs; do

# check config consistency for wifi-iface sections

done

# check mode combination

}

enable_<driver>:这个函数将会唤起wifi设备并任意创建应用特别配置文件,例如发起请求或WPA认证。

例:

enable_dummy()

{

local device="$1"

config_get vifs "$device" vifs

for vif in $vifs; do

# bring up virtual interface belonging to

# the wifi-device "$device"

done

}

disable_<driver >:这个函数将会关闭wifi设备和它所有的虚拟接口(如果该设备支持的话)。

例:

disable_dummy()

{

local device="$1"

# bring down virtual interfaces belonging to

# "$device" regardless of whether they are

# configured or not. Dont rely on the vifs

# variable at this point

}

Detect_<driver>:这个函数会寻找驱动可用的接口,新设备配置节点模板需写入为标准输出,且在创在模板之前必须对所属接口的已存在配置节点进行检测。

例:

detect_dummy()

{

[ wifi-device = "$(config_get dummydev type)" ] && return 0

cat <<EOF

config wifi-device dummydev

option type dummy

# REMOVE THIS LINE TO ENABLE WIFI:

option disabled 1

config wifi-iface

option device dummydev

option mode ap

option ssid OpenWrt

EOF

}

 

1.3 高级配置

配置文件结构:

配置文件内容可分为节点和操作/赋值。

每个节点有它的类型,节点名称则是不一定必要的;每个操作有个名称和制且写在所在节点之下。

语法:

config      <type> ["<name>"]      # Section

option  <name> "<value>"       # Option

每个参数必须为单字节字符且格式必须和壳函数参数一样准确。和壳的规则一致,特殊字符同样可用。

在通用脚本里解析配置文件:

要使能正常载入配置文件,你需要使通用函数包含以下部分:

· /etc/functions.sh

然后你可以用config_load <name>”来载入配置文件,该函数首先检测<name>(绝对地址文件名)再跳转回从“/etc/config”下载入配置文件(这是使用配置文件最常用的方法)。

如果你想用与或方式进行特殊跳转,你需要在使用config_load前定义如下的壳函数(包含 /etc/functions.sh 后):

config_cb()

{

local type="$1"

local name="$2"

# commands to be run for every section

}

option_cb()

{

# commands to be run for every option

}

你同样可以改变基于节点类型的config_cb下的option_cb。它可以使之允许对节点类型下单一配置节点独立执行。

config_cb总是在新节点启动时运行(在节点下其他操作执行之前),它可以通过CONFIG_SECTION 变量对上一节点进行处理。而且在config_load完成后将会有一个额外的用用(无新节点运行),如此可以使上一个节点和下一个节点的所有操作都能被执行。

另一种配置节点迭代执行的方法是使用config_foreach命令。

语法:

config_foreach <function name> [<sectiontype>] [<arguments...>]

这个命令可以使每个单一配置节点在当前载入的配置中运行,节点名称则会作为依据1而被传递给函数,如果节点类型已添加在命令行,则函数会仅运行命令行所写的配置类型。

你可以通过使用config_get命令来处理已执行过的操作。

语法:

# print the value of the option

config_get <section> <option>

# store the value inside the variable

config_get <variable> <section> <option>

busybox ash中三线程的config_get会运行的更快速一点,因为它不会导致额外的交叉,是更为合适的一种方式。

另外你可以通过config_set命令对节点操作进行修改或添加。

语法:

config_set <section>  <option>  <value>

如果一个节点未命名,则系统会自动命名,如:cfg1cfg2,等。

1.3.1 热插拔

1.3.2 初始化脚本

由于OpenWrt使用的是自己独有的初始化脚本系统,所有初始化脚本都必须安装为“/etc/init.d/name”的形式用“/etc/rc.common”进行封装。

例: /etc/init.d/httpd

#!/bin/sh /etc/rc.common

# Copyright (C) 2006 OpenWrt.org

START=50

start()

{

[ -d /www ] && httpd -p 80 -h /www -r OpenWrt

}

stop()

{

killall httpd

}

就如例子中所见,脚本实际上并未解析命令行论据本身,而是由封装脚本/etc/rc.common”处理。

Start()stop()是基本函数,几乎所有的初始化脚本都有这两个函数。Start()在用户运行启动“/etc/init.d/httpd”时或者系统在启动过程中(脚本是使能的且在这个行为中未被重写)会被调用。

初始化脚本可以通过运行/etc/init.d/name”启动或关闭,运行过程中创建或移除的符号均位于“/etc/rc.d”文件内——这个文件在启动过程中会由“/etc/init.d/rcS”处理。

这些脚本运行用到的指令都定义在初始化脚本的START变量下面,修改后需要重新运行“/etc/init.d/name”一次。

你自己可以重写如下这些初始化脚本函数:

·boot()

启动过程中会被运行的命令,默认到start()

·restart()

重启服务,默认到styop();start()

·reload()

为服务重新加载配置文件,默认到restart()

例:

status()

{

# print the status info

}

EXTRA_COMMANDS="status"

EXTRA_HELP="        status  Print the status of the service"

1.3.3 网络脚本

使用网络脚本:

要使能成功执行网络相关的函数,需要运行以下这些所必须的壳脚本:

. /etc/functions.sh       # 通用函数 
   include /network      # include /network/*.sh 
   scan_interfaces         # 读取并解析网络配置

一些像PPP一样的协议在运行时候会改变配置接口名称(例:PPPoE拨号时会由eth0 => ppp0),这就是为何我们要运行scan_interface而不是直接读取配置文件下具体值的原因了。在运行过scan_interface后,“ifname”选项将始终会是那个有效的接口名称(使用IP流量),并且加入物理设备的名称区别于它,它将会被存储在“device”选项下,这也就意味着运行config_get lan ifname scan_interfaces 将不一定会返回和之前运行时相同的结果。

在运行完scan_interfaces后,一下函数将有效:

·find_config interface

查找已定义网络接口的网络配置。

·setup_interface interface [config] [protocol]

它会将已定义接口的网络名称和所使用的协议重写。

编写协议处理程序:

你可以通过添加壳脚本到/etc/network”下来添加通用协议,以下挺了两种壳函数:

scan_<protocolname>()

{

local config="$1"

# change the interface names if necessary

}

setup_interface_<protocolname>() {

local interface="$1"

local config="$2"

# set up the interface

}

scan_protocalname 是可操作的而且仅在协议在通用设备上使用时才是必须的。例:隧道或PPP设备。

第二章

开发

2.1 构建系统

要在一个嵌入式设备上成功启动的一个最大问题之一是:无法仅仅安装一个Linux的复制包并要求它能编译出一个固件,而且你还需要安装每种用到的开发工具和一个编译器并将它们配置好以便于去编译固件。一个嵌入式设备代表着一个区别于且不兼容于你用于开发系统的计算机设备不同全新硬件平台,故而在交叉编译的过程中需要新生成一个用来生成适用于那台嵌入式平台代码的可用编译器,并用之编译出一个linux发行版来运行那个嵌入式设备。

创建一个交叉编译的机制可以是很复杂的,因为经过反复尝试后仍然存在着一定的神秘性和黑魔法。在很多案例中,在你要处理一个嵌入式设备的时候,你将会被提供一个编译器二进制副本和一些基本的库而不是让你直接创建一个自己的架构——这样可以使你节约工作步骤但同时却也意味着你需要使用过时的工具。同样的,得到由芯片供应商或上级合作人提供的linux内核补丁也是很常有的事,但这些被改动过的内核也同样过时且将很难再进行正确矫而使其在嵌入式平台上运行的更加流畅。

2.1.1 构建镜像

OpenWrt使用了一个迥异的方法来构建固件,包括下载、修补、编译和交叉编译都通过scratch这个简易编译工具进行。简单的说,OpenWrt不包含任何可执行文件和源代码,它使一个用于下载源代码,并修补和编译使之能正确工作在所要求的平台的自动化系统,也就是说,只需要修改特定的模块,就能改变进程中的任何步骤。

举个例子说明,如果一个新的内核发布,简单的修改某个Makefile就能下载到最新的内核文件,修复并运行在嵌入式设备上并生成一个新的固件镜像——你不需要做任何事来追踪一个现有内核的未定义副本来查看哪些部分被修改了,补丁已经执行完成了而你几乎感觉不到,这个方法不仅仅适用于内核,它适用于整个OpenWrt系统——这是一个简单的概念使OpenWrt始终保持在拥有最新编译器、最新内核、最新应用的前沿。

所以,让我们好好了解一下OpenWrt,看看它都是怎么工作的吧。

下载OpenWrt

本节使用的源代码为OpenWrt下的“kamikaze”分支。它可以使用以下命令进行通过subversion下载:

$ svn checkout svn://svn.openwrt.org/openwrt/trunk kamikaze

另外,在http://dev/openwrt.org/”上有个trac接口可以用来监听svn行为和浏览源代码库。

目录结构:

以下是四个关键目录:

·tools

·toolchain

·package

·target

Toolstoolchain下是一些用来构建固件固件镜像的工具、编译器和c语言库。造成这一结果的是三个新的目录:build_dir/host,用来存放构建目标文件的独立工具的目录;build_dir/toolchain-<arch>*,用来存放构建特殊结构工具链的目录;staging_dir/toolchain-<arch>*,用来存放所安装好的工具链。你对工具链目录不需要做任何改动除非你希望给其中一个元件添加新的版本。

·build_dir/host

·build_dir/toolchain-<arch>*

package字如其名——用来存放安装包。在一个OpenWrt固件里,几乎所有包都封装成.ipk格式的,这样可以节约固件被所添加的软件包占用的空间。要注意的是固件之外的安装包也是ipk格式的,且可以用包补给系统通过subversion获得:

$ ./scripts/feeds update

这些安装包可以拓展所构建系统的功能且必须动态链接到主干上,当这么操作之后,安装的功能将在配置菜单中可以看见,在kamikaze固件上你能做如下的操作:

$ ./scripts/feeds serch nmap

在补给结果中寻找nmap”安装包;网络探索与或安全审计效用。

$ ./scripts/feeds install nmap

要包含所有的包,键入一下命令:

$ make package/symlinks

target指的是嵌入式平台,涵盖一个特殊嵌入式平台的特殊项目。有意思的是,“target/linux”目录是分解自<arch>平台且包含了特别平台的内核补丁、配置简介。该目录还有一个“target/image”目录描述了一个特殊平台如何封装固件。

不管是target还是package在编译过程中都会使用“build_dir/<arch>”作为临时目录。另外,在编译过程中,不管是被下载下来的工具链、目标文件、包,都会被放置在“dl”目录下。

·build_dir/<arch>

·dl

构建OpenWrt

OpenWrt环境已经由开发者构建好了之后,那么即使是对毫无经验的用户来说构建起他们自己的通用固件也是一件非常简单的事情。

运行make menuconfig”命令将会启动OpenWrt的配置菜单,你可以通过这个配置菜单选择好要构建的目标平台、要使用的工具链版本、要安装到固件里的功能包等。要注意的是系统也会检测和确认基本归属以保证能正确运行,如果失败了,你需要在本地环境安装更多的工具知道能满足条件启动配置菜单。

linux 内核配置相似的是,OpenWrt每个配置选项都有三种选择:

·<*> (键入y

这个选项将会被包含在固件镜像里。

·<M>(键入m

这个选项将会被编译但并不包含在固件里(可以在之后安装)。

·< >(键入n

这个选项将不会被编译。

当你完成了配置菜单的操作之后,保存配置改变并退出。

如果你还想修改所选目标系统的内核配置,运行make kernal_menuconfig”命令,构建系统将会打开内核源代码(如果必要)以在内核树上运行配置菜单,然后会拷贝内核配置内容到“target/linux/<platform>/config”并保留到调用“make clean”命令之前。

键入make”开始编译固件,OpenWrt默认只显示编译进程的高级概述而不是细节的独立命令行。

例:

make[2] toolchain/install

make[3] -C toolchain install

make[2] target/compile

make[3] -C target compile

make[4] -C target/utils prepare

[...]

如此可以更简便地监听实际编译过程中都执行了哪些步骤,还能减少编译时输出的大量的垃圾信息,要想看完成的输出信息,则要运行make V=99”命令。

在编译过程中,编译工具将会把所有的源代码下载到dl”目录下并开始在“build_dir<arch>”目录下修补和编译它们。当编译完成后,固件将会被存储在“bin”目录下,包文件将会被放置在“bin/package”目录下。

2.1.2 创建包

我们在OpenWrt模板系统上已经做好的一件事情是是OpenWrt的软件端变得难以置信的简单化,当你查看一个OpenWrt下的包目录是,可以看到如下文件:

·package/<name>/Makefile

·package/<name>/patches

·package/<name>files

补丁目录是可操作的而且通常包含bug修复或者优化以减少可执行文件的大小。Package makefile提供了下载和编译包的实际步骤详情。

文件夹目录也是可操作的且通常包括封装的特殊启动脚本和默认配置文件,这些文件在OpenWrt中都可以被使用。

我们来看一下一个package makefile,我们很难能认出这是一个makefile。忽视掉这些通用的格式,整个makefile已经被转化成一个面向对象的模板而简化编写makefile的难度。

例: package/brdge/Makefile:

1  # $Id: Makefile 5624 2006-11-23 00:29:07Z nbd $

2

3  include $(TOPDIR)/rules.mk

4

5  PKG_NAME:=bridge

6  PKG_VERSION:=1.0.6

7  PKG_RELEASE:=1

8

9  PKG_SOURCE:=bridge-utils-$(PKG_VERSION).tar.gz

10  PKG_SOURCE_URL:=@SF/bridge

11  PKG_MD5SUM:=9b7dc52656f5cbec846a7ba3299f73bd

12  PKG_CAT:=zcat

13

14  PKG_BUILD_DIR:=$(BUILD_DIR)/bridge-utils-$(PKG_VERSION)

15

16  include $(INCLUDE_DIR)/package.mk

17

18  define Package/bridge

19    SECTION:=net

20    CATEGORY:=Base system

21    TITLE:=Ethernet bridging configuration utility

22    URL:=http://bridge.sourceforge.net/

23  endef

24

25  define Package/bridge/description

26    Manage ethernet bridging:

27    a way to connect networks together to form a larger network.

28  endef

29

30  define Build/Configure

31      $(call Build/Configure/Default, \

32          --with-linux-headers="$(LINUX_DIR)" \

33      )

34  endef

35

36  define Package/bridge/install

37      $(INSTALL_DIR) $(1)/usr/sbin

38      $(INSTALL_BIN) $(PKG_BUILD_DIR)/brctl/brctl $(1)/usr/sbin/

39  endef

40

41  $(eval $(call BuildPackage,bridge))

如例子中所见,还有很多工作都为直接呈现在里面,很多都工作内容都被隐藏在其它的makefile里面,抽象到你只需要定义一些变量就可以了。

·PKG_NAME

包的名称,可以通过menuconfigipkg查看

·PKG_VERSION

下载的包的版本号

·PKG_RELEASE

Package Makefile的版本

·PKG_SOURCE

源码文件名

·PKG_MD5SUM

用来验证下载文件的验证和

·PKG_BUILD_DIR

在该目录下编译包

PKG_* 变量定义了要下载的包的地址。@SF是从sorceforge.net下载包是需要的特殊关键词;@GNU是下载发布的GNU源的特殊关键词。如果以上提到的任何源失效了,OpenWrt镜像都将被用来作为源。

MD5SUM(当前的)是用来验证包是否下载正确的,PKG_BUILD_DIR则是用来在源代码没有被压缩在 $(BUILD_DIR) 查找后查找包用的。

在文件的底部才是魔法真正发生的地方,BuildPackage”是在早期include声明的宏设定,BuildPackage只有一个作用——要构建的包的名称,就如本例子中“bridge”;其他的所有信息都在定义块区声明,这样提供了一定程度的冗长,能清晰的描述出Package/bridge的描述模板目录,这样我们可以直接使用这个目录中的第N个参数进行BuildPackage

BuildPackage使用如下定义:

<name>l连接通过编译器的参数,描述了包的配置菜单和ipkg(包管理系统)条目,在Package/<name>里可以定义如下变量:

·SECTION

包类型(非当前使用的)

·CATEGORY

出现在配置菜单里的子菜单,包括网络、声音、功用、多媒体等选项

·TITLE

包概述

·URL

源软件的地址

·MAINTAINER(可操作)

包相关文件

·DEPENDS(可操作)

构建/安装 包时需要的已有的包文件,可用<dependency name>参考定义于同一   Makefile下的附属定义,如果被定义成拓展包,则使用 +<dependency name> 。要   查阅内核版本所属,可以用@LINUX_2_<minor version>”命令。

·BUILDONLY(可操作)

如果不想包在配置菜单中显示,可将该选项置1,此操作只在构建包附属的时候   有用。

Package/<name>/conffiles(可操作):

包里已安装的配置文件列表,一个文件一行。

Build/Prepare(可操作):

打开和修复源码的一套工具,你可以不定义它而安全离开。

Build/Configure(可操作):

如果源码未进行配置或者有一个常规配置脚本则你可以不定义它直接离开,或者你可以在这里加入自己的命令或用$(call Build/Configure/Default,<first list of arguments, second list>”在标准配置脚本中加入额外的参数。参数的第一列表将会以类似“-arg 1 -arg 2”的形式加入到配置脚本中,而且需要在配置脚本运行前就已经定义成autoconf或者编译器特殊变量。

为了简化配置命令行的修改,也可以拓展或重写以下变量:

·CONFIGURE_ARGS

包含全部命令行参数(格式: -arg 1 -arg 2

·CONFIGURE_VARS

包含 ./configure下全部环境变量(格式:NAME=”value”)

Build/Compile(可操作):

在大部分情况下需要不定义该选项以编译源码。

Build/Configure选项中有两个变量允许重写编译命令行的环境变量和标志位:

·MAKE_FLAGES

包含全部命令行参数(典型的变量重写形式如: NAME=”value”)

·MAKE_VARS

包含编译命令的全部环境变量

Build/InstallDev(可操作):

要使包里提供的库在其它包中有效,你可以使用Build/InstallDev模板来拷贝这个库里将要在其它包中的所用的文件到一个分段目录下,当在构建系统时候被调用时,会有两个参数被添加到其中:$(1) 指向常规分段目录,如staging_dir/ARCH$(2)指向staging_dir/host。只有主分段目录是二进制的,它直接执行和链接到主目录且它的 bin/ 子目录包含在构建系统进程的PATH里。这里使用$(1)$(2)而不是构建系统参数$(STAGING_DIR)$(STAGING_DIR_HOST)是因为构建系统行为在未来中转库操作是变成包含自动卸载操作。

Package/<name>/install

$(1)目录下的一套可以从编译好的源码中拷贝文件到ipkg的命令。注意命令中当前定义了4个安装宏:

·INSTALL_DIR

install -d -m0755

·INSTALL_BIN

install -m0755

·INSTALL_DATA

install   -m0644

·INSTALL_CONF

install   -m0600

一些定义的前缀用Package/<name>”而其他的单纯用“Build”的原因是我们有可能基于同一源码编译多个包。OpenWrt是基于每个包下的Makefile工作的,但你可以将源码分解成多个包,假如你想的话。你只要编译一次源代码,就会有一个“Build”的全局定义被设定起来,你可以通过添加额外的调用命令来添加尽可能多的“Package/<name>”定义到BuidPackage里面——可以参考dropbear目录。

在创建完 package/<name>/Makefile 后,新的包将会在下一次执行“make menuconfig”后自动出现在配置菜单里,假如包被选中的话,会在下次执行“make”命令后被编译进去。

2.1.3 创建内核模块包

OpenWrt分布将不同内核模块区别开来,分成主核心内核和其他可独立其外的内核,下面将举例说明一个两种内核通用的模板。

主核心内核的源码,它们的makefile位于“package/kernel/modules/*.mk”,出现在“Kernel modules”节点下。

外部内核模块,可以通过在package makefile下定义一个“KernelPackage”节点后,像添加软件包一样将它们添加都构架系统中。

例:I2C传输系统内核模块

1  # $Id $

2

3  I2CMENU:=I2C Bus

4

5  define KernelPackage/i2c-core

6    TITLE:=I2C support

7    DESCRIPTION:=Kernel modules for i2c support

8    SUBMENU:=$(I2CMENU)

9    KCONFIG:=CONFIG_I2C_CORE CONFIG_I2C_DEV

10    FILES:=$(MODULES_DIR)/kernel/drivers/i2c/*.$(LINUX_KMOD_SUFFIX)

11    AUTOLOAD:=$(call AutoLoad,50,i2c-core i2c-dev)

12  endef

13  $(eval $(call KernelPackage,i2c-core))

要将内核模块用一个通用描述集合到配置菜单里,需要在内核模块的makefile的顶端定义一个 <descriptin>MENU 变量。

·TITLE

通过配置菜单可看见的模块名称

·DESCRIPTION

通过配置菜单的帮助可看见的描述

·SUBMENU

这个包中可以看见的传输列表

·KCONFIG

内核配置附属操作,在外部模块,要将它移除

·FILES

这个内核模块包里你想要包含的文件,分配一定的空间

·AUTOLOAD

模块将会在启动时自动载入,你写了什么就会载入什么

在创建完 package/kernel/modules/<name>.mk 后,新的内核模块包将会在下一次执行“make menuconfig”后自动出现在“Kernel modules”目录下,如果它被选中后,则会在下次执行“make”后自动被编译进去。

2.1.4 惯例

相关包遵循一下两个惯例;
·files

1.配置文件遵循 <name>.conf

2.初始化文件遵循 <name>.init

·patches

1.补丁名为数字前缀加补丁功能

2.1.5故障排除

当发现我们自己的包在配置菜单上没有显示出来的时候,试着使用以下命令来查看是否获取到正确的概述:

TOPDIR=$PWD make -C package/<name> DUMP=1 V=99

如果只是在编译包过程中出现故障,这里有一些快捷方式可以使用,可以直接运行以下命令:

·make package/<name>/clean V=99

·make package/<name>/install V=99

还有个小技巧是如果build_dir/<arch>下的源码目录比包目录更新,那么我们无需再解压源代码;如果是在运行一个补丁文件,则可以简单编辑build_dir/<arch>/<source>目录下的源码后再运行以上提及的安装命令,在安装完成后,把打完补丁的源码拷贝到其它地方并与那些未打好补丁的源码区别开来。这里需要提醒一下,在package/<name>下修改任何源码都会移除旧的源码并打开新的副本。

其它有用的命令还有:

·make package/<name>/prepare V=99

·make package/<name>/compile V=99

·make package/<name>/configure V=99

2.1.6 使用构建的环境

OpenWrt提供了一种对构建镜像进行多重配置的手段,可以使多个目标放在一个单子中。这些环境由“make menuconfig”生成并保存为一份“.config”格式的文件放置在“./files”文件夹下。“./scripts/env”脚本就是用来管理这些环境,它使用的是git(该命令需要额外安装)命令来作为后台版本控制。

./scripts/env help”命令提供了命令列表下命令的简单帮助文本。

如果要创建一个名为current”的环境,使用“./scripts/env new current”命令。这个命令会移动“.config”文件和“./fliles(如果有)”目录到“env/”目录下作为子目录存在并在库文件夹中创建一个符号链接。

在运行完make menuconfig”或修改过“files/”目录下东西后,当前所处的系统状态就会区别于上一次保存时的状态,要显示具体的改变,则运行:

./scripts/env/ diff

如果要保存这些修改,则:

./scripts/env sava

如果要恢复上一次保存的状态,则

./scripts/env revert

如果还想创建第二个环境,运行new”命令,系统会询问是否要复制当前环境状态(例:用来作为镜子对比)还是开启一个空白环境(例:用来选择新的目标设备时用)。如果要切换到另一个环境中,则

./scripts/env switch test1

要重命名当前环境分支,则

./scripts/env rename test2

要离开环境重新回到库目录下,则、

./scripts/env clear

2.2 附加工具

2.2.1 镜像生成器

2.2.2 SDK

2.3 添加支持平台

Linux因为其开源特质和适用于非常广泛的应用平台而成为当今世界上使用最广的嵌入式操作系统之一,很多设备都有基于Linux系统固件的产品,例如DVB-T 解码器、路由器、打印机、DVD播放器等。大多数固件都是不开放给客户的,即使使用的是开源的软件。

之所以选择使用基于Linux固件来运行一台路由器的原因有很多个:可延伸使用网络协议(例如IPv6)、会有新功能、新的软件、还有安全性。当你要在一个完全开源的固件上开发应用时,你需要针对一些特殊的bug进行更正。一些制造商利用样品开发工具包来实现应用开发,有了这些工具包,大部分时间你在创建自己的通用固件时甚至都不需要创建特别的固件编译进程。这也就是存在许多版本的OpenWrt系统的原因之一了,使用不同的工具和不同版本的系统都能载许多平台上使用,不过根本还是基于Linux的。

2.3.1 设备支持哪个操作系统?

有很多方法可以确认设备使用的系统是否为Linux,一些方法需要路由器出于打开状态,而也有一些方法可以通过其他网络接口进行探测。

操作系统识别和端口扫描:

网上有一大堆的工具可以帮助你识别你的操作系统,以下举例使用nmap”命令进行识别。

例:

nmap -P0 -O <IP address>

Starting Nmap 4.20 ( http://insecure.org ) at 2007-01-08 11:05 CET

Interesting ports on 192.168.2.1:

Not shown: 1693 closed ports

PORT   STATE SERVICE

22/tcp open  ssh

23/tcp open  telnet

53/tcp open  domain

80/tcp open  http

MAC Address: 00:13:xx:xx:xx:xx (Cisco-Linksys)

Device type: broadband router

Running: Linksys embedded

OS details: Linksys WRT54GS v4 running OpenWrt w/Linux kernel 2.4.30

Network Distance: 1 hop

nmap命令能够报告你的设备是否使用LinuxTCP/IP堆栈,如果是,则会显示出所使用的Linux内核版本。Nmap命令返回的报告可以泣别出BSDLinuxTCP/IP堆栈及其他,可行度很高。

使用统一工具也能实现端口扫描和服务版本探测,例如以下命令就能报告设备运行的IP服务和所使用的服务版本。

例:

nmap -P0 -sV <IP address>

Starting Nmap 4.20 ( http://insecure.org ) at 2007-01-08 11:06 CET

Interesting ports on 192.168.2.1:

Not shown: 1693 closed ports

PORT   STATE SERVICE VERSION

22/tcp open  ssh     Dropbear sshd 0.48 (protocol 2.0)

23/tcp open  telnet  Busybox telnetd

53/tcp open  domain  ISC Bind dnsmasq-2.35

80/tcp open  http    OpenWrt BusyBox httpd

MAC Address: 00:13:xx:xx:xx:xx (Cisco-Linksys)

Service Info: Device: WAP

如果知道web服务器版本也能确定是哪种操作系统,例如:BOA web服务器就是典型基于开源Unix或类unix系统的web服务器。

无线通信识别:

有种并不被普遍认知的方法就是使用无线扫描器来发现操作系统类别和接入端使用情况,目前暂时没有明确的例子来证明真的可以确定这种方法可用,因为这需要监听原生802.11框架并和一台我们熟知的基于Linux固件的设备进行对比才有望发现。

Web服务器安全漏洞:

曾经发现过在Linksys WRT54G路由器的web接口可以使用“ping bug”命令来侵入设备系统,而且这个问题Linksys公司持续好几个月之后才会确定了问题所在,这个bug允许了用户通过web接口打开“boot-wait”帮助进程。许多固件里使用的web服务器都是开源的web服务器,因此web服务器的代码可以被很多人审计而发现漏洞,如果你知道自己web服务器的版本,你可以通过使用“nmap -sV”命令来进行代码审计,也或许你会对使用漏洞进入设备的壳数据感兴趣呢。

本地Telnet/SSH访问:

一些固件对Telnet/SSH访问可以设置受限与否的,如果可以访问,则可以在web接口键入用户名和密码之后登陆,而且还能于其上键入一些命令。可见于一些基于Broadcom BCM963XX开发的固件产品,例如Neuf/Cegetel ISP路由器、Club-Iternet ISP CI-Box等。一些例如cat命令等可以用来确定Linux内核版本。

分析一个二进制固件镜像:

在一些制造商的网站上很可能能找到一些固件镜像文件,甚至是你设备专有的那个操作系统也能找到。如果有,则可以将它下载下来,用诸如vmlinuxlinuxramdiskmtd等十六进制编辑器来打开它。

一些例如hexdumpstringUnix工具可以用来分析固件,以下例子是一个载自互联网的二进制固件的内容:

例:

hexdump -C <binary image.extension> | less (more)

00000000  46 49 52 45 32 2e 35 2e  30 00 00 00 00 00 00 00   |FIRE2.5.0.......|

00000010  00 00 00 00 31 2e 30 2e  30 00 00 00 00 00 00 00   |....1.0.0.......|

00000020  00 00 00 00 00 00 00 38  00 43 36 29 00 0a e6 dc    |.......8.C6)..??|

00000030  54 49 44 45 92 89 54 66  1f 8b 08 08 f8 10 68 42 |TIDE..Tf....?.hB|

00000040  02 03 72 61 6d 64 69 73  6b 00 ec 7d 09 bc d5 d3   |..ramdisk.?}.???|

00000050  da ff f3 9b f7 39 7b ef    73 f6 19 3b 53 67 ea 44     |???.?9{?s?.;Sg?D|

滚动固件内容可以找到重要的输出信息。

闪存大小:

Linux不适合2MB闪存大小的设备使用,如果设备成功打开了,可以试着在网上查找一下设备的特性,如果闪存确实为2MB甚至更小,那么设备运行的可能是个专门的系统,例如WindRiver VxWorks,或通用制造商操作系统如Zyxel ZynOS

OpenWrt当前并不支持在2MB或以下闪存大小的设备上运行,当一些微路由器或无线接入设备不是使用主流OpenWrt系统是这条限制可能不受限制。

加入串行端口:

通过使用串行端口和电平移相器,可以连接设备控制器以达到刷入和调试程序的目的。通过分析设备的输出信息就能轻易的知道设备的内核信息和一些其他信息。

2.3.2 查找和使用厂商SDK

当你确定设备运行的是基于linux的固件后,就可以尝试侵入它了,如果厂商尊重GPLGNU通用公共许可证)条款,会发布一个硬件设备配套的样品开发工具包的。

GPL违法行为:

某些厂商在发布了基于Linux的二进制固件后,不附上源码。遇到这种事情的时候需要做的第一件是就是阅读设备的许可证书,然后根据证书写下缺少开源代码。如果厂商答复说他们没有必须得发布包含开源软件的SDK,则建议你与gpl-violation协会取得联系。

以下为给厂商写信的样本:

Miss, Mister,

I am using a <device name>, and I cannot find neither on your website nor on the CD-ROM the open source software used to build or modify the firmware.

In conformance to the GPL license, you have to release the following sources:

complete toolchain that made the kernel and applications be compiled (gcc, binutils, libc)

tools to build a custom firmware (mksquashfs, mkcramfs ...)

kernel sources with patches to make it run on this specific hardware, this does not include binary drivers

Thank you very much in advance for your answer.

Best regards, <your name>

使用SDK

如果有个SDK是可获取到的,那么你很可能无法构建一个完整的功能性固件来使用它,除了内核或根目录文件系统。大部分厂家并不关心每个工具都得实时在解压和执行,但无论如何你都需要能对一下元件进行操作:

·关于硬件功能补丁的讷河源码

·链接或将要链接到装载的内核版本上的二进制驱动

·用于编译整个固件的故居连包,包括:gccbinutilslibcuClibc

·创建有效固件镜像的二进制工具

将会分布成一下几个任务:

·创建一个匹配Linux内核关于硬件部分的空白补丁包

·点出违反GPL规定内容的部分,尤其是网络过滤器和USB堆栈

·让二进制驱动工作,知道开源驱动部分

·理解和编写开源工具来生成一个有效的固件镜像文件

创建特殊硬件内核补丁:

通常情况下,SDK下的内核源码都不是很纯粹,而且不是一个标准的Linux版本,其结构大多糅合和内核开发树下的CVSgit库。总之,一些部分是能被分离出来并组合成一个独特的固件来运行特定的硬件设备。

许多目录也需要针对本地特征进行修改以让特定的硬件设备能否使用,首先,需要知道硬件上运行的内核版本,这个可以通过编辑linux/Makefile”文件得到。

例:

head -5 linux-2.x.x/Makefile

VERSION = 2

PATCHLEVEL = x

SUBLEVEL = y

EXTRAVERSION = z

NAME=A fancy name

在知道版本后需要到kernel.org上下载匹配该版本的标准内核解压包,然后在两个树之间再创建一个diff文件,尤其是一下目录:

diff -urN linux-2.x.x/arch/<sub architecture> linux-2.x.x-modified/arch/<sub architecture> > 01-architecture.patch

diff -urN linux-2.x.x/include/ linux-2.x.x-modified/include > 02-includes.patch

diff -urN linux-2.x.x/drivers/ linux-2.x.x-modified/drivers > 03-drivers.patch

如此可以构成一套三个,包含在Linux内核上任意修改掉的内容的基本补丁。当然,由“diff -urN”命令产生目录并不是总相关的,所以需要清除所有非必须的代码。

第一个补丁包含启动时初始化的全部代码,也包括处理器检测和其它启动时间的代码。

第二个补丁包含所有有用定义,包括地址、内核粒度、重定义、处理器族、功能等。

第三个补丁包含串行控制台、以太网NIC、无线NICUSB NIC等外设的驱动,这些代码在计划从硬件中编译器写入代码时无效。

使用设备启动引导程序:

启动引导程序是设备上电启动后打开的第一个程序,程序多少有点复杂,它可以使网络、USB、存储模块等被启动,根据设备不同也具有特异性,而有些启动引导程序也可以是通用的,如RedBootU-Boot,因此甚至可见于完全不同的平台并用相同的运作方式。

如果你的设备运行的是一个专有的操作系统,那么很可能它使用的也是专有的启动引导程序,但这并不是绝对的,一些专有的启动引导程序也有它有效的源代码使之可以在其它设备上实现运行。

根据启动引导程序的特证将多少能简化侵入设备的难度,通常这些启动引导程序即使是很标新立异的,也都能在网上找到相关的文档介绍,为了能了解某设备其启动引导程序的特性和尝试侵入设备,需要注意以下几点:

·是否允许通过bootp/DHCP/NFStftp方式来启动设备的启动引导程序?

·引导程序是否允许载入ELF二进制文件?

·引导程序对内核/固件大小是否有限制?

·引导程序是否允许载入固件格式?

·所载入的文件是位于RAM执行还是于闪存中执行?

启动网络一定程度上而言是非常便捷的,因为你只需要在开发平台上设置设置好网络一启动服务器并在确认能替换掉设备固件之前始终保持原有固件就可以了。这样也能防止设备被刷机和防止在测试和修改内核/文件系统后变砖。

当你想要给设备刷入固件是,启动引导程序可能只能识别特定固件格式的文件,因此需要在刷入之前理解设备支持的固件格式。

使二进制驱动能运行和工作:

之前曾提到过,厂商将自己的二进制驱动集成到了他们自己的GPL包里面,那些驱动是静态链接到内核的,也就成为了GPL包的一部分,不知是幸运还是不行,大多数驱动并未被静态链接进去,但这也正好使得能改变驱动和当前内核半杯之间的动态链接,再使它们能允许一起工作。这也正是整个开源项目中最诡变的部分。

一些驱动需要经过一些修改之后才能在通用内核中运行,因为它们是在更早期的内核版本上运行的,而这些就该就是为了使之能适应到当前更新的版本上,例如BroadcomBCM43xx设备,它仅仅在无线网络接口的结构上有所区别。

一些一般原则适用任意内核版本来用于生成适用于你的通用内核版本的二进制驱动:

·打开内核调试功能如:

·CONFIG_DEBUG_KERNEL

·CONFIG_DETECT_SOFTLOCKUP

·CONFIG_KALLSYMS

·CONFIG_KALLSYMS_ALL

·如果当前内核版本可以支持则连接到二级制驱动

·尝试载入其他那些二进制驱动

·理解造成死机的机制

大多数情况载入二进制驱动总会失败并生成一份内核调试信息,可以知道二进制驱动最近一次尝试使用的符号并在内核的头文件上查看。可以将一些结构区域移动到这个符号的前或后来保持二进制驱动和内核驱动堆栈的交互。

理解关键格式:

无法确定固件是否能在设备上运行而需要对固件格式有所理解,这也是阻碍我们刷机流程进行的一大原因。

固件格式大多由一下几部分构成:

·header:包含固件版本及其他如供应商、硬件版本等信息

·CRS校验和位于整个文件或作为其中的一部分

·二进制与或压缩而成的内核镜像

·二进制与或压缩而成的根文件系统镜像

·潜在垃圾数据

要指出固件格式是如何分区的,需要自己编写工具来生成一个有效的二进制固件文件,这里尤其需要关注生成二进制固件的工具和使用该二进制固件的设备之间的排列顺序。

编写闪存对比驱动:

闪存对比驱动在固件工作流程中扮演着非常重要的角色,因为它负责对比正确闪存扇区和系统相关的特殊部分例如启动引导程序、内核、用户文件系统。

在知道固件镜像和闪存的结构后,编写一个自己的闪存对比驱动其实并不是个多难的任务。以下案例讨论了设备的启动引导程序如何对内核进行分区规划。

首先,需要让闪存对比驱动在内核配置选项中可见,可以通过编辑linux/drivers/mtd/maps/Kconfig”如下得以实现:

config MTD_DEVICE_FLASH

tristate "Device Flash device"

depends on ARCHITECTURE && DEVICE

help

Flash memory access on DEVICE boards. Currently only works with

Bootloader Foo and Bootloader Bar.

再将源文件添加到linux/drivers/mtd/maps/Makefile”中,这样才可以使它随内核一起编译。

obj-\$(CONFIG_MTD_DEVICE_FLASH)      += device-flash.o

也可以通过创建一个linux/drivers/mtd/maps/device-flash.cC语言文件来对驱动本身直接编辑。

// Includes that are required for the flash map driver to know of the prototypes:  
#include <asm/io.h>  
#include <linux/init.h>  
#include <linux/kernel.h>  
#include <linux/mtd/map.h>  
#include <linux/mtd/mtd.h>  
#include <linux/mtd/partitions.h>  
#include <linuxmalloc.h>  
 
// Put some flash map definitions here:  
#define WINDOW_ADDR 0x1FC00000         /* Real address of the flash */  
#define WINDOW_SIZE 0x400000                /* Size of flash */  
#define BUSWIDTH 2                                   /* Buswidth */  
 
static void __exit device_mtd_cleanup(void);  
 
static struct mtd_info *device_mtd_info;  
 
static struct map_info devicd_map = {  
       .name = "device",  
       .size = WINDOW_SIZE,  
       .bankwidth = BUSWIDTH,  
       .phys = WINDOW_ADDR,  
};  
 
static int __init device_mtd_init(void)  
{  
  // Display that we found a flash map device  
       printk("device: 0x\%08x at 0x\%08x\n", WINDOW_SIZE, WINDOW_ADDR);  
   // Remap the device address to a kernel address  
       device_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE);  
 
       // If impossible to remap, exit with the EIO error  
       if (!device_map.virt) {  
               printk("device: Failed to ioremap\n");  
               return -EIO;  
       }  
 
   // Initialize the device map  
       simple_map_init(&device_map);  
 
   /* MTD informations are closely linked to the flash map device  
       you might also use "jedec_probe" "amd_probe" or "intel_probe" */  
       device_mtd_info = do_map_probe("cfi_probe", &device_map);  
 
  if (device_mtd_info) {  
               device_mtd_info->owner = THIS_MODULE;  
 
int parsed_nr_parts = 0;  
 
// We try here to use the partition schema provided by the bootloader specific code  
                       if (parsed_nr_parts == 0) {  
                               int ret = parse_bootloader_partitions(device_mtd_info, &parsed_parts, 0);  
                               if (ret > 0) {  
                                       part_type = "BootLoader";  
                                       parsed_nr_parts = ret;  
                               }  
                       }  
 
                       add_mtd_partitions(devicd_mtd_info, parsed_parts, parsed_nr_parts);  
 
                       return 0;  
               }  
       iounmap(device_map.virt);  
 
       return -ENXIO;  
}  
 
// This function will make the driver clean up the MTD device mapping  
static void __exit device_mtd_cleanup(void)  
{  
  // If we found a MTD device before  
       if (device_mtd_info) {  
   // Delete every partitions  
               del_mtd_partitions(device_mtd_info);  
   // Delete the associated map  
               map_destroy(device_mtd_info);  
       }  
 
// If the virtual address is already in use  
       if (device_map.virt) {  
// Unmap the physical address to a kernel space address  
               iounmap(device_map.virt);  
// Reset the structure field  
              device_map.virt = 0;  
       }  
}  
 
 
// Macros that indicate which function is called on loading/unloading the module  
module_init(device_mtd_init);  
module_exit(device_mtd_cleanup);  
 
 
// Macros defining license and author, parameters can be defined here too.  
MODULE_LICENSE("GPL");  
MODULE_AUTHOR("Me, myself and I <memyselfandi@domain.tld");

2.4 调试和debricjing

2.4.1 添加串行端口

2.4.2 JTAG

2.5 错误报告

2.5.1 使用Trac标签系统

OpenWrt作为一个开源软件,它开放了它的开发社区允许公众访问subversion库。Trac软件意味着一个subversion前端、一个wiki、一个面向开发者的报表系统,可以使用户和贡献者的开发进程变得更加简易和高效。

Trac系统将用户分为两类:

·开发者:可以报告、修改和关闭标签

·报告者:可以添加评说明、补丁或者请求标签状态

打开一个标签:

报告者可能会因为一下原因而需要打开标签:

·出现了一个bug影响了特定硬件的与或软件并需要对之进行修改

·出现一个特殊软件包需要在官方OpenWrt库中显示出来

·OpenWrt上需要添加或移除某个功能

视打开的标签种类的不同,补丁在以下情况下可以被接受:

·需要包含进OpenWrt的新包

·修复报告者用户模式下bug且位置是否具有影响时

·修改现有OpenWrt内的文件添加新功能

如果标签已经打开,则会受到开发者的关注,并打上开发者认可的名字,这时允许随时在标签中添加说明或者将标签关闭。

关闭一个标签:

标签会因为一下原因而关闭被开发者关闭:

·问题已修复

·问题无法判定为有效的

·开发者已经知道错误被上一级修复了

·错误重复

·问题不会转移和影响其他部分运作

同时标签也可能在bug不再被报告者触发或者发现bug本身没有意义时会被关闭。

如果一个标签由开发者打上了“已修复”的标记,则subversion子集中将会随着更正为已修复完bug的文件内容。

2.6 上传补丁

2.6.1 如何贡献

OpenWrt系统是在持续进步着的,这归功于无数人员的资源贡献,使这些资源能让广大爱好者能够获取得到。当你发现有一些修改有用,并利用各种方法将之整合到整个项目中,如此就能提升OpenWrt的品质,并可能会被收录保存在将来的OpenWrt官方版本中去。

本节主要介绍一种让人们能够上传补丁的行之有效的方法。

你需要反复重复以下步骤,这是至关重要的:

·聆听他人的想法

·解释你所遇到的问题和解决的方法

·编写有用的补丁和文档

·测试、测试再测试

2.6.2 何处聆听和讨论

·在谷歌上查找和你问题相关的资料

·邮件列表:http://lists.openwrt.org/

·wiki:查找wikihttp://wiki.openwrt.org/OpenWrtDocs

·论坛:http://forum.openwrt.org/

·IRC互联中继聊天:irc.freenode.netOpenwrtopenwrt-devel频道

·TRAChttps://dev.openwrt.org/ issue/bug/change 跟踪系统

最好要描述清楚之前你做的内容,过程文档往往能暴露出其中可能的问题,请保持书写到目前为止的开发文档。

2.6.3 补丁提交进程

1.使用gitsvn创建补丁,手动使用“diff -urN”命令也可,但通常不需要这么做。

2.将以下内容整理成邮件发送给openwrt-devel@lists.openwrt.org

A.[PATCH]<简单描述一下>放置于主题处

B.(可选)在信息内容中详细描述补丁功能

C.署名(自己的邮箱地址)

D.附件附上补丁

3.阅读http://kerneltrap.org/Linux/Email_Clients_and_Patches 并找出确认邮箱客户端没有破坏了你的补丁文件的方法。

4.遵循Linux内核补丁上传指南上的要求在署名处使用真实的名字和邮箱地址。

Linux内核补丁上传指南:http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob;f=Documentation/SubmittingPatches;h=681e2b36195c98ea5271b76383b3a574b190b04f;hb=HEAD

5.补丁上传范例:http://lists.openwrt.org/pipermail/openwrt-devel/2007-November/001334.html 。

OpenWrt官方入门手册相关推荐

  1. Python官方入门手册等你领取!

    Python入门指南 一 Python世界 Python 是一门简单易学且功能强大的编程语言.它拥有高效的高级数据结构,并且能够用简单而又高效的方式进行面向对象编程.Python 优雅的语法和动态类型 ...

  2. React 入门手册

    大家好,我是若川.推荐这篇可收藏的React入门手册.也推荐之前一篇类似的文章<如何使用 React 和 React Hooks 创建一个天气应用>. 点击下方卡片关注我.加个星标 Rea ...

  3. figma客户端_小白的Figma入门手册

    全世界都在用Figma 不知道你们有没有这种感觉,仿佛有一天,很突然的,全世界都在使用figma,一个软件从无人问津到现在的如日中天,用了不到3年,而现在,它不仅仅是当下的最优生产力工具,在疫情掀起的 ...

  4. Paddle Quantum 量桨入门手册

    Paddle Quantum 量桨入门手册 Copyright © 2021 Institute for Quantum Computing, Baidu Inc. All Rights Reserv ...

  5. SpringBoot2+MybatisPlus3入门手册v2修订版

    Mybatis-Plus简介 Mybatis-Plus 是一款 Mybatis 动态 SQL 自动注入 Mybatis 增删改查 CRUD 操作中间件, 减少你的开发周期优化动态维护 XML 实体字段 ...

  6. MatLab入门手册

    本文章采用创作共用版权协议, 要求署名.非商业用途和保持一致. 转载本文章必须也遵循署名-非商业用途-保持一致的创作共用协议. 1. MatLab简介和安装 MatLab是综合高性能的数值计算软件, ...

  7. 视频教程-PHP7入门手册视频版第一季-PHP

    PHP7入门手册视频版第一季 2009年4月创办 淄博日诺网络科技有限公司 法人总经理 2016年负责 中国传媒大学凤凰学院 网站开发 项目负责人 2017年 参与负责 用友软件理财项目开发 郭孟涛 ...

  8. 零基础小白的大数据入门手册

    零基础小白的大数据入门手册,学大数据前,大家可能听过不少说大数据难学.入行做好心理准备的.大家听完也很动摇很犹豫,怀疑自己能不能学好大数据.这其实完全没有必要,觉得一个东西难,百分之八十的原因是你不了 ...

  9. VUE3/TS/TSX入门手册指北

    VUE3入门手册 vue3入门 首先 查看 官方文档:https://cn.vuejs.org/guide/quick-start.html 如果有vue2基础,速成课程:https://www.zh ...

  10. 关于FPGA,小白的入门手册,高手的晋升宝典。

    @关于FPGA,小白的入门手册,高手的晋升宝典. #文章主体内容 FPGA「是什么」 FPGA「能干嘛」 FPGA「怎么干」 FPGA「学什么」 FPGA有一本比较简单粗暴的入门书籍Altera公司官 ...

最新文章

  1. mysql int(40)_MySQL Integer类型与INT(11)
  2. 设置centos6.5虚拟机时间同步
  3. 【动态树】[BZOJ2002] Bounce 弹飞绵羊
  4. laravel 邮件SwiftMailer
  5. 苹果系统的自带的系统录屏软件中新录制的视频会出现在这里!
  6. POJ 1655 Balancing Act (求树的重心)【树形DP】(经典)
  7. MySQL 8.0索引合并
  8. linux shell加密压缩,linux的shell指令进行压缩或者解压缩
  9. MaciOS之多线程(转)
  10. c++实验4—项目6输出星号图
  11. (68)FPGA模块调用(Verilog调用VHDL)
  12. 合并模块和安装文件的区别
  13. Nginx何防止流量攻击
  14. python画数学函数_Python 绘制你想要的数学函数图形 !
  15. Android JNI使用方法,JNI机制详解
  16. 在linux里如何建立一个快捷方式,连接到另一个目录
  17. BUUCTF misc 专题(77)间谍启示录
  18. swfupload ajax,swfupload ajax无刷新上传图片实例代码
  19. 154. 正则表达式匹配
  20. asp.net学习心得总结

热门文章

  1. 双向循环链表讲解及实现
  2. get和post的区别
  3. matlab 生成gcode文件,解析gcode文件以提取坐标
  4. doc 问卷调查模板表_问卷调查表格式范本.doc
  5. SQL SERVER 数据库日志已满,清理数据库日志的方法
  6. android nfc源码分析,深入分析Android NFC技术 android nfc开发
  7. 三星note10 android q,【极光ROM】-【三星NOTE10/NOTE10+/5G N97XX-9825】-【V5.0 Android-Q-TE9】...
  8. 草根程序员转型做项目管理走过的点点滴滴_康奈尔笔记法介绍
  9. fragment中高德地图定位
  10. mysql嵌套查询实例_MySQL嵌套查询实例详解_MySQL