2.3.8 TetherCmd和SoftapCmd命令

TetherCmd和SoftapCmd命令都和手机中一项名为绑定(Tether)的功能相关。简单来说,绑定功能即把手机当成Modem用。智能手机一般都有多种连接网络的方式,例如使用Wi-Fi或3G。在某些环境下如高铁列车上,差旅人士只要把手机接到笔记本上,然后开启3G和Tether,笔记本就可以利用手机上网了(在智能机普及前,类似的场景中就需要使用3G上网卡)。

另外,如果手机中的无线网络设备支持Soft AP(Soft Access Point,软件实现的接入点)功能,还可以通过Softap命令将手机变成一个AP(可以把它看成是一个无线路由器)。

目前Android 4.2系统支持以下三种方式的绑定。

·Soft AP:利用Wi-Fi无线网络的特性,开启手机Soft AP功能。主机和手机间通过Wi-Fi通信。

·Bluetooth:主机(PC或笔记本电脑)和手机通过蓝牙协议通信。

·USB:主机和手机通过USB协议通信。手机相当于一个USB上网卡。

本节主要介绍TetherCmd中的USB绑定和Softap命令。其余内容我们将留给读者自行研究。

提示 TetherCmd还支持所谓的逆绑定(reverse tethering),即手机借助主机上网。这部分内容请读者自行研究。

1.TetherCmd命令

本节仅介绍利用USB实现Tether的功能,其中涉及RNDIS以及DHCP相关的背景知识,我们先来介绍它们。

(1)背景知识介绍[26][27][28][29][30]

RNDIS(Remote Network Driver Interface Specification)是微软公司的,主要用于Windows平台中USB网络设备的驱动开发。RNDIS的协议栈如图2-24所示。

2.3.8 TetherCmd和SoftapCmd命令 - 图1

图2-24 RNDIS协议栈

RNDIS的作用是简化Windows平台上USB网络设备驱动开发的流程。此处不讨论相关内容,感兴趣的读者可阅读本章最后列出的参考资料。

RNDIS和Android有什么关系呢?当手机通过USB连接到主机(主机一般运行Windows系统)后,如果要启用USB绑定,必须要把手机的USB设置成RNDIS(绝大部分厂商的手机都是这么实现的)。这样,主机上的OS就能识别到一个新的网卡。然后用户就可以选择使用它来开展网络操作了。

提示 本书后续章节将讨论Android平台上USB的相关功能。

假设用户选择使用这个通过USB绑定的网卡,下一步要做的就是给主机分配IP地址了。此处涉及DHCP协议。

DHCP(Dynamic Host Configuration Protocol,动态主机配置协议)的前身是BOOTP。BOOTP原本是用于无磁盘主机连接的网络上的,网络主机使用BOOT ROM而不是磁盘启动并连接上网络,BOOTP则可以自动地为那些主机设定TCP/IP环境。DHCP是BOOTP的增强版本,它分为两个部分。

·服务器端:所有的IP网络设定数据都由DHCP服务器集中管理,并负责处理客户端的DHCP要求。

·客户端:客户端会使用从服务器分配下来的IP地址等配置信息。

根据上述介绍,相信读者很容易想到,在USB绑定中,主机将是DHCP的客户端,而手机是DHCP的服务器端。那么在Android系统中,DHCP服务器端是谁呢?同Pppd类似,Android也使用了另外一个开源软件DNSmasq来充当DHCP服务器。

DNSmasq是一个用于配置DNS和DHCP的工具,小巧且方便,适用于小型网络,它提供了DNS功能和可选择的DHCP功能。它服务只在本地适用的域名,这些域名是不会在全球的DNS服务器中出现的。DHCP服务器和DNS服务器结合,并且允许DHCP分配的地址能在DNS中正常解析,而这些DHCP分配的地址和相关命令可以配置到每台主机中,也可以配置到一台核心设备中(如路由器)。

DNSmasq适用于拥有NAT的家庭网络、用Modem、ADSL设备连接到互联网等环境。对于需求低资源消耗且配置方便简单的小型网络(最多可支持1000台主机)是一个很好的选择。

(2)TetherCmd命令使用

Android中启动USB Tether功能将涉及Framework层多个模块,其详细过程留待后续章节介绍。此处读者仅需从TetherCmd角度考虑其中的两个主要步骤。

1)添加需要Tether的接口。对USB绑定来说,接口名为rndis0。对应的处理函数是TetherController的tetherInterface,代码如下所示。

[—>TetherController.cpp::tetherInterface]

  1. int TetherController::tetherInterface(const char *interface) {
  2. mInterfaces->push_back(strdup(interface));
  3. // 把需要interface名字保存到一个链表即可
  4. return 0;
  5. }

tetherInterface的功能很简单,就是保存需要Tether的设备名。这一步其实没有太多实质性的内容。

