1 Punkte von GN⁺ 2025-06-09 | 1 Kommentare | Auf WhatsApp teilen
  • Android bietet Unterstützung für USB-Ethernet und ein Einstellungsmenü, doch CDC-Ethernet-Geräte werden zwar vom Kernel erkannt, möglicherweise aber nicht bis in die Netzwerkeinstellungen durchgereicht
  • Die Hauptursache ist, dass EthernetTracker nur Interfaces verfolgt, die zu config_ethernet_iface_regex passen, und der Standardwert eth\d CDC-Interfaces wie usb0 ausschließt
  • Die Linux-Treiber für CDC-Ethernet erkennen EEM-, ECM- und NCM-Geräte jeweils als cdc_eem, cdc_ether und cdc_ncm und legen unter /sys/class/net usb0 an, die Android-Einstellungen bleiben jedoch deaktiviert
  • Über normale Benutzereinstellungen lässt sich das nicht umgehen; nötig ist Root-Zugriff, um den Wert von config_ethernet_iface_regex zu ändern
  • Bei der Auswahl eines USB-Ethernet-Adapters für Android muss man daher nach Geräten auf Basis anbieter-/chipsatzspezifischer Treiber suchen, die einen ethX-Namen erzeugen, statt nach CDC-Standardgeräten

Fazit: Nicht der Kernel-Treiber blockiert, sondern der Filter für Interface-Namen

  • Der EthernetTracker-Dienst von Android erkennt nur Interfaces mit Namen ethX als Ethernet-Interfaces an
  • Die CDC-Ethernet-Treiber von Linux erzeugen Interface-Namen im Format usbX
  • Wegen dieses Namensunterschieds werden CDC-Ethernet-Geräte von den Ethernet-Einstellungen und der Netzwerkverwaltungsebene ignoriert, selbst wenn sie vom Android-Kernel erkannt werden
  • Über normale Einstellungen lässt sich das nicht lösen; möglich ist nur eine Änderung des Werts config_ethernet_iface_regex nach dem Rooten

Unterstützung für Android-USB-Ethernet ist je nach Gerät schwer zu prüfen

  • Android hat Unterstützung für USB-Ethernet-Adapter und entsprechende Menüs
  • Welche USB-Ethernet-Chipsätze auf einem bestimmten Android-Gerät funktionieren, ist schwer herauszufinden, weil Hersteller kaum Support-Listen veröffentlichen
  • In der Praxis verlassen sich Nutzer meist auf folgende Informationen
    • USB-Ethernet-Adapter, die der Smartphone-Hersteller als offizielles Zubehör verkauft
    • Forenbeiträge, in denen Nutzer desselben Geräts berichten, dass ein bestimmter Adapter erfolgreich funktioniert hat
  • Anhand der Kernel-Konfiguration lässt sich bis zu einem gewissen Grad erkennen, welche USB-Ethernet-Treiber der Smartphone-Kernel enthält

So findet man die Kernel-Konfiguration eines Smartphones

  • Android läuft auf einem Linux-Kernel, und die Kernel-Konfiguration bestimmt unterstützte Funktionen und Hardwaretreiber
  • Geräte, die nach Android 11 erschienen sind, basieren auf dem Android Common Kernel und dem GKI-Kernel
    • Google baut den Kernel, und Hersteller legen gerätespezifische Elemente in Kernel-Module
    • Die Konfiguration findet sich im Android-Kernel-Repository unter arch/$ARCH/configs/gki_defconfig
    • Bei 64-Bit-ARM-Geräten prüft man zum Beispiel arch/arm64/configs/gki_defconfig
  • Kernel-Version und Architektur lassen sich per ADB mit uname -a prüfen
    • Eine Beispielausgabe enthält die Kernel-Version 4.19.113-26203352 und die Architektur aarch64
  • Im Fall des Samsung Galaxy S20, das mit Android 10 erschienen ist, blieb der Kernel auch nach dem Upgrade auf Android 13 auf Linux 4.19 basiert
    • Samsung-Gerätequellen findet man unter opensource.samsung.com
    • In Samsungs build_kernel.sh lassen sich Namen von Kernel-Konfigurationsdateien wie vendor/x1q_usa_singlex_defconfig finden
  • Mit etwas Glück liegt die tatsächliche Build-Konfiguration als komprimierte Datei unter /proc/config.gz
    • Sie lässt sich mit adb shell zcat /proc/config.gz > my_kernel_config speichern
    • Falls nicht vorhanden, erscheint zcat: /proc/config.gz: No such file or directory, und man muss die Kernel-Quellen des Herstellers prüfen

