Linux 系统作为远程接口(带有 g_ether 驱动程序的 USB 小工具)

Linux 系统作为远程接口(带有 g_ether 驱动程序的 USB 小工具)

我目前正在做一个项目,我们有一个嵌入式 Linux 系统,运行一些传感器/电机控制功能,我们正在创建一个 GUI 应用程序,以允许用户控制系统。将来,我们可能会在单个系统上运行这两个应用程序,但目前,我们希望能够将其作为对现有机器的升级来安装,而现有的控制器板无法按照设计运行 GUI,因此它将在单独的 SBC 上运行(目前我们正在使用ODroid C4运行Android 9)

我们已经设计出两个系统之间的通信 API,并且我一直在通过在两个系统之间使用静态 IP 地址运行直接以太网连接来进行初步测试,但是由于 Android 的部署要求和限制,我需要找出一种不同的连接方法来实际部署产品。我们需要客户能够通过 WiFi 或以太网在 GUI 系统上连接到互联网,因此 ODroid 的板载以太网端口不能用于此目的,而且最重要的是,Android 内核有一些内部行为,只允许在任何给定时间激活一个网络连接。

Android 网络优先级规则的例外是 USB 网络接口。Linux 控制器系统和 Android 设备本身都能够作为网络接口出现在远程主机上 - 在控制器系统上,我们有一个可用的 USB 小工具端口,我g_ether在系统映像中启用了内核模块,在 GUI 系统上,我们有一个 USB OTG 端口,我可以在 Android 系统设置中启用 USB 网络共享。

我已经能够使用它们各自的接口在这两个系统和我的 Windows 开发系统之间建立通信,但是到目前为止我还没有弄清楚如何让任何一个解决方案与另一个解决方案进行通信。

Linux 系统作为远程接口(带有 g_ether 驱动程序的 USB 小工具)

  • 在linux系统上加载g_ether内核模块会创建一个usb0接口:
