Linux-System als Remote-Schnittstelle (USB-Gadget mit g_ether-Treiber)

Linux-System als Remote-Schnittstelle (USB-Gadget mit g_ether-Treiber)

Ich arbeite gerade an einem Projekt, bei dem wir ein eingebettetes Linux-System haben, auf dem einige Sensor-/Motorsteuerungsfunktionen laufen, und wir erstellen eine GUI-Anwendung, mit der der Benutzer das System steuern kann. In Zukunft werden wir vielleicht beide Anwendungen auf einem einzigen System ausführen, aber vorerst wollen wir dies als Upgrade auf vorhandenen Maschinen installieren können, und die vorhandenen Controller-Boards sind nicht in der Lage, die GUI wie vorgesehen auszuführen, also wird sie auf einem separaten SBC laufen (derzeit entwickeln wir einen Prototyp mit einemODroid C4mit Android 9)

Wir haben die Kommunikations-API zwischen den beiden Systemen ausgearbeitet und ich habe erste Tests durchgeführt, indem ich eine direkte Ethernet-Verbindung zwischen den beiden Systemen mit statischen IP-Adressen hergestellt habe. Aufgrund der Bereitstellungsanforderungen und -beschränkungen von Android muss ich mir jedoch eine andere Verbindungsmethode für die tatsächliche Bereitstellung des Produkts überlegen. Der Kunde muss in der Lage sein, über WLAN oder Ethernet auf dem GUI-System eine Verbindung zum Internet herzustellen, daher kann der integrierte Ethernet-Port des ODroid nicht für diesen Zweck verwendet werden. Darüber hinaus weist der Android-Kernel ein internes Verhalten auf, das zu einem bestimmten Zeitpunkt nur eine einzige aktive Netzwerkverbindung zulässt.

Die Ausnahme von Androids Regeln zur Netzwerkpriorisierung sind USB-Netzwerkschnittstellen. Sowohl das Linux-Controllersystem als auch das Android-Gerät selbst können als Netzwerkschnittstelle für einen Remote-Host erscheinen. Auf dem Controllersystem steht uns ein USB-Gadget-Port zur Verfügung, und ich habe das g_etherKernelmodul in unserem Systemabbild aktiviert. Auf dem GUI-System haben wir einen USB-OTG-Port, und ich kann USB-Tethering in den Android-Systemeinstellungen aktivieren.

Ich konnte über die jeweiligen Schnittstellen eine Kommunikation zwischen diesen Systemen und meinem Windows-Entwicklungssystem herstellen, habe bisher aber noch nicht herausgefunden, wie ich die eine Lösung dazu bringe, mit der anderen zu kommunizieren.

Linux-System als Remote-Schnittstelle (USB-Gadget mit g_ether-Treiber)

  • Durch das Laden des Kernelmoduls g_ether auf dem Linux-System wird eine usb0Schnittstelle erstellt:
# 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
  • Durch das Anschließen eines USB-Kabels vom Gadget-Port des Linux-Systems an einen Host-Port des Android-Systems wird sofort eine usb0Schnittstelle unter Android erstellt und eine IP-Adresse für die usb0Schnittstelle unter Linux generiert:

Android:

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
  • Beim Aufrufen der Schnittstelle auf dem Android-System wird keine IP-Adresse zugewiesen, daher muss ich manuell eine zuweisen, indem ich den Bereich 169.254/16 verwende, den das Linux-System selbst zuweist
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

An diesem Punkt habe ich zwei Probleme: Erstens führt das Pingen eines der Geräte vom anderen Gerät aus zu keiner Antwort. Wenn man sich die Paketzahlen auf der Android-Seite ansieht, sieht es so aus, als ob es die Pings von der Linux-Seite empfängt, aber nicht antwortet, was durch das zweite Problem verursacht werden kann, nämlich dass die Routing-Tabellen auf der Android-Seite nicht wie erwartet zu funktionieren scheinen. Da dies funktionieren muss, während auf dem Android-System auch eine aktive Internetverbindung besteht, habe ich gleichzeitig das Ethernet angeschlossen, und das ist, was ich sehe, wenn ich mir das Routing ansehe:

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-System als Remote-Schnittstelle (USB-Tethering mit OTG-Anschluss)

Dieses Szenario scheint mich ein Stück näher zu bringen, da ich eine Einwegkommunikation zum Laufen bringen kann.

  • Nachdem ich die erforderlichen Treiber zu meinem Linux-Image hinzugefügt habe, erkennt das System das USB-Gerät wie folgt, wenn ich den Android-OTG-Port über ein Kabel mit dem Port eines Linux-Hosts verbinde 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
  • usb0Auf der Linux-Seite wird sofort eine Schnittstelle erstellt und ihr eine IP-Adresse zugewiesen:
# 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
  • Auf der Android-Seite mit aktiviertem USB-Tethering in den Einstellungen wird die Schnittstelle usb0 angezeigt, ist aber zunächst inaktiv. Wenn sie aufgerufen wird, erhält sie keine IP-Adresse, also habe ich manuell eine zugewiesen, aber wie im ersten Szenario scheint die Routing-Tabelle nicht wie erwartet zu funktionieren:
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
  • In diesem Szenario kann ich jedoch eine erfolgreiche Kommunikation vom Android-Ende aus erreichen, indem ich die Schnittstelle manuell angebe:
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
  • Ich kann immer noch keinen Datenverkehr von Linux zum Laufen bringen, vermutlich weil ein Routing-Problem auf der Android-Seite die korrekte Weiterleitung des zurückkommenden Datenverkehrs verhindert:
# 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

In beiden Fällen scheint die Ursache des Problems darin zu liegen, dass die Routing-Tabelle auf der Android-Seite den Verkehr nicht richtig über die USB-Schnittstelle leitet und die Android-Seite nicht automatisch eine IP-Adresse zuweist, während die Linux-Seite dies tut. Bei der Linux-Gadget-Schnittstelle/dem Android-Host kann ich diese Probleme einigermaßen nachvollziehen, aber bei der Android-OTG-Port-Tethering/dem Linux-Host würde ich erwarten, dass es richtig geroutet wird, da das Android-System die Tethering-Verbindung kontrolliert.

Antwort1

Hallo @rdowell,

Um dieses Problem zu beheben, muss die Hauptroutentabelle auf Ihrem Android-Gerät hinzugefügt werden:

ip rule add from all lookup main pref 1

verwandte Informationen