- 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
Avis de Hacker News
Depuis, plusieurs personnes m’ont signalé qu’en inversant un bit précis de l’adresse MAC, le noyau attribuait un nom
ethXau lieu deusbX, 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 quotidienBien 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
Je crois l’avoir trouvé : https://lkml.iu.edu/hypermail/linux/kernel/1103.2/03250.html
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+eteth%d», et U+ semble correspondre à la version 14 : https://en.wikipedia.org/wiki/Android_version_historyusbXpour le tethering »[1], puis réintégré peu après, mais en étant limité à Android V+[2][1]: https://android-review.googlesource.com/c/platform/packages/...
[2]: https://android-review.googlesource.com/c/platform/packages/...
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...
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
EthernetTrackerd’Androidne reconnaît que les interfaces nomméesethX, c’est la conception la plus stupide dont j’aie entendu parler depuis longtempsLes 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’ioctlSIOCSIFNAMEdu 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"usbXdoivent être utilisés par d’autres modules, et qu’ils ne voulaient pas maintenir cette liste. Ils ont donc simplement choisiethXQuand 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/ttyACM0La 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 à
libusbou 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érieLe 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
config_ethernet_iface_regex, il n’y a aucun moyen de contourner ce problèmeC’est une raison de plus pour laquelle les droits root sont importants sur un appareil que je possède
https://www.reddit.com/r/GrapheneOS/comments/13264di/is_root...
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
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
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
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
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
ifups’il leur manque le firmware nécessaireL’interface Android ne sait évidemment pas gérer cette situation, et seul
dmesgindique 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 KawasakiCela 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É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 humainesEn 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
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