sheldon_blogs

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编辑  收藏  举报

导航