# modprobe g_ether
# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.42.128.107  netmask 255.255.255.0  broadcast 10.42.128.255
        inet6 fe80::206:cff:fe01:1027  prefixlen 64  scopeid 0x20<link>
        ether 00:06:0c:01:10:27  txqueuelen 1000  (Ethernet)
        RX packets 500  bytes 54062 (52.7 KiB)
        RX errors 0  dropped 46  overruns 0  frame 0
        TX packets 0  bytes 24423 (23.8 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 0  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

usb0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet6 fe80::24b:5bfc:8a9e:b148  prefixlen 64  scopeid 0x20<link>
        ether 9a:8c:fa:85:ec:a1  txqueuelen 1000  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 1  bytes 96 (96.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
  • 将 USB 电缆从 Linux 系统上的 gadget 端口连接到 Android 系统上的主机端口会立即usb0在 Android 上创建一个接口,并为 Linux 上的接口生成一个 IP 地址usb0

安卓:

odroidc4:/ # ifconfig usb0
usb0      Link encap:Ethernet  HWaddr fa:4c:95:c0:8d:18  Driver cdc_subset
          BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 TX bytes:0

Linux:

# ifconfig usb0
usb0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 169.254.119.94  netmask 255.255.0.0  broadcast 169.254.255.255
        inet6 fe80::24b:5bfc:8a9e:b148  prefixlen 64  scopeid 0x20<link>
        ether 9a:8c:fa:85:ec:a1  txqueuelen 1000  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 1  bytes 96 (96.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
  • 在 Android 系统上启动界面不会分配 IP 地址,因此我必须手动分配一个,使用 Linux 系统自行分配的 169.254/16 空间
odroidc4:/ # ifconfig usb0 up
odroidc4:/ # ifconfig usb0
usb0      Link encap:Ethernet  HWaddr fa:4c:95:c0:8d:18  Driver cdc_subset
          inet6 addr: fe80::f84c:95ff:fec0:8d18/64 Scope: Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:117 errors:4 dropped:75 overruns:0 frame:4
          TX packets:27 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:5080 TX bytes:4897

odroidc4:/ # ip addr add 169.254.1.1/16 broadcast 169.254.255.255 dev usb0
odroidc4:/ # ifconfig usb0
usb0      Link encap:Ethernet  HWaddr fa:4c:95:c0:8d:18  Driver cdc_subset
          inet addr:169.254.1.1  Bcast:169.254.255.255  Mask:255.255.0.0
          inet6 addr: fe80::f84c:95ff:fec0:8d18/64 Scope: Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:117 errors:4 dropped:75 overruns:0 frame:4
          TX packets:44 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:5080 TX bytes:8528

此时我有两个问题:首先,从另一台设备 ping 任一设备都无响应。查看 Android 端的数据包计数,似乎它正在接收来自 Linux 端的 ping,但没有响应,这可能是由第二个问题引起的,即路由表在 Android 端似乎没有按预期工作。考虑到我需要在 Android 系统上也有活动的互联网连接时实现此功能,我同时连接了以太网,这是我在查看路由时看到的内容:

odroidc4:/ # ip route list
169.254.0.0/16 dev usb0 proto kernel scope link src 169.254.1.1
10.42.128.0/24 dev eth0 proto kernel scope link src 10.42.128.166
odroidc4:/ # ip route get 169.254.119.94
169.254.119.94 via 10.42.128.2 dev eth0 table eth0 src 10.42.128.166 uid 0
    cache
odroidc4:/ # ip route show table 0
default via 10.42.128.2 dev eth0 table eth0 proto static
...

Android 系统作为远程接口(通过 OTG 端口进行 USB 网络共享)

由于我可以实现单向沟通,因此这种情况似乎让我更接近目标了。

  • 在我的 Linux 映像中添加必要的驱动程序后,将电缆从 Android OTG 端口连接到 Linux 主机端口,系统会识别 USB 设备dmesg
[  235.710937] usb 1-2.3: new full-speed USB device number 7 using at91_ohci
[  235.862304] rndis_host 1-2.3:1.0 usb0: register 'rndis_host' at usb-at91-2.3, RNDIS device, 32:1d:e8:fc:dd:8
  • usb0Linux 端立即创建一个接口并分配一个 IP 地址:
# ifconfig usb0
usb0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 169.254.249.80  netmask 255.255.0.0  broadcast 169.254.255.255
        inet6 fe80::e341:f9b1:b676:99b7  prefixlen 64  scopeid 0x20<link>
        ether 32:1d:e8:fc:dd:80  txqueuelen 1000  (Ethernet)
        RX packets 69  bytes 13572 (13.2 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 73  bytes 18251 (17.8 KiB)
        TX errors 8  dropped 0 overruns 0  carrier 0  collisions 0
  • 在 Android 端,在设置中启用 USB 网络共享后,usb0 接口会出现,但一开始是关闭的。启动它并没有给它一个 IP 地址,所以我手动分配了一个,但与第一种情况一样,路由表似乎没有按预期运行:
odroidc4:/ # ifconfig usb0
usb0      Link encap:Ethernet  HWaddr de:75:5c:41:2a:e6
          BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 TX bytes:0
odroidc4:/ # ifconfig usb0 up
odroidc4:/ # ifconfig usb0
usb0      Link encap:Ethernet  HWaddr de:75:5c:41:2a:e6
          inet6 addr: fe80::dc75:5cff:fe41:2ae6/64 Scope: Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:10 errors:0 dropped:0 overruns:0 frame:0
          TX packets:12 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:1090 TX bytes:2751
odroidc4:/ # ip addr add 169.254.1.1/16 broadcast 169.254.255.255 dev usb0
odroidc4:/ # ip route
10.42.128.0/24 dev eth0 proto kernel scope link src 10.42.128.166
169.254.0.0/16 dev usb0 proto kernel scope link src 169.254.1.1
odroidc4:/ # ip route get 169.254.249.80
169.254.249.80 via 10.42.128.2 dev eth0 table eth0 src 10.42.128.166 uid 0
    cache
  • 但是,在这种情况下,我可以通过手动指定接口来获得来自 Android 端的成功通信:
odroidc4:/ # ping -c 5 -I usb0 169.254.249.80
PING 169.254.249.80 (169.254.249.80) from 169.254.1.1 usb0: 56(84) bytes of data.
64 bytes from 169.254.249.80: icmp_seq=1 ttl=64 time=1.56 ms
64 bytes from 169.254.249.80: icmp_seq=2 ttl=64 time=1.89 ms
64 bytes from 169.254.249.80: icmp_seq=3 ttl=64 time=1.71 ms
64 bytes from 169.254.249.80: icmp_seq=4 ttl=64 time=1.75 ms
64 bytes from 169.254.249.80: icmp_seq=5 ttl=64 time=1.85 ms

--- 169.254.249.80 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4006ms
2|odroidc4:/ # ping6 -c5 ff02::1%usb0
PING ff02::1%usb0(ff02::1) 56 data bytes
64 bytes from fe80::dc75:5cff:fe41:2ae6: icmp_seq=1 ttl=64 time=0.202 ms
64 bytes from fe80::e341:f9b1:b676:99b7: icmp_seq=1 ttl=64 time=1.91 ms (DUP!)
64 bytes from fe80::dc75:5cff:fe41:2ae6: icmp_seq=2 ttl=64 time=0.196 ms
64 bytes from fe80::e341:f9b1:b676:99b7: icmp_seq=2 ttl=64 time=1.80 ms (DUP!)
64 bytes from fe80::dc75:5cff:fe41:2ae6: icmp_seq=3 ttl=64 time=0.199 ms
64 bytes from fe80::e341:f9b1:b676:99b7: icmp_seq=3 ttl=64 time=1.37 ms (DUP!)
64 bytes from fe80::dc75:5cff:fe41:2ae6: icmp_seq=4 ttl=64 time=0.199 ms
64 bytes from fe80::e341:f9b1:b676:99b7: icmp_seq=4 ttl=64 time=1.85 ms (DUP!)
64 bytes from fe80::dc75:5cff:fe41:2ae6: icmp_seq=5 ttl=64 time=0.205 ms

--- ff02::1%usb0 ping statistics ---
5 packets transmitted, 5 received, +4 duplicates, 0% packet loss, time 4004ms
rtt min/avg/max/mdev = 0.196/0.883/1.914/0.776 ms
  • 我仍然无法使任何来自 Linux 端的流量正常工作,大概是因为 Android 端的路由问题导致返回流量无法正确路由:
# ping -c 5 -I usb0 169.254.1.1
PING 169.254.1.1 (169.254.1.1) from 169.254.249.80 usb0: 56(84) bytes of data.

--- 169.254.1.1 ping statistics ---
5 packets transmitted, 0 received, 100% packet loss, time 4295ms
# ping6 -c 5 ff02::1%usb0
PING ff02::1%usb0(ff02::1) 56 data bytes
64 bytes from fe80::e341:f9b1:b676:99b7: icmp_seq=1 ttl=64 time=0.522 ms
64 bytes from fe80::e341:f9b1:b676:99b7: icmp_seq=2 ttl=64 time=0.302 ms
64 bytes from fe80::e341:f9b1:b676:99b7: icmp_seq=3 ttl=64 time=0.376 ms
64 bytes from fe80::e341:f9b1:b676:99b7: icmp_seq=4 ttl=64 time=0.383 ms
64 bytes from fe80::e341:f9b1:b676:99b7: icmp_seq=5 ttl=64 time=0.385 ms

--- ff02::1%usb0 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4009ms
rtt min/avg/max/mdev = 0.302/0.393/0.522/0.074 ms

在这两种情况下,问题的根源似乎是 Android 端的路由表没有正确地通过 USB 接口路由流量,并且 Android 端不会自动分配 IP 地址,而 Linux 端会。使用 Linux 小工具接口/Android 主机,我可以理解这些问题,但使用 Android OTG 端口网络共享/Linux 主机,我希望它能够正确路由,因为 Android 系统控制着网络共享连接。

答案1

Hy @rdowell,

要解决此问题,需要在您的 Android 设备上添加主路由表:

ip rule add from all lookup main pref 1

相关内容