使用arm开发板搭建无线mesh网络(二)
上篇博文介绍了无线mesh网络和adhoc网络的区别,这篇文章将介绍无线mesh网络的骨干网节点的组建过程。首先需要介绍下骨干网节点的设计方案:每个骨干网节点都是由一块友善之臂的tiny6410 arm开发板+两块TP-LINK TL-WN721N USB无线网卡+linux 2.6.38系统组成的,其中一块网卡工作在adhoc模式下,用来和其他骨干网节点进行无线连接(自组织形式连接,而不是wifi接入点方式),另一块网卡工作在wifi的master模式下,也就是说需要在这块网卡上创建wifi热点,供用户的终端设备连接。即,骨干网节点之间采用自组网方式互连,而用户终端设备和骨干网之间采用wifi接入方式。
1.linux内核的裁剪
由于骨干网节点之间采用自组织方式进行连接,因此将来需要运行adhoc网络的路由协议(aodv或者别的自组网协议),工作在adhoc模式下的那张网卡需要参与该协议的运行。本实验采用的aodv协议是由开源社区提供的aodv-uu-0.9.6协议。该协议是基于linux的Netfilter框架实现的。因此在进行linux内核裁剪时,需要加入Netfilter框架。本实验使用的linux内核是友善之臂tiny6410开发板所带的光盘中的linux-2.6.38-20120828.tgz,文件系统使用光盘中提供的rootfs_qtopia_qt4-mlc2.ubi。另外,内核裁剪时,使用了linux-2.6.38-20120828.tgz源码根目录下的config_linux_mini6410作为内核的原始配置文件。mv config_linux_mini6410 .config即可。
该配置文件中没有加入Netfilter框架,因此需要手动去添加,笔者使用make menuconfig在图形化界面中进行内核裁剪。
(1)打开内核配置界面首页后,进入Networking support选项,如下图:
(2)接着进入Networking options选项,如下图:
(3)接着选择Network packet filtering framework (Netfilter) 选项,并进入其中。所谓选择,就是将该选项前的[]变为[*],将该选项对应的功能编译进内核。如下图:
(4)接着进入Core Netfilter Configuration选项,如下图:
(5)按照下图所示,选择相应的选项。没有在图中出现的选项一律不管。
(6)退出当前选项,然后进入IP: Netfilter Configuration选项,如下图:
(7)按照如下图示,进行配置。不在图中的选项不用管。
至此,Netfilter框架和iptables工具就配置进了内核中。iptables是用来设置linux防火墙的工具,我们在后边要使用其设置一些过滤规则,因此将其一块编译进内核。之后可以使用make zImage && make install 编译和安装内核,并将编译好的内核烧写到arm开发板中。
2.将网卡A配置为adhoc模式
将两张网卡中的任意一张(假设为网卡A)设置为adhoc模式,使用到的命令下面列出。笔者在实验过程中,发现usb无线网卡插入开发板后,只能引起usb驱动做出响应,并不能激活无线网卡驱动。因此无法使用ifconfig,iwconfig对插入的无线网卡进行设置(此时设置会提示不存在wlan0设备)。笔者使用了tiny 6410 linux自带的scan-wifi命令来加载网卡驱动(可能比较笨,不过很有效)。所有命令列出如下:
scan-wifi //此命令本用来搜索wifi热点的,笔者使用它激活网卡驱动,笨笨哒~~
ifconfig //该命令可以查看所有网卡的配置情况,包括以太网卡和无线网卡,使用过scan-wifi操作后,在该命令下就会发现wlan0网卡的信息。
ifconfig wlan0 down //使用scan-wifi命令后,接着需要使用该命令停止wlan0网卡工作(该操作并未停止无线网卡驱动哦~),然后才能使用iwconfig命令对无线网卡的工作模式进行设置,否则如果不停止无线网卡的工作,使用iwconfig命令时将提示设备正忙。。。
iwconfig wlan0 mode ad-hoc //将网卡wlan0的工作模式设置为ad-hoc
iwconfig wlan0 essid “自定义的name” //设置该网卡所在的adhoc网络的名称,设置完成后,当其他的无线网卡也将其essid设置为相同名称后,这些网卡将处于同一个adhoc网络中。因此essid实际上是用来区分不同网络的。
iwconfig wlan0 //该命令专门用来查看无线网卡的配置信息。此时,就会看到wlan0网卡工作模式为adhoc,essid为所设置的名称,cell为当前网络的详细标志。
ifconfig wlan0 X.X.X.X //配置网卡wlan0的ip地址
ifconfig wlan0 up //启动网卡wlan0
至此,无线网卡wlan0配置完毕,工作完成一半了。
3.重新编译无线网卡驱动ath9k_htc
其实当配置完内核,加入Netfilter框架和iptables工具后,在使用scan-wifi命令时,内核会报出oops错误并导致arm板宕机。笔者懒于重现该错误,因此没有错误截图,很抱歉。但是错误的大概意思就是Unable to handle kernel NULL pointer dereference,不能操作空指针。笔者经过分析后,发现是无线网卡驱动ath9k_htc导致了该错误发生。由于我们在新内核中使用的仍然是友善之臂提供的旧无线网卡驱动,而新内核的虚拟地址空间有所变动,可能会导致旧的无线网卡驱动中某些虚拟地址已经不再被映射到正确的地方,因此出现了这种错误。解决办法就是在新内核下重新编译ath9k_htc无线网卡驱动,具体操作步骤下面给出。重新编译后问题得以解决,进而验证了笔者的猜测。
(1)用make menuconfig重新配置内核。在首页中进入Networking support ----> Wireless选项中,选择cfg80211 - wireless configuration API选项及其子选项。将cfg80211选为模块来编译,即将[]变为[M]。此外也将Generic IEEE 802.11 Networking Stack (mac80211)选项选择为模块来编译,如下图。
(2)退回配置文件的首页,进入Device Driver ----> Netword device support选项中,选择Wireless Lan选项并进入,如下图:
(3)进入后,按照下图所示进行选择。
(4)进入Atheros Wireless Cards选项,并按下图进行选择。
至此,无线网卡驱动配置完毕,使用make modules && make modules_install对网卡驱动进行编译与安装。最后将/lib/modules/2.6.38-FriendlyARM/kernel/drivers/net/wireless/ath/,/lib/modules/2.6.38-FriendlyARM/kernel/net/mac80211/,
/lib/modules/2.6.38-FriendlyARM/kernel/net/wireless/路径下的内容拷贝到arm linux的/lib中的相应路径中,覆盖掉原先的这些文件。宿主机系统和arm linux系统的这些路径大体上是一致的,可能稍有不同,仔细找下,很容易找到相应的目录。重新启动arm linux系统,一切ok。
4.iptables安装
上面1中linux内核裁剪时,提到了iptables已经编译进了内核。其实iptables包含了两个部分,上面的只是将内核部分搞定了,还需要对用户态部分进行编译和安装。iptables的编辑比较简单,只是需要注意,执行configure命令时,用prefix指定的安装目录,一定要与将来移植到arm linux系统中的路径完全一致。例如,configure -prefix=/usr/local/iptables,那么编译完后执行make install命令,iptables将被安装在宿主机的/usr/local/iptables目录下。之后也要将iptables目录下的所有内容移植到arm linux的/usr/local/iptables下,不能移到其他路径,否则iptables命令使用时将出错,很难排查。笔者在这里花费了不少时间。
5.aodv协议的编译和安装
打开aodv-uu-0.9.6根目录下的Makefile文件,找到CC=gcc处,将其改为CC=arm-linux-gcc(交叉编译器),然后进行编译。编译完后生成aodvd和kaodv.ko两个文件,kaodv.ko为内核模块,aodvd为用户态的可执行程序,将二者拖入arm linux系统中,先插入kaodv.ko模块,然后再执行aodvd程序,aodv协议就成功运行了。当然这一切都要在上面的1、2、3步骤之后才能进行。也就是要有无线网卡工作在adhoc模式下,该路由协议才能发挥作用。
4.host Ap的安装
此处较为简单,以后再写。
5.使用iptables配置网络地址转换方式
笔者使用上图所示的拓扑测试了网络的连通性,发现如果计算机A和计算B是win系统的话,则需要在1、2两个节点上执行iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE命令,也就是说,要在节点1的POSTROUTING处为笔记本B做网络地址转换(对源地址做NAT),这样B才能ping通A;同理,在节点2的POSTROUTING处为笔记本A做网络地址转换(对源地址做NAT),这样A才能ping通B。但是如果计算机A和B为linux系统的话,就不需要做NAT。因此笔者猜测win系统和linux在处理包转发或包回复时机制是不同的,至于是不是这样,还有待于研究。
6.激活路由转发模块
普通的pc linux或arm linux的网络层默认情况下,是没有开启路由转发功能的,当系统收到的数据包不是发给本机的,会将数据包丢弃;因此当pc或者开发版作为路由器时,必须要激活路由转发模块。命令为:echo “1” > /proc/sys/net/ipv4/ip_forward。这样就激活了主机的路由转发模块。
题外话
通过实验,笔者对网络的很多概念,包括ip地址、默认网关、路由表、arp表、路由表项、arp表项等等有了更深一步的认识。笔者觉得,ip地址虽然进行了A/B/C/D/E类划分,甚至划分了公网ip和局域网ip,可是就ip地址本身而言,它们之间没有任何本质区别,在这种自组织的ip地址分配中,可以任意使用所有ip地址。因此笔者在对全网进行ip地址规划时,将mesh骨干网的所有节点的ip地址划为一个网段,将连接在某个骨干网节点的所有客户端划为一个网段,并称其为“局域网”,连接在不同骨干网节点上的若干个局域网之间绝不能处于同一个网段,也不能和骨干网处于同一网段。示意图如下:
尽管骨干网是无自组织网络,使用了aodv路由协议,但其mac层依然使用的是802.11协议。试想下,如果局域网1和局域网2处于处于同一网段,那么它们二者之间还能否进行通信??笔者认为,这种情况下,只有使用端口映射才能通信,那么局域网1和局域网2中都有若干台终端设备,那么还怎样映射呢?因此不同局域网之间必须处于不同网段,这些相互之间才能通信。
细心的实验者还应该发现,当不运行aodv协议时,这些节点之间有时也是可以连通的。其实这是对的,如果骨干网的所有节点都处于同一网段,那么arp协议会自动获取本网段内所有节点的ip地址和mac地址,并初始化节点的arp表和路由表,使得本网段的主机可以直接通信;这就和以太网内所有主机处于同一网段,也可以互相通信是一个道理。如果骨干网内的所有节点并不在同一网段的时候,就需要aodv协议来进行路由探索了。另外,骨干网内,信号不能相互覆盖的节点(即不是邻居节点),也需要aodv协议进行路由探索,aodv协议一旦探索成功路由,并将路由信息更新至内核的路由表中,其就失去作用了(可以粗略这么理解)。
aodv协议的作用本身就只是探索路由并更新路由表,除此之外,别无它用。
最后,还要更正网上一些同类文章中错误的概念。他们认为节点上的两张无线网卡需要使用NAT方式连通,这属于概念性错误。其实在linux系统中,无论你插入多少张无线网卡,只要安装好了网卡驱动,这些网卡本身就是连通的,也就是说,每个网卡的ip地址和Mac地址都会被记录到路由表和arp表中,ip协议可以正确的将数据包通过相应的网卡发送出去。这和NAT方式压根没任何关系,NAT用来做网络地址转换,也就是说它会修改数据包的源地址或目的地址(对源地址做转换或对目的地址做转换,具体要根据需求来定),将其改为所设置的ip地址。NAT的作用在于,假如某些内网主机要通过一台连接在公网上的主机去上网,如果不做NAT,内网主机发送到互联网上的数据包,互联网站点是无法返回数据包的(返回的那些主机是内网主机,其ip地址为内网地址),所以这些内网主机是无法上网的;因此需要在连接到公网的那台主机上对这些内网主机数据包的源地址做NAT,将源地址转换为公网主机的ip地址,这时内网主机发送到互联网上的数据包,互联网可以做应答的,将应答包发送给这台公网主机,该主机再逆向根据NAT规则,将应答包交给某个内网主机。因此内网主机就可以上网了。