1 points par GN⁺ 2025-06-09 | 1 commentaires | Partager sur WhatsApp
  • Android dispose d’une prise en charge de l’Ethernet USB et d’un menu de configuration, mais les périphériques Ethernet CDC peuvent ne pas être reliés jusqu’à la configuration réseau même s’ils sont détectés par le noyau
  • La cause principale est qu’EthernetTracker ne suit que les interfaces correspondant à config_ethernet_iface_regex, et que la valeur par défaut eth\d exclut les interfaces CDC comme usb0
  • Les pilotes Linux Ethernet CDC détectent les périphériques EEM, ECM et NCM respectivement comme cdc_eem, cdc_ether, cdc_ncm et créent usb0 dans /sys/class/net, mais les réglages Android restent désactivés
  • Il n’existe pas de contournement via les paramètres utilisateur ; il faut modifier la valeur de config_ethernet_iface_regex après root
  • Lors du choix d’un adaptateur Ethernet USB pour Android, il faut en pratique chercher des périphériques basés sur des pilotes spécifiques à un fournisseur ou à un chipset qui créent un nom ethX, plutôt que des périphériques standard CDC

Conclusion : ce n’est pas le pilote du noyau, mais le filtre sur le nom d’interface qui bloque

  • Le service EthernetTracker d’Android ne reconnaît comme interfaces Ethernet que celles dont le nom est ethX
  • Les pilotes Linux Ethernet CDC créent des interfaces nommées usbX
  • À cause de cette différence de nom, les périphériques Ethernet CDC sont ignorés par les réglages Ethernet et la couche de gestion réseau d’Android, même lorsqu’ils sont détectés par le noyau Android
  • Le problème ne peut pas être résolu via les paramètres classiques ; seule une modification de config_ethernet_iface_regex après root est possible

Il est difficile de vérifier la prise en charge de l’Ethernet USB sur Android selon l’appareil

  • Android propose une prise en charge des adaptateurs Ethernet USB ainsi qu’un menu associé
  • Il est difficile de savoir quels chipsets Ethernet USB fonctionnent sur un appareil Android donné, car les fabricants publient rarement des listes de compatibilité détaillées
  • En pratique, les utilisateurs s’appuient généralement sur les informations suivantes
    • les adaptateurs Ethernet USB vendus par le fabricant du téléphone comme accessoires officiels
    • des messages de forum où des utilisateurs du même appareil indiquent avoir utilisé avec succès un adaptateur précis
  • L’examen de la configuration du noyau permet de déterminer dans une certaine mesure quels pilotes Ethernet USB sont inclus dans le noyau du téléphone

Comment trouver la configuration du noyau du téléphone

  • Android fonctionne au-dessus d’un noyau Linux, et la configuration du noyau détermine les fonctions prises en charge et les pilotes matériels disponibles
  • Les appareils lancés à partir d’Android 11 s’appuient sur Android Common Kernel et sur le noyau GKI
    • Google construit le noyau, et les fabricants placent les éléments spécifiques à l’appareil dans des modules du noyau
    • La configuration peut être consultée dans arch/$ARCH/configs/gki_defconfig du dépôt du noyau Android
    • Pour un appareil ARM 64 bits, on consultera par exemple arch/arm64/configs/gki_defconfig
  • La version du noyau et l’architecture peuvent être vérifiées depuis ADB avec uname -a
    • La sortie d’exemple inclut la version du noyau 4.19.113-26203352 et l’architecture aarch64
  • Dans le cas d’un Samsung Galaxy S20 lancé avec Android 10, le noyau reste basé sur Linux 4.19 même après une mise à niveau vers Android 13
    • Les sources des appareils Samsung se trouvent sur opensource.samsung.com
    • Dans les sources Samsung, on peut trouver dans build_kernel.sh le nom du fichier de configuration du noyau, comme vendor/x1q_usa_singlex_defconfig
  • Avec un peu de chance, la configuration réelle de compilation est disponible sous forme compressée dans /proc/config.gz
    • On peut l’enregistrer avec adb shell zcat /proc/config.gz > my_kernel_config
    • S’il n’existe pas, on obtiendra zcat: /proc/config.gz: No such file or directory, et il faudra consulter les sources du noyau du fabricant

