ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
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所示。 :-: ![](https://box.kancloud.cn/fa420f6e5219def4b7d9d69e43c60d79_777x636.jpg) 图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** ~~~ int TetherController::tetherInterface(const char *interface) { mInterfaces->push_back(strdup(interface)); // 把需要interface名字保存到一个链表即可 return 0; } ~~~ tetherInterface的功能很简单,就是保存需要Tether的设备名。这一步其实没有太多实质性的内容。 - 2、**通过"start"选项启动Tether**。这个步骤将触发TetherController的startTethering函数被调用。该函数的主要功能就是配置dnsmasq的启动参数并启动它。这部分代码比较简单,dnsmasq的启动参数如下所示。 ~~~ dnsmasq\ --keep-in-foreground\#前台运行 --no-resolv\#不解析/etc/resolv.conf,该文件记录域名和dns服务器的一些信息 --no-poll\#不关注/etc/resolv.conf文件的变化 --dhcp-option-force=43,ANDROID_METERED\#强制的dhcp选项。客户端和dnsmasq交互时,首先 #会获取dhcp服务器的一些配置信息。43是DHCP协议中定义的option的一种,代表vendor specific #infomation该选项说明vendor specifi information就是ANDROID_METERED --pid-file\#指定dnsmasq记录自己进程id(pid)到某个文件。默认是/var/run/dnsmasq.pid --dhcp-range=192.168.1.2 192.168.1.100 1h\#该选项开启dnsmasq的dhcp服务功能。分配的IP地址 #位于192.168.1.2和192.168.1.100之间。1h代表租约时间为1小时。租约时间即某IP地址可以被DHCP #客户端使用的时间。如果超过租约时间,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接入互联网,另一方面又利用SoftAP向笔记本提供Wi-Fi接入功能。 在Android系统中使用Soft AP功能还得借助另一个开源软件"hostapd",这是一个运行在用户空间的用于AP和认证服务器的守护进程。它实现了IEEE 802.11相关的接入管理、IEEE802.1X/WPA/WPA2/EAP认证、RADIUS客户端、EAP服务器和RADIUS认证服务器。 (2)SoftapCmd命令使用 和TetherCmd类似,开启Android中手机的Soft AP功能将涉及大量Framework层中的操作,本节仅关注和Netd相关的三个步骤。 1)首先为Wi-Fi加载不同的固件(Firmware),这是通过SoftapController的fwReloadSoftap函数完成的,代码如下所示。 **SoftapController.cpp::fwReloadSoftap** ~~~ int SoftapController::fwReloadSoftap(int argc, char *argv[]) { int ret, i = 0; char *iface; char *fwpath; ......// 参数检测 iface = argv[2]; if (strcmp(argv[3], "AP") == 0) { fwpath = (char *)wifi_get_fw_path(WIFI_GET_FW_PATH_AP); } else if (strcmp(argv[3], "P2P") == 0) { fwpath = (char *)wifi_get_fw_path(WIFI_GET_FW_PATH_P2P); } else { fwpath = (char *)wifi_get_fw_path(WIFI_GET_FW_PATH_STA); } // 通过往/sys/module/wlan/parameters/fwpath文件中写入固件名 // 触发驱动去加载对应的固件 ret = wifi_change_fw_path((const char *)fwpath); ...... return ret; } ~~~ 上面这段代码表示在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** ~~~ int SoftapController::setSoftap(int argc, char *argv[]) { char psk_str[2*SHA256_DIGEST_LENGTH+1]; int ret = 0, i = 0, fd; char *ssid, *iface; ......// 参数检查 iface = argv[2]; char *wbuf = NULL; char *fbuf = NULL; if (argc > 3) { ssid = argv[3]; } else { ssid = (char *)"AndroidAP"; // SSID即接入点的名称 } asprintf(&wbuf, "interface=%s\ndriver=nl80211\nctrl_interface=" "/data/misc/wifi/hostapd\nssid=%s\nchannel=6\nieee80211n=1\n", iface, ssid); if (argc > 4) { // 判断AP的加密类型 if (!strcmp(argv[4], "wpa-psk")) { generatePsk(ssid, argv[5], psk_str); asprintf(&fbuf, "%swpa=1\nwpa_pairwise=TKIP CCMP\nwpa_psk=%s\n", wbuf, psk_str); } else if (!strcmp(argv[4], "wpa2-psk")) { generatePsk(ssid, argv[5], psk_str); asprintf(&fbuf, "%swpa=2\nrsn_pairwise=CCMP\nwpa_psk=%s\n", wbuf, psk_str); } else if (!strcmp(argv[4], "open")) { asprintf(&fbuf, "%s", wbuf); } } ...... // HOSTAPD_CONF_FILE指向/data/misc/wifi/hostapd.conf文件 fd = open(HOSTAPD_CONF_FILE, O_CREAT | O_TRUNC | O_WRONLY, 0660); ...... if (write(fd, fbuf, strlen(fbuf)) < 0) { ALOGE("Cannot write to \"%s\": %s", HOSTAPD_CONF_FILE, strerror(errno)); ret = -1; } ......// 修改该文件的读写权限等 return ret; } ~~~ 上面代码中涉及Wi-Fi技术的很多概念,将在后续章节统一介绍。从功能上来说,setSoftap函数无非就是把一些配置信息写到一个hostapd.conf文件中。可以通过一个例子文件来了解此文件的内容。 Android4.2/hardware/ti/wlan/mac80211/config目录中有一个hostapd.conf文件,其内容如下所示。 **hostapd.conf** ~~~ driver=nl80211 #指定Wi-Fi驱动的名称 ......#略去部分内容 ssid=AndroidAP #设置接入点名称为AndroidAP country_code=US wep_rekey_period=0 eap_server=0 own_ip_addr=127.0.0.1 wpa_group_rekey=0 wpa_gmk_rekey=0 #加密方式等设置 wpa_ptk_rekey=0 interface=wlan1 #网络设备接口 ......#略去部分内容 ~~~ 由上边示例的hostapd.conf可知,当使用该配置文件后,其他Station搜索到由这台手机设置的Soft AP的名称将会是"AndroidAP"。 3)最后,SoftapController的startap函数被调用,它将启动hostapd进程。重点关注hostapd启动的参数信息,如下所示。 ~~~ hostapd\ -e/data/misc/wifi/entropy.bin \和Wi-Fi协议中的信息加密有关 /data/misc/wifi/hostapd.conf \hostapd的配置文件 ~~~