Unterstützung für USB-Ethernet-Treiber prüfen

  • Kernel-Einstellungen für USB-Ethernet beginnen meist mit USB_NET
  • In der Kernel-Konfigurationsdatei lässt sich das zum Beispiel so prüfen
grep USB_NET my_kernel_config
  • Eine Beispielkonfiguration enthält mehrere USB-Netzwerktreiber
    • CONFIG_USB_NET_DRIVERS=y
    • CONFIG_USB_NET_AX8817X=y
    • CONFIG_USB_NET_AX88179_178A=y
    • CONFIG_USB_NET_CDCETHER=y
    • CONFIG_USB_NET_CDC_EEM=y
    • CONFIG_USB_NET_CDC_NCM=y
  • Die Konfigurationswerte unterscheiden, wie ein Treiber eingebunden ist
    • y: Der Treiber ist in den Kernel eingebaut und unterstützt den jeweiligen Chipsatz sicher
    • m: Der Treiber wurde als Modul gebaut und kann vermutlich geladen werden, sofern der Hersteller ihn nicht weggelassen hat
    • is not set: Der Treiber ist weder eingebaut noch als Modul vorhanden und kann sehr wahrscheinlich nicht genutzt werden
  • Welche Konfigurationsoptionen welchen Chipsätzen entsprechen, lässt sich im Kernel-Tree unter drivers/net/usb/Kconfig prüfen
  • Welchen Chipsatz ein bestimmter USB-Ethernet-Adapter nutzt, geben Hersteller oft nicht an; die Identifikation bleibt daher schwierig

Was CDC-Ethernet macht

  • CDC steht für Communications Device Class, eine Sammlung von Standards, an die sich Hersteller von USB-Geräten halten können
  • Für CDC-Ethernet gibt es drei relevante Standards
    • EEM: Ethernet Emulation Model, die einfachste Implementierung und für leistungsschwache Geräte leichter zu unterstützen
    • ECM: Ethernet Control Model, auf Host- und Geräteseite komplexer zu implementieren, verspricht aber bessere Leistung als EEM
    • NCM: Network Control Model, der Nachfolger von ECM, der höhere Geschwindigkeiten verspricht
  • Ziel des CDC-Standards ist, dass Betriebssysteme gemeinsame Treiber für unterschiedliche Geräte bereitstellen können
  • Linux implementiert sowohl die Host- als auch die Geräteseite von CDC-Ethernet
    • Bei Geräten wie einem Raspberry Pi mit USB-OTG-Port kann der Kernel diesen Port wie einen Ethernet-Adapter erscheinen lassen
    • Dadurch können Geräte wie eingebettete Router, Firewalls oder VPN-Gateways aus Sicht des Hosts wie ein normaler Ethernet-Adapter aussehen
  • Linux, Windows und macOS enthalten Treiber für CDC-Ethernet-Geräte, iOS jedoch nicht

Der Android-Kernel erkennt CDC-Geräte

  • Die Kernel-Konfiguration des Samsung Galaxy S20 enthält Unterstützung für alle drei CDC-Ethernet-Standards
    • CONFIG_USB_NET_CDCETHER=y
    • CONFIG_USB_NET_CDC_EEM=y
    • CONFIG_USB_NET_CDC_NCM=y
  • Beim Google-GKI-Kernel scheinen ECM und NCM zu fehlen, während EEM offenbar als Modul enthalten ist
  • Ein Gerät, dessen OTG-Port als Ethernet-Gadget konfiguriert war, funktionierte unter Mac, Ubuntu und Windows, beim Galaxy S20 blieben die Android-Ethernet-Einstellungen jedoch deaktiviert
  • Prüft man unter Android /sys/class/net, erscheint beim Anschließen eines CDC-Geräts usb0
adb shell ls /sys/class/net
  • Die Ausgabe von ifconfig usb0 zeigt, dass der Treiber als CDC-Variante erkannt wurde
    • EEM-Modus: Driver cdc_eem
    • ECM-Modus: Driver cdc_ether
    • NCM-Modus: Driver cdc_ncm
  • In allen drei Fällen wird das Interface erkannt, ist aber im Zustand down, und die Android-Ethernet-Einstellungen werden nicht aktiviert

