2.3.8 TetherCmd和SoftapCmd命令
最后更新于:2022-04-02 06:01:41
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://docs.gechiui.com/gc-content/uploads/sites/kancloud/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的配置文件
~~~
';