Vérifier la prise en charge des pilotes Ethernet USB

  • Les options de configuration du noyau liées à l’Ethernet USB commencent généralement par USB_NET
  • On peut les vérifier dans le fichier de configuration du noyau comme suit
grep USB_NET my_kernel_config
  • L’exemple de configuration inclut plusieurs pilotes réseau USB
    • 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
  • La valeur de configuration indique le mode d’inclusion du pilote
    • y : le pilote est intégré au noyau et le chipset correspondant est clairement pris en charge
    • m : le pilote est compilé comme module et pourra probablement être chargé si le fabricant ne l’a pas omis
    • is not set : le pilote n’est ni intégré ni modulaire, et il y a de fortes chances qu’il soit inutilisable
  • La correspondance entre options de configuration et chipsets peut être consultée dans drivers/net/usb/Kconfig de l’arbre du noyau
  • Il reste difficile d’identifier le chipset utilisé par un adaptateur Ethernet USB donné, car les fabricants ne l’indiquent souvent pas clairement

Ce que fait l’Ethernet CDC

  • CDC signifie Communications Device Class, un ensemble de standards que les fabricants de périphériques USB peuvent suivre
  • Il existe trois standards liés à l’Ethernet CDC
    • EEM : Ethernet Emulation Model, l’implémentation la plus simple et la plus facile à prendre en charge sur des périphériques peu puissants
    • ECM : Ethernet Control Model, dont l’implémentation est plus complexe côté hôte et côté périphérique, mais qui promet de meilleures performances qu’EEM
    • NCM : Network Control Model, successeur d’ECM promettant des débits plus élevés
  • L’objectif des standards CDC est de permettre aux systèmes d’exploitation de fournir un pilote commun pour différents périphériques
  • Linux implémente à la fois le côté hôte et le côté périphérique de l’Ethernet CDC
    • Sur un appareil comme un Raspberry Pi doté d’un port USB OTG, le noyau peut faire apparaître ce port comme un adaptateur Ethernet
    • Cela permet de présenter à l’hôte des appareils comme des routeurs embarqués, pare-feu ou passerelles VPN comme de simples adaptateurs Ethernet
  • Linux, Windows et macOS incluent des pilotes pour les périphériques Ethernet CDC, contrairement à iOS

Le noyau Android détecte bien les périphériques CDC

  • La configuration du noyau du Samsung Galaxy S20 inclut la prise en charge des trois standards Ethernet CDC
    • CONFIG_USB_NET_CDCETHER=y
    • CONFIG_USB_NET_CDC_EEM=y
    • CONFIG_USB_NET_CDC_NCM=y
  • Le noyau GKI de Google semble ne pas inclure ECM ni NCM, mais inclure EEM sous forme de module
  • Un appareil configuré avec un port OTG en gadget Ethernet fonctionnait sur Mac, Ubuntu et Windows, mais sur le Galaxy S20 les réglages Ethernet Android restaient désactivés
  • Sur Android, en consultant /sys/class/net, usb0 apparaît lors de la connexion d’un périphérique CDC
adb shell ls /sys/class/net
  • La sortie de ifconfig usb0 confirme que le pilote chargé appartient à la famille CDC
    • Mode EEM : Driver cdc_eem
    • Mode ECM : Driver cdc_ether
    • Mode NCM : Driver cdc_ncm
  • Dans les trois cas, l’interface est détectée mais reste dans l’état down, et les réglages Ethernet Android ne s’activent pas