2)通过"start"选项启动Tether。这个步骤将触发TetherController的startTethering函数被调用。该函数的主要功能就是配置dnsmasq的启动参数并启动它。这部分代码比较简单,dnsmasq的启动参数如下所示。

  1. dnsmasq\
  2. --keep-in-foreground\#前台运行
  3. --no-resolv\#不解析/etc/resolv.conf,该文件记录域名和dns服务器的一些信息
  4. --no-poll\#不关注/etc/resolv.conf文件的变化
  5. --dhcp-option-force=43ANDROID_METERED\#强制的dhcp选项。客户端和dnsmasq交互时,首先
  6. #会获取dhcp服务器的一些配置信息。43是DHCP协议中定义的option的一种,代表vendor specific
  7. #infomation该选项说明vendor specifi information就是ANDROID_METERED
  8. --pid-file\#指定dnsmasq记录自己进程idpid)到某个文件。默认是/var/run/dnsmasq.pid
  9. --dhcp-range=192.168.1.2 192.168.1.100 1h\#该选项开启dnsmasqdhcp服务功能。分配的IP地址
  10. #位于192.168.1.2和192.168.1.100之间。1h代表租约时间为1小时。租约时间即某IP地址可以被DHCP
  11. #客户端使用的时间。如果超过租约时间,dnsmasq必须为该客户端重新分配IP

这两步完成后,USB绑定功能中和TetherCmd相关的任务就完成了。从整个绑定过程来看,涉及应用(例如Settings提供的设置功能)、网络模块、USB模块、驱动等,是一个非常复杂的过程。

提示 这个过程对软件开发者来说也是一个挑战,只有对USB Tether涉及的各个模块都有相应了解,碰到问题时候才能快速定位和解决它。

2.SoftapCmd命令

Softap命令和Wi-Fi有紧密关系。本节先简单介绍Soft AP相关的背景知识,后续章节将对Wi-Fi开展深入讨论。

(1)背景知识介绍[31][32][33]

Soft AP代表通过软件实现Access Point的功能。那么AP是什么?AP和Soft AP有什么不同?

在Wi-Fi无线技术规范中,AP和Station是其中的两个基本概念。

·从功能角度来看,AP作为基站设备,起着连接其他无线设备到有线网的作用,相当于有线网络中的HUB与交换机。在日常工作和家庭中经常使用的无线路由器就是一个AP。一般情况下,它一端接着有线网络,另一端连接其他无线设备。

·Station代表配备无线网络接口的设备,如手机、笔记本等。

虽然AP和Station是两个不同的设备,但实际上在Station中用软件也能实现AP拥有的功能,如桥接、路由等。在基本功能上,Soft AP与AP并没有太大的差别,只是Soft AP设备的接入能力和覆盖范围不如AP。

以前面提到的高铁列车上的应用场景为例,除了用USB绑定外,还可以打开笔记本和手机的Wi-Fi,并启动手机的Soft AP功能。这样,手机一方面用3G接入互联网,另一方面又利用Soft AP向笔记本提供Wi-Fi接入功能。

在Android系统中使用Soft AP功能还得借助另一个开源软件"hostapd",这是一个运行在用户空间的用于AP和认证服务器的守护进程。它实现了IEEE 802.11相关的接入管理、IEEE 802.1X/WPA/WPA2/EAP认证、RADIUS客户端、EAP服务器和RADIUS认证服务器。

(2)SoftapCmd命令使用

和TetherCmd类似,开启Android中手机的Soft AP功能将涉及大量Framework层中的操作,本节仅关注和Netd相关的三个步骤。

1)首先为Wi-Fi加载不同的固件(Firmware),这是通过SoftapController的fwReloadSoftap函数完成的,代码如下所示。

[—>SoftapController.cpp::fwReloadSoftap]

  1. int SoftapController::fwReloadSoftap(int argc, char *argv[])
  2. {
  3. int ret, i = 0;
  4. char *iface;
  5. char *fwpath;
  6.  
  7. ......// 参数检测
  8. iface = argv[2];
  9. if (strcmp(argv[3], "AP") == 0) {
  10. fwpath = (char *)wifi_get_fw_path(WIFI_GET_FW_PATH_AP);
  11. } else if (strcmp(argv[3], "P2P") == 0) {
  12. fwpath = (char *)wifi_get_fw_path(WIFI_GET_FW_PATH_P2P);
  13. } else {
  14. fwpath = (char *)wifi_get_fw_path(WIFI_GET_FW_PATH_STA);
  15. }
  16. // 通过往/sys/module/wlan/parameters/fwpath文件中写入固件名
  17. // 触发驱动去加载对应的固件
  18. ret = wifi_change_fw_path((const char *)fwpath);
  19. ......
  20. return ret;
  21. }

上面这段代码表示在Android中,如果要让Wi-Fi无线设备扮演不同的角色,得为它们加载不同的固件(Firmware),具体说明如下。

·WIFI_GET_FW_PATH_AP:代表Soft AP功能的固件,其对应的文件位置由WIFI_DRIVER_FW_PATH_AP宏表达。三星Tuna平台中,该文件位置为/vendor/firmware/fw_bcmdhd_apsta.bin。