Die Regex von EthernetTracker filtert usb0 heraus

  • Da das CDC-Ethernet-Gerät auf Kernel-Ebene korrekt erkannt wird, liegt das Problem in der Android-Netzwerkverwaltungsebene oberhalb des Kernels
  • Verfolgt man den Ethernet-bezogenen Java-Code in den Android-Quellen, landet man bei EthernetTracker.java als zuständigem Dienst
  • EthernetTracker empfängt über einen Netlink-Socket Benachrichtigungen des Kernels über neue Netzwerkinterfaces und entscheidet, ob es sich um ein gültiges Ethernet-Interface handelt
  • Die Gültigkeitsprüfung erfolgt, indem geprüft wird, ob der Interface-Name zur Regex mIfaceMatch passt
private boolean isValidEthernetInterface(String iface) {
    return iface.matches(mIfaceMatch) || isValidTestInterface(iface);
}
  • mIfaceMatch stammt aus der Ressource config_ethernet_iface_regex
  • Der Standardwert in den Android-Quellen lautet wie folgt
<string translatable="false" name="config_ethernet_iface_regex">eth\\d</string>
  • eth\d ist eine Regex, die nur Namen durchlässt, bei denen auf eth eine Ziffer folgt
  • CDC-Ethernet-Geräte beginnen wie usb0 mit usb, daher verfolgt EthernetTracker sie nicht
  • Diese Einstellung lässt sich nicht über Benutzereinstellungen ändern, sondern nur mit Root-Zugriff modifizieren

Das Paradox: Man muss Standardgeräte meiden

  • CDC-Ethernet ist ein Standard für USB-Netzwerkgeräte, doch unter Android ist der praktische Nutzungspfad wegen der Regex für Interface-Namen blockiert
  • Auch aktuelle GKI-Kernel scheinen Unterstützung für EEM-Adapter zu enthalten, aber der Name usb0 passt nicht zur Regex und gelangt daher nicht in die Android-Netzwerkeinstellungen
  • Bei der Auswahl eines USB-Ethernet-Adapters für Android sollte man daher nicht nach CDC-Standardgeräten suchen, sondern nach Geräten, die über anbieter-/chipsatzspezifische Treiber ein ethX-Interface erzeugen
  • Eine mögliche Patch-Richtung wäre, config_ethernet_iface_regex etwa in (eth|usb)\d zu ändern