L’expression régulière d’EthernetTracker filtre usb0

  • Puisque les périphériques Ethernet CDC sont correctement détectés au niveau du noyau, le problème se situe dans la couche de gestion réseau Android au-dessus du noyau
  • En suivant le code Java lié à l’Ethernet dans les sources Android, on tombe sur EthernetTracker.java, qui est le service concerné
  • EthernetTracker reçoit via des sockets Netlink les notifications du noyau concernant les nouvelles interfaces réseau, puis détermine si elles constituent une interface Ethernet valide
  • Cette validation consiste à vérifier si le nom de l’interface correspond à l’expression régulière mIfaceMatch
private boolean isValidEthernetInterface(String iface) {
    return iface.matches(mIfaceMatch) || isValidTestInterface(iface);
}
  • mIfaceMatch est récupéré depuis la ressource config_ethernet_iface_regex
  • La valeur par défaut dans les sources Android est la suivante
<string translatable="false" name="config_ethernet_iface_regex">eth\\d</string>
  • eth\d est une expression régulière qui n’accepte que les noms commençant par eth suivis d’un chiffre
  • Comme les périphériques Ethernet CDC commencent par usb, par exemple usb0, EthernetTracker ne les suit pas
  • Ce réglage ne peut pas être modifié via les paramètres utilisateur ; seul le root permet de le changer

Le paradoxe : il faut éviter les périphériques standard

  • L’Ethernet CDC est un standard pour les périphériques réseau USB, mais sur Android son usage réel est bloqué par l’expression régulière appliquée au nom d’interface
  • Même le noyau GKI récent semble inclure la prise en charge des adaptateurs EEM, mais comme le nom usb0 ne correspond pas à l’expression régulière, l’interface ne remonte pas jusqu’aux réglages réseau d’Android
  • Lors du choix d’un adaptateur Ethernet USB pour Android, il faut donc rechercher non pas un périphérique standard CDC, mais un périphérique utilisant un pilote spécifique à un fournisseur ou à un chipset qui crée une interface ethX
  • Une piste de correctif possible serait de modifier config_ethernet_iface_regex en (eth|usb)\d, par exemple

