Android的USB网络共享功能
一、什么是USB网络共享?
USB 共享网络是一种基于 USB 接口的数据传输和资源共享解决方案,例如 Android设备作为一个usb网卡连接到其他主机,将Android设备的网络共享给主机使用。在Android系统设置中的 “开发者选项” 中,可以找到usb的默认配置选择USB 共享网络的功能,选择还包括其MTP,PTP等。默认的网络共享协议是RNDIS,是将TCP/IP封装在USB报文里,实现网络通信。(即将TCP/IP包 封装成为USB总线要求的格式)类似的封装报文的情况也出现在PPPoE(将点对点协议(PPP)封装在以太网(Ethernet)框架中)等技术中。
另外还有NCM和ECM协议:cdc ethernet usb规范规定的CommunicationsDevice Class “Ethernet Model” protocol。USB NCM,属于USB-IF定义的CDC(Communication Device Class)下的一个子类:Network Control Model,用于Host和Device之间交换以太网帧。NCM主要用于高速网络场景下比如HSPA和LTE数据服务。NCM协议规范基于ECM改进而来,支持了更高的数据率。使用NCM的主要优点在于它在单个USB批量传输中传输多个数据报。NCM允许设备和主机使用一个USB传输有效地传输一个或多个以太网帧。USB传输被格式化为NCM传输块(NTB)。有两种NTB格式:NTB-16和NTB-32。前者用来表示长度小于65536字节的NTB,后者用来表示不超过4GB的NTB。
二、RNDIS的使用
一般Android系统默认就支持该功能,可以在开发者选项中选择开启,如果ODM厂商有自己做适配也可以通过属性开启:
setprop sys.usb.config rndis //仅开启rndis setprop sys.usb.config rndis,adb //开启rndis同时支持有线adb
如果想了解属性配置如何实现的,可以看看专门讲usb gadget驱动的这篇文章:https://www.cnblogs.com/blogs-of-lxl/p/16815102.html
开启RNDIS网络共享后,如果Android设备的USB口硬件上支持otg的话,可以通过usb直接连到主机端,主机端有RNDIS HOST驱动的话就可以识别到一个usb网卡,Android设备有网络的情况下,主机端就可以间接通过Android设备上网了。usb tethering 本质上是利用tcp/ip协议栈的转发功能, 和softap以及 bluetooth tethering 类似 (tcp/ip 网络协议栈的数据包转发来实现网络共享, 通常是使用iptables 命令来操作 其nat表来配置的)
问题1: windows无法正常识别RNDIS网卡
解决方法:更新一下RNDIS网卡驱动
问题2: Android或Linux主机无法正常识别RNDIS网卡
解决方法:内核编译配置加上RNDIS HOST的支持
+CONFIG_USB_USBNET=y
+CONFIG_USB_NET_RNDIS_HOST=y
另外如果Android主机端需要默认启用usb网卡的DHCP服务,则可以修改如下系统服务的配置文件:
diff --git a/frameworks/base/core/res/res/values/config.xml b/frameworks/base/core/res/res/values/config.xml index 93b1ed2de..bc2ce5cb5 100755 --- a/frameworks/base/core/res/res/values/config.xml +++ b/frameworks/base/core/res/res/values/config.xml @@ -414,7 +414,7 @@ </string-array> <!-- Regex of wired ethernet ifaces --> - <string translatable="false" name="config_ethernet_iface_regex">eth\\d</string> + <string translatable="false" name="config_ethernet_iface_regex">eth\\d|usb\\d</string> <!-- Configuration of Ethernet interfaces in the following format: <interface name|mac address>;[Network Capabilities];[IP config];[Override Transport]
三、NCM的使用
NCM(网络控制模型)协议用于在设备和主机之间交换高速以太网帧数据。符合CDC NCM的设备将自己作为虚拟NIC暴露给主机操作系统。所以对于仅是主机和设备之间通过USB 网络方式交互数据,不需要上外网的情况,使用NCM协议更合适,并且结合静态路由的配置可以实现多网络共存,不影响原来的网络状态。
Android一般标配的是RNDIS,所以使用NCM需要内核配置打开选项:
+CONFIG_USB_CONFIGFS_NCM=y
+CONFIG_USB_F_NCM=y
usb gadget驱动支持NCM后,就可以在usb rc文件中配置属性控制:
on property:sys.usb.config=ncm && property:sys.usb.configfs=1 write /config/usb_gadget/g1/UDC "none" rm /config/usb_gadget/g1/configs/b.1/f1 rm /config/usb_gadget/g1/configs/b.1/f2 rm /config/usb_gadget/g1/configs/b.1/f3 mkdir /config/usb_gadget/g1/functions/ncm.gs7 write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "ncm" write /config/usb_gadget/g1/idProduct 0x000A symlink /config/usb_gadget/g1/functions/ncm.gs7 /config/usb_gadget/g1/configs/b.1/f1 write /config/usb_gadget/g1/UDC ${sys.usb.controller} setprop sys.usb.state ${sys.usb.config} start ip_config_ncm on property:sys.usb.config=ncm,adb && property:sys.usb.configfs=1 start adbd on property:sys.usb.ffs.ready=1 && property:sys.usb.config=ncm,adb && property:sys.usb.configfs=1 write /config/usb_gadget/g1/UDC "none" rm /config/usb_gadget/g1/configs/b.1/f1 rm /config/usb_gadget/g1/configs/b.1/f2 rm /config/usb_gadget/g1/configs/b.1/f3 mkdir /config/usb_gadget/g1/functions/ncm.gs7 write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "ncm_adb" write /config/usb_gadget/g1/os_desc/use 1 write /config/usb_gadget/g1/idProduct 0x001A symlink /config/usb_gadget/g1/functions/ncm.gs7 /config/usb_gadget/g1/configs/b.1/f1 symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f2 write /config/usb_gadget/g1/UDC ${sys.usb.controller} setprop sys.usb.state ${sys.usb.config} start ip_config_ncm
其中 ip_config_ncm 是自定义的一个脚本服务,用来配置静态IP和路由:
service ip_config_ncm /system/bin/sh /system/bin/clientnetwork.sh usb_ncm class late_start user root group root disabled oneshot seclabel u:r:shell:s0
脚本 clientnetwork.sh 的具体实现就是静态IP和路由的配置:
#!/system/bin/sh IP_NCM="192.168.42.11/24" IP_RULE_LIST=`ip rule list` RULE_NCM="from all to $IP_NCM lookup main" if [[ $1 == usb_ncm ]];then USB_CONFIG=`getprop sys.usb.config` if [[ $USB_CONFIG == *ncm* ]] then sleep 1 echo "/system/bin/ifconfig usb0 $IP_NCM up ..." /system/bin/ifconfig usb0 $IP_NCM up #ip route add $IP_NCM dev usb0 if [[ $IP_RULE_LIST == *$RULE_NCM* ]]; then echo "already exist: $RULE_NCM" else ip rule add to $IP_NCM table main fi else echo "/system/bin/ifconfig usb0 down ..." /system/bin/ifconfig usb0 down ip rule del to $IP_NCM fi fi exit 0
上面默认配置的IP是 192.168.42.11/24 ,后面就可以通过 setprop sys.usb.config ncm,adb 来启用ncm并且同时支持usb adb使用。
注:通过usb连接到主机端后就可以看到一个usb0网卡接入,但默认是未启用的状态,需要手动配置静态IP启用:ifconfig usb0 192.168.42.12/24 up ,启用后会发现直接ping 192.168.42.11 (device端IP)不通,担指定网卡是可以ping通的:ping -I usb0 192.168.42.11 ,是因为路由策略问题,查看路由表可以知main路由表就满足需求:
# ip route list table main 192.168.2.0/24 dev wlan0 proto kernel scope link src 192.168.2.31 192.168.42.0/24 dev usb0 proto kernel scope link src 192.168.42.12
以上第二行含义就是数据包目标IP属于 192.168.42.0/24 网段(192.168.42.1~192.168.42.254)时,通过usb0网卡直接发送,源IP为 192.168.42.12。
字段解释:
- default via: 默认路由,指定默认的下一跳IP地址。
- dev: 指定出接口,即数据包将通过哪个网络接口发送。
- proto kernel: 表示这是一个由内核自动生成的路由表项。
- scope link: 表示本地链路,数据包只在本地网络内传输。
- src: 指定数据包的源IP地址。
那么就可以添加一条规则:
ip rule add to 192.168.42.12/24 table main
选项说明:
- from: 源地址
- to: 目的地址(这里是选择规则时使用,查找路由表时也使用)
- tos: IP包头的TOS(type of sevice)域Linux高级路由
- dev: 物理接口
- fwmark: iptables标签,可能需要定制,有些Android原生不支持。
- prohibit: 丢弃该包,并发送 COMM.ADM.PROHIITED的ICMP信息
- unreachable: 丢弃该包并发送 NET UNREACHABLE的ICMP信息
- nat: 透明网关
192.168.42.12/24
是一个CIDR(无类别域间路由)表示法,192.168.42.0/24和192.168.42.12/24都代表网段192.168.42.1-192.168.42.255,网络地址为192.168.42.0,广播地址为192.168.42.255,主机地址为192.168.42.1-192.168.42.254,即192.168.42.12/24也代表主机地址为192.168.42.12,子网掩码为24(255.255.255.0)的地址,所以和配置 ip rule add to 192.168.42.0/24 table main 是一样的,其含义就是让数据包目标IP为 192.168.42.1-192.168.42.254网段的数据使用main路由表的路由规则。
之后就可以直接 ping 192.168.42.11
Android设备的otg口是usb2.0的,两个设备之间通过usb网络共享连接后,使用iperf测试网络带宽大概120Mbps左右:
连接到Windows PC上也可以识别到USB NCM设备,只是无法上网:
posted on 2024-08-21 19:24 sheldon_blogs 阅读(2012) 评论(0) 编辑 收藏 举报