·WIFI_GET_FW_PATH_P2P:代表P2P功能的固件,其对应的文件位置由WIFI_DRIVER_FW_PATH_P2P宏表达。三星Tuna平台中,该文件位置为/vendor/firmware/fw_bcmdp2p.bin。

·WIFI_GET_FW_PATH_STA:代表Station功能的固件,其对应的文件位置由WIFI_DRIVER_FW_PATH_STA宏表达。三星Tuna平台中,该文件位置为/vendor/firmware/fw_bcmdhd.bin。

提示 三星Tuna平台对应的配置文件在Android 4.2源码根目录/device/samsung/tuna目录中。从上面的固件文件名来看,它用的Wi-Fi无线芯片是博通(Broadcom)公司生产的。通过加载不同固件的方式来启用无线芯片硬件的不同功能可能和Wi-Fi驱动及芯片的设计有关。

另外,根据审稿专家的反馈,在Android 4.2中,STA和P2P可同时运行(即所谓的共存模式),这样STA和P2P实际对应的固件相同,但可能文件名不同。而SoftAP的固件与STA/P2P就不一样了。

2)加载完指定的Wi-Fi固件后,下一步将对Soft AP功能进行一些配置,配置信息最终将写到一个配置文件。这部分功能由SoftapController的setSoftap函数完成,代码如下所示。

[—>SoftapController.cpp::setSoftap]

  1. int SoftapController::setSoftap(int argc, char *argv[]) {
  2. char psk_str[2*SHA256_DIGEST_LENGTH+1];
  3. int ret = 0, i = 0, fd;
  4. char *ssid, *iface;
  5.  
  6. ......// 参数检查
  7.  
  8. iface = argv[2];
  9.  
  10. char *wbuf = NULL;
  11. char *fbuf = NULL;
  12.  
  13. if (argc > 3) {
  14. ssid = argv[3];
  15. } else {
  16. ssid = (char *)"AndroidAP"; // SSID即接入点的名称
  17. }
  18.  
  19. asprintf(&wbuf, "interface=%s\ndriver=nl80211\nctrl_interface="
  20. "/data/misc/wifi/hostapd\nssid=%s\nchannel=6\nieee80211n=1\n",
  21. iface, ssid);
  22.  
  23. if (argc > 4) { // 判断AP的加密类型
  24. if (!strcmp(argv[4], "wpa-psk")) {
  25. generatePsk(ssid, argv[5], psk_str);
  26. asprintf(&fbuf, "%swpa=1\nwpa_pairwise=TKIP CCMP\nwpa_psk=%s\n",
  27. wbuf, psk_str);
  28. } else if (!strcmp(argv[4], "wpa2-psk")) {
  29. generatePsk(ssid, argv[5], psk_str);
  30. asprintf(&fbuf, "%swpa=2\nrsn_pairwise=CCMP\nwpa_psk=%s\n",
  31. wbuf, psk_str);
  32. } else if (!strcmp(argv[4], "open")) {
  33. asprintf(&fbuf, "%s", wbuf);
  34. }
  35. } ......
  36. // HOSTAPD_CONF_FILE指向/data/misc/wifi/hostapd.conf文件
  37. fd = open(HOSTAPD_CONF_FILE, O_CREAT | O_TRUNC | O_WRONLY, 0660);
  38. ......
  39. if (write(fd, fbuf, strlen(fbuf)) < 0) {
  40. ALOGE("Cannot write to \"%s\": %s", HOSTAPD_CONF_FILE, strerror(errno));
  41. ret = -1;
  42. }
  43. ......// 修改该文件的读写权限等
  44. return ret;
  45. }

上面代码中涉及Wi-Fi技术的很多概念,将在后续章节统一介绍。从功能上来说,setSoftap函数无非就是把一些配置信息写到一个hostapd.conf文件中。可以通过一个例子文件来了解此文件的内容。

Android4.2/hardware/ti/wlan/mac80211/config目录中有一个hostapd.conf文件,其内容如下所示。

[—>hostapd.conf]

  1. driver=nl80211 #指定Wi-Fi驱动的名称
  2. ......#略去部分内容
  3. ssid=AndroidAP #设置接入点名称为AndroidAP
  4. country_code=US
  5. wep_rekey_period=0
  6. eap_server=0
  7. own_ip_addr=127.0.0.1
  8. wpa_group_rekey=0
  9. wpa_gmk_rekey=0 #加密方式等设置
  10. wpa_ptk_rekey=0
  11. interface=wlan1 #网络设备接口
  12. ......#略去部分内容

由上边示例的hostapd.conf可知,当使用该配置文件后,其他Station搜索到由这台手机设置的Soft AP的名称将会是"AndroidAP"。

3)最后,SoftapController的startap函数被调用,它将启动hostapd进程。重点关注hostapd启动的参数信息,如下所示。

  1. hostapd\
  2. -e/data/misc/wifi/entropy.bin \和Wi-Fi协议中的信息加密有关
  3. /data/misc/wifi/hostapd.conf \hostapd的配置文件