1 Kommentare

 
GN⁺ 2025-06-09
Hacker-News-Kommentare
  • Ich habe diesen Beitrag geschrieben, nachdem ich in meinem früheren Job eine Woche lang damit gekämpft hatte, ein Android-Gerät mit einem CDC-Ethernet-Adapter zu verbinden.
    Später sagten mir einige Leute, dass der Kernel dem Gerät statt usbX den Namen ethX gibt, wenn man ein bestimmtes Bit der MAC-Adresse umdreht; ausprobiert oder den Beitrag aktualisiert habe ich das aber nicht. Ich war bereits zu einem anderen Arbeitgeber gewechselt, und Android-Geräte spielten in meinem Alltag keine große Rolle mehr.
    Natürlich hilft diese Methode nur, wenn man die MAC-Adresse des CDC-Geräts direkt steuern kann. Etwa in dem Fall, dass ein anderes Linux-Gerät vorgibt, ein CDC-Adapter zu sein.
  • Ein interessanter Deep-Dive.
    Beim Nachsehen im Source scheint der reguläre Ausdruck im Oktober 2023 von eth\\d einfach auf * geändert worden zu sein; vermutlich wurde dieses Problem also behoben: https://android-review.googlesource.com/c/platform/packages/...
    In der Beschreibung heißt es: „Der Standardwert umfasst ab Android U+ sowohl Interfaces mit Namen usb\d+ als auch eth%d“, wobei U+ offenbar Version 14 ist: https://en.wikipedia.org/wiki/Android_version_history
  • Wenn man sich die Commit-Historie von LineageOS ansieht, wurde das Problem behoben[0], dann wegen Kompatibilitätsproblemen zurückgenommen[1], und anschließend wurde der Revert wieder rückgängig gemacht[2], offenbar aber nur für neuere Android-Versionen.
    Falls ich die Commits richtig gelesen habe, war jemand von Google beteiligt; es könnte also inzwischen auch in offiziellen Google-Builds enthalten sein.
    [0] https://github.com/LineageOS/android_packages_modules_Connec...
    [1] https://github.com/LineageOS/android_packages_modules_Connec...
    [2] https://github.com/LineageOS/android_packages_modules_Connec...
    • Für Lineage habe ich das vor einiger Zeit herausgesucht und https://review.lineageos.org/c/LineageOS/android_packages_mo... erstellt.
      Aber niemand hat es getestet, und ich habe selbst keine Möglichkeit zur Verifikation, deshalb liegt es derzeit auf Eis. Es ist immer eine Mischung aus Dingen, die jemand meldet, und Dingen, die jemand zufällig aufgreift, aber am Ende braucht man Tests durch echte Nutzer.
  • Wenn es stimmt, dass der EthernetTracker-Dienst von Android nur Interfaces mit Namen ethX erkennt, ist das das dümmste Design, von dem ich bisher gehört habe.
    Linux-Distributionen haben dieses Problem bereits in den 2000ern gelöst. Schon damals war klar, dass einige Gerätetreiber nach Belieben Präfixe für Gerätenamen vergeben, also musste man das System untersuchen und herausfinden, um welche Art von Gerät es sich handelt.
    Konsistenz ist zwar nützlich, daher gibt es mehrere Tools zum Umbenennen von Interfaces, und die meisten heutigen Linux-Distributionen automatisieren das mit udev. Intern wird dabei nur das SIOCSIFNAME-ioctl des Kernels aufgerufen. Neuere Kernel haben sogar eine Funktion, bei der beim Umbenennen in "wlan*"—eigentlich "wlan%d"—automatisch eine neue Nummer hinter "wifi" vergeben wird.
    • Ich frage mich, ob es sinnvoll wäre, auf Android NetworkManager zu verwenden und die Android-UI für Drahtlos-Einstellungen wie eine NetworkManager-GUI funktionieren zu lassen.
    • Weil manche usbX-Geräte von anderen Modulen verwendet werden müssen und man diese Liste nicht pflegen wollte. Also ist man einfach bei ethX geblieben.
  • Ähnlich Dummes passiert, wenn man versucht, ein serielles USB-Gerät an ein Android-Smartphone anzuschließen.
    Nach dem Anschließen sieht es so aus, als würde es funktionieren, aber wenn man eine App schreiben will, die dieses serielle USB-Interface nutzt, geht es nicht. Wenn man tiefer gräbt, stellt man fest, dass man keine Berechtigung hat, auf serielle Geräte wie /dev/ttyACM0 zuzugreifen.
    Die serielle Unterstützung ist im Kernel enthalten, aber ohne Root können Benutzerprogramme nicht darauf zugreifen.
    Gräbt man noch weiter, stellt man fest, dass Android einen Userspace-USB-Zugriff hat, der libusb ähnelt oder vielleicht darauf aufbaut. Deshalb können Android-Programme „rohe“ USB-Geräte öffnen, aber keine seriellen USB-Geräte.