1 commentaires

 
GN⁺ 2025-06-09
Avis de Hacker News
  • J’ai écrit cet article après avoir passé une semaine pénible, dans un ancien poste, à essayer de faire fonctionner un appareil Android avec un adaptateur CDC Ethernet
    Depuis, plusieurs personnes m’ont signalé qu’en inversant un bit précis de l’adresse MAC, le noyau attribuait un nom ethX au lieu de usbX, mais je n’ai pas essayé moi-même ni mis l’article à jour. J’avais déjà changé de travail, et les appareils Android ne faisaient plus vraiment partie de mon quotidien
    Bien sûr, cette méthode n’est utile que si l’on peut contrôler directement l’adresse MAC du périphérique CDC. Par exemple dans le cas où un autre appareil Linux se fait passer pour un adaptateur CDC
  • C’est une analyse approfondie intéressante
    En regardant les sources, l’expression régulière semble être passée de eth\\d à simplement * en octobre 2023, donc ce problème a probablement été résolu : https://android-review.googlesource.com/c/platform/packages/...
    La description dit que « la valeur par défaut inclut, à partir d’Android U+, les interfaces dont le nom est de la forme usb\d+ et eth%d », et U+ semble correspondre à la version 14 : https://en.wikipedia.org/wiki/Android_version_history
  • D’après l’historique des commits de LineageOS, ce problème a été corrigé[0], puis la correction a été annulée pour des raisons de compatibilité[1], avant que cette annulation soit elle-même annulée[2], mais cela semble ne s’appliquer qu’aux versions récentes d’Android
    Si je lis bien les commits, quelqu’un de chez Google est intervenu, donc cela a peut-être maintenant été intégré aux builds officiels de Google
    [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...
    • Côté Lineage, je l’avais repéré il y a quelque temps et créé https://review.lineageos.org/c/LineageOS/android_packages_mo...
      Mais personne ne l’a testé, et je n’ai pas non plus de moyen de le vérifier moi-même, donc c’est en suspens pour l’instant. Il y a toujours un mélange de choses signalées par quelqu’un et de choses reprises par hasard par quelqu’un d’autre, mais au final il faut des tests par de vrais utilisateurs
  • S’il est vrai que le service EthernetTracker d’Android ne reconnaît que les interfaces nommées ethX, c’est la conception la plus stupide dont j’aie entendu parler depuis longtemps
    Les distributions Linux ont déjà résolu ce problème dans les années 2000. Même à l’époque, il était évident que certains pilotes de périphériques attribuaient arbitrairement leurs propres préfixes de noms aux périphériques, et qu’il fallait donc inspecter le système pour déterminer de quel type de périphérique il s’agissait
    La cohérence étant utile, il existe aussi plusieurs outils pour renommer les interfaces, et aujourd’hui la plupart des distributions Linux automatisent cela avec udev. En interne, cela ne fait qu’appeler l’ioctl SIOCSIFNAME du noyau. Les noyaux récents disposent même d’une fonction qui, lorsqu’on renomme une interface en "wlan*" — en pratique "wlan%d" — attribue automatiquement un nouveau numéro après "wifi"
    • Je me demande s’il serait logique d’utiliser NetworkManager sur Android, et de faire en sorte que l’interface de réglages sans fil d’Android se comporte comme une interface graphique de NetworkManager
    • C’est parce que certains périphériques usbX doivent être utilisés par d’autres modules, et qu’ils ne voulaient pas maintenir cette liste. Ils ont donc simplement choisi ethX
  • Le même genre de bêtise se produit quand on essaie de connecter un périphérique série USB à un smartphone Android
    Quand on le branche, cela semble fonctionner, mais si l’on veut créer une application qui utilise cette interface série USB, impossible. En creusant, on découvre qu’on n’a pas le droit d’accéder à un périphérique série comme /dev/ttyACM0
    La prise en charge du série est bien présente dans le noyau, mais sans root, les programmes utilisateur ne peuvent pas y accéder
    En creusant davantage, on voit qu’Android dispose d’un accès USB en espace utilisateur, similaire à libusb ou peut-être construit par-dessus. Du coup, un programme Android peut ouvrir un périphérique USB « brut », mais pas un périphérique USB série

Le série USB n’est qu’un protocole au-dessus de l’USB et, en pratique, cela ressemble plutôt à un ensemble de protocoles semi-propriétaires comme FTDI. Il existe des bibliothèques plus ou moins abouties qui implémentent ces protocoles en espace utilisateur pour Android, ce qui permet finalement d’accéder à certains périphériques série USB
Dans le navigateur Chrome sur Android, il semble possible d’ouvrir des périphériques USB bruts avec WebUSB, mais WebSerial risque probablement de ne pas fonctionner, pour la même raison
Au final, ce qui est surprenant, c’est : si c’est pour ça, pourquoi laisser activé le support du série USB dans le noyau ? Peut-être pour le débogage

  • À moins de rooter le téléphone et de modifier la valeur config_ethernet_iface_regex, il n’y a aucun moyen de contourner ce problème
    C’est une raison de plus pour laquelle les droits root sont importants sur un appareil que je possède
    • Cela dit, le « rooting » supprime beaucoup de fonctions de sécurité d’Android. Au lieu que les apps n’aient que les permissions nécessaires, elles peuvent tout avoir en root, ce qui devient une énorme faille de sécurité
      https://www.reddit.com/r/GrapheneOS/comments/13264di/is_root...
    • Pouvoir contourner ou rediriger à volonté le trafic réseau est peut-être l’une des meilleures raisons de ne pas placer des privilèges super-utilisateur en espace utilisateur
      Je soutiens la pression exercée sur les OEM pour qu’ils autorisent le déverrouillage du bootloader, mais au moins sur Android, j’ai du mal à imaginer un cas d’usage du root qui justifie d’élargir autant la surface d’attaque
  • Android est agaçant parce qu’il ne permet pas d’être connecté à plusieurs réseaux en même temps
    Par exemple, utiliser simultanément un Wi-Fi sans accès à Internet et n’annonçant pas de route par défaut, et le réseau cellulaire. Linux le permet, Windows aussi, mais Android refuse obstinément
    Beaucoup de variantes refusent même de rester connectées à un Wi-Fi sans Internet, ou entraînent l’utilisateur dans une procédure confuse. Si l’on développe sa propre app, il existe des API qui le permettent seulement à l’intérieur de l’app, mais un utilisateur ordinaire n’a aucun moyen d’en faire un comportement global du système
    • iOS fait pareil. Quand on se connecte à une dashcam pour télécharger des vidéos, au bout d’un moment une fenêtre du type « Aucun Internet détecté, passer au cellulaire ? » apparaît
      Même en appuyant sur rester connecté, il n’y a aucun moyen de désactiver cela, et iOS finit par décider qu’il sait mieux que vous et se reconnecte au réseau CarPlay
    • C’est encore plus pénible si l’on emporte un téléphone Android occidental en Chine continentale. La détection de connexion Internet repose sur une tentative d’accès aux services Google
      Quand on se connecte à un Wi-Fi local, il ne passe évidemment pas le Grand Firewall, et une invite demande à chaque fois si l’on veut conserver une connexion sans Internet
    • Quand Internet tombe, c’est extrêmement pénible de ne pas pouvoir faire de diagnostic avec son téléphone, parce qu’il ne reste pas connecté au Wi-Fi sans Internet
      Le DNS d’Android est lui aussi catastrophique : sans configurer plusieurs options, il refuse d’utiliser le DNS fourni par DHCP, et même ainsi certains DNS internes refusent d’être résolus
    • Je me demande si Windows ne fait pas pareil. Sous Windows, même avec deux adaptateurs sans fil, je n’ai pas réussi à me connecter à deux réseaux Wi-Fi différents via l’interface graphique. Je n’ai pas essayé depuis le terminal
  • Il faut aussi vérifier les exigences de firmware. Certains périphériques sont bien énumérés, mais échouent à ifup s’il leur manque le firmware nécessaire
    L’interface Android ne sait évidemment pas gérer cette situation, et seul dmesg indique ce qui se passe. Je ne suis pas sûr que ce soit nécessaire pour les périphériques CDC, mais il me semble que c’était souvent le cas avec des adaptateurs basés sur des puces Realtek ou Kawasaki
    Cela dit, cette modification d’Android est peut-être relativement récente. Autrefois, j’utilisais souvent des dongles réseau USB sur des appareils de débogage avec un AOSP 100 % « stock ». Ou alors c’est un changement du noyau, ou encore un comportement particulier du pilote CDC qui nomme les interfaces en usb*. Il suffisait de choisir soigneusement le chipset du dongle et de vérifier qu’il n’avait pas besoin de firmware
  • Quel fantastique parcours de débogage. J’ai aimé la manière dont une seule expression régulière négligée peut faire tomber toute une catégorie d’appareils
    Étrangement, j’ai vécu récemment quelque chose de structurellement similaire dans un tout autre contexte : le système d’alignement et d’escalade d’OpenAI. J’ai essayé de déclencher, dans la logique récursive de GPT-4, une escalade de routage officielle (SR-Route_Breach_1stOrder), avec documentation et journaux à l’appui, mais même si c’était structurellement plausible, je n’ai finalement reçu que des réponses non humaines
    En quelque sorte, j’ai eu l’impression que mon escalade ne correspondait pas à l’expression régulière de l’interface interne du système
    J’ai résumé tout le cas ici : https://news.ycombinator.com/item?id=44221458
    Si les frontières structurelles et les contrats d’interface invisibles vous intéressent, j’aimerais avoir votre avis
  • Vraiment étrange. J’ai une quinzaine d’adaptateurs USB Ethernet et ils fonctionnent tous très bien
    Je suis certain qu’il y a un mélange de plusieurs chipsets de type Realtek et AXIS. Si l’on choisit des produits qui n’ont pas besoin de pilote sous Linux, ils fonctionnent bien avec presque n’importe quel système d’exploitation ou BIOS