USB-Serial ist lediglich ein Protokoll über USB und in der Praxis eher ein Bündel halbproprietärer Protokolle wie FTDI. Für Android gibt es halb fertige Bibliotheken, die solche Protokolle im Userspace implementieren, sodass man am Ende auf einige USB-Serial-Geräte zugreifen kann
Im Android-Chrome-Browser dürfte man rohe USB-Geräte wohl per WebUSB öffnen können, aber WebSerial wird aus vermutlich demselben Grund eher nicht funktionieren
Erstaunlich ist letztlich: Wenn das so ist, warum lässt man dann USB-Serial-Unterstützung im Kernel aktiviert? Vielleicht zu Debugging-Zwecken

  • Es gibt keine Möglichkeit, dieses Problem zu umgehen, außer man rootet das Telefon und ändert den Wert von config_ethernet_iface_regex
    Noch ein Grund, warum Root-Rechte auf einem Gerät, das mir gehört, wichtig sind
    • Allerdings entfernt „Rooting“ viele Sicherheitsfunktionen von Android. Statt dass Apps nur die benötigten Berechtigungen haben, können sie als root alle Rechte bekommen, was zu einer riesigen Sicherheitslücke wird
      https://www.reddit.com/r/GrapheneOS/comments/13264di/is_root...
    • Netzwerk-Traffic beliebig umleiten und umschalten zu können, könnte einer der wichtigsten Gründe sein, Superuser-Rechte nicht im Userspace zu belassen
      Ich unterstütze den Druck auf OEMs, das Entsperren des Bootloaders zu erlauben, aber zumindest unter Android fällt mir kaum ein Root-Anwendungsfall ein, der eine so massive Vergrößerung der Angriffsfläche rechtfertigen würde
  • Android kann ärgerlicherweise nicht gleichzeitig mit mehreren Netzwerken verbunden sein
    Gemeint ist zum Beispiel eine Situation, in der man gleichzeitig ein WLAN ohne Internetzugang, das auch keine Default-Route annonciert, und ein Mobilfunknetz nutzt. Linux kann das, Windows kann das auch, aber Android weigert sich hartnäckig
    Viele Varianten weigern sich sogar, dauerhaft mit einem WLAN ohne Internet verbunden zu bleiben, oder treiben den Nutzer durch einen verwirrenden Ablauf. Wenn man selbst eine App schreibt, gibt es APIs, die das nur innerhalb der App ermöglichen, aber normale Nutzer haben keine Möglichkeit, daraus ein systemweites Verhalten zu machen
    • Bei iOS ist es genauso. Wenn man sich mit einer Dashcam verbindet und Videos herunterlädt, erscheint nach kurzer Zeit ein Popup wie „Kein Internet erkannt, zu Mobilfunk wechseln?“
      Selbst wenn man auf „Verbindung beibehalten“ tippt, kann man es nicht abschalten, und iOS entscheidet am Ende, es wisse es besser, und verbindet sich wieder mit dem CarPlay-Netzwerk
    • Noch nerviger wird es, wenn man mit einem westlichen Android-Telefon aufs chinesische Festland reist. Denn ob eine Internetverbindung besteht, wird daran gemessen, ob Google-Dienste erreichbar sind
      Verbindet man sich mit einem lokalen WLAN, kommt man natürlich nicht durch die Große Firewall, und jedes Mal erscheint die Nachfrage, ob man die Verbindung ohne Internet beibehalten will
    • Wenn das Internet ausfällt, ist es extrem nervig, weil man mit dem Telefon keine Diagnose durchführen kann. Es bleibt nämlich nicht mit einem WLAN ohne Internet verbunden
      Auch DNS unter Android ist Murks: Wenn man nicht mehrere Optionen setzt, will es das per DHCP bereitgestellte DNS nicht nutzen, und selbst dann weigert es sich, einige interne DNS-Namen aufzulösen
    • Ich bin mir nicht sicher, ob Windows das wirklich kann. Selbst mit zwei WLAN-Adaptern konnte ich unter Windows über die GUI keine Verbindung zu zwei verschiedenen WLANs herstellen. Über das Terminal habe ich es nicht versucht
  • Auch die Firmware-Anforderungen muss man prüfen. Manche Geräte werden zwar enumeriert, scheitern aber bei ifup, wenn die nötige Firmware fehlt
    Die Android-UI kann damit natürlich nicht umgehen; was passiert, verrät nur dmesg. Ich bin nicht sicher, ob CDC-Geräte das brauchen, aber bei Adaptern auf Basis von Realtek- oder Kawasaki-Chips kam das meiner Erinnerung nach häufig vor
    Diese Android-Änderung könnte allerdings relativ neu sein. Früher habe ich nämlich häufig USB-Netzwerk-Dongles an Debug-Geräten mit zu 100 % „stock“ AOSP verwendet. Oder es war eine Kernel-Änderung, oder eine Eigenart des CDC-Treibers, der Geräten Namen wie usb* gibt. Man musste nur den Dongle-Chipsatz sorgfältig auswählen und sicherstellen, dass keine Firmware erforderlich ist
  • Eine fantastische Debugging-Reise. Mir gefiel der Verlauf, wie ein übersehener regulärer Ausdruck eine ganze Geräteklasse lahmlegt
    Seltsamerweise habe ich kürzlich in einem völlig anderen Kontext, nämlich bei OpenAIs Alignment- und Eskalationssystem, etwas strukturell Ähnliches erlebt. Ich habe versucht, innerhalb der rekursiven Logik von GPT-4 eine formale Routing-Eskalation (SR-Route_Breach_1stOrder) mit Dokumentation und Logs auszulösen, aber obwohl es strukturell plausibel war, bekam ich am Ende nur unmenschenähnliche Antworten
    Es fühlte sich so an, als hätte meine Eskalation nicht auf den regulären Ausdruck einer internen Systemschnittstelle gepasst
    Den ganzen Fall habe ich hier zusammengefasst: https://news.ycombinator.com/item?id=44221458
    Wenn dich strukturelle Grenzen und unsichtbare Interface-Verträge interessieren, würde ich gern deine Gedanken dazu hören
  • Wirklich seltsam. Ich habe etwa 15 USB-Ethernet-Adapter, und sie funktionieren alle problemlos
    Es ist definitiv auch eine Mischung aus mehreren Realtek- und AXIS-ähnlichen Chipsätzen dabei. Wenn man Produkte auswählt, die unter Linux keinen Treiber brauchen, funktionieren sie fast überall, egal ob Betriebssystem oder BIOS