1 puntos por GN⁺ 2025-06-09 | 1 comentarios | Compartir por WhatsApp
  • Android tiene soporte para Ethernet por USB y un menú de configuración, pero los dispositivos CDC Ethernet pueden ser detectados por el kernel sin llegar a integrarse con la configuración de red
  • La causa principal es que EthernetTracker solo sigue interfaces que coinciden con config_ethernet_iface_regex, y el valor predeterminado eth\d deja fuera interfaces CDC como usb0
  • El driver de Linux para CDC Ethernet detecta dispositivos EEM, ECM y NCM como cdc_eem, cdc_ether y cdc_ncm, y crea usb0 en /sys/class/net, pero la configuración de Android sigue desactivada
  • No se puede sortear con la configuración normal del usuario; hace falta root y cambiar el valor de config_ethernet_iface_regex
  • Al elegir un adaptador USB Ethernet para Android, termina siendo necesario buscar dispositivos basados en drivers específicos del fabricante/chipset que creen nombres ethX, en lugar de dispositivos estándar CDC

Conclusión: no lo bloquea el driver del kernel, sino el filtro por nombre de interfaz

  • El servicio EthernetTracker de Android solo reconoce como interfaces Ethernet aquellas cuyo nombre es ethX
  • Los drivers de Linux para CDC Ethernet crean nombres de interfaz usbX
  • Por esta diferencia de nombres, los dispositivos CDC Ethernet son detectados por el kernel de Android pero ignorados por la configuración de Ethernet y la capa de administración de red
  • No se puede resolver con la configuración normal; solo es posible cambiando config_ethernet_iface_regex después de rootear el dispositivo

Es difícil verificar el soporte de USB Ethernet en Android según el dispositivo

  • Android incluye soporte para adaptadores USB Ethernet y un menú relacionado
  • Es difícil confirmar qué chipsets de USB Ethernet funcionan en un dispositivo Android específico porque los fabricantes casi nunca publican listas de compatibilidad
  • En la práctica, el usuario suele depender de lo siguiente
    • Adaptadores USB Ethernet que el fabricante del teléfono vende como accesorios oficiales
    • Publicaciones en foros donde usuarios del mismo dispositivo reportan haber usado con éxito cierto adaptador
  • Revisando la configuración del kernel se puede inferir en cierta medida qué drivers de USB Ethernet incluye el kernel del teléfono

Cómo encontrar la configuración del kernel del teléfono

  • Android funciona sobre el kernel de Linux, y la configuración del kernel determina las funciones compatibles y los drivers de hardware
  • Los dispositivos lanzados desde Android 11 en adelante se basan en Android Common Kernel y el kernel GKI
    • Google compila el kernel, y los fabricantes ponen los elementos específicos del dispositivo en módulos del kernel
    • La configuración puede revisarse en arch/$ARCH/configs/gki_defconfig dentro del repositorio del kernel de Android
    • En dispositivos ARM de 64 bits, por ejemplo, se revisa arch/arm64/configs/gki_defconfig
  • La versión del kernel y la arquitectura pueden comprobarse desde ADB con uname -a
    • La salida de ejemplo incluye la versión del kernel 4.19.113-26203352 y la arquitectura aarch64
  • En el caso del Samsung Galaxy S20, lanzado con Android 10, incluso después de actualizarse a Android 13 siguió usando un kernel basado en Linux 4.19
    • El código fuente de dispositivos Samsung puede encontrarse en opensource.samsung.com
    • En build_kernel.sh del código fuente de Samsung se puede encontrar el nombre del archivo de configuración del kernel, como vendor/x1q_usa_singlex_defconfig
  • Con un poco de suerte, la configuración real de compilación existe comprimida en /proc/config.gz
    • Puede guardarse con adb shell zcat /proc/config.gz > my_kernel_config
    • Si no existe, aparecerá zcat: /proc/config.gz: No such file or directory y habrá que revisar el código fuente del kernel del fabricante

Cómo verificar el soporte de drivers USB Ethernet

  • Las opciones del kernel relacionadas con USB Ethernet normalmente empiezan con USB_NET
  • En el archivo de configuración del kernel puede comprobarse así
grep USB_NET my_kernel_config
  • La configuración de ejemplo incluye varios drivers de red 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
  • Los valores de configuración distinguen cómo se incluye cada driver
    • y: el driver está integrado en el kernel y ese chipset está soportado con seguridad
    • m: el driver fue compilado como módulo, y puede cargarse si el fabricante no lo omitió
    • is not set: el driver no está integrado ni como módulo, así que probablemente no pueda usarse
  • La correspondencia entre opciones de configuración y chipsets puede consultarse en drivers/net/usb/Kconfig dentro del árbol del kernel
  • Sigue siendo difícil identificar qué chipset usa un adaptador USB Ethernet específico, porque muchas veces el fabricante no lo indica claramente

Qué hace CDC Ethernet

  • CDC significa Communications Device Class, un conjunto de estándares que los fabricantes de dispositivos USB pueden seguir
  • Hay tres estándares relacionados con CDC Ethernet
    • EEM: Ethernet Emulation Model, la implementación más simple y más fácil de soportar en dispositivos de bajo rendimiento
    • ECM: Ethernet Control Model, con una implementación más compleja tanto en el host como en el dispositivo, pero con mejor rendimiento que EEM
    • NCM: Network Control Model, sucesor de ECM que promete mayor velocidad
  • El objetivo de los estándares CDC es permitir que el sistema operativo ofrezca un driver común para distintos dispositivos
  • Linux implementa tanto el lado host como el lado dispositivo de CDC Ethernet
    • En equipos como una Raspberry Pi con puerto USB OTG, el kernel puede hacer que ese puerto se presente como si fuera un adaptador Ethernet
    • Eso permite que dispositivos como routers embebidos, firewalls o gateways VPN aparezcan ante el host como adaptadores Ethernet normales
  • Linux, Windows y macOS incluyen drivers para dispositivos CDC Ethernet, pero iOS no

El kernel de Android sí detecta dispositivos CDC

  • La configuración del kernel del Samsung Galaxy S20 incluye soporte para los tres estándares de CDC Ethernet
    • CONFIG_USB_NET_CDCETHER=y
    • CONFIG_USB_NET_CDC_EEM=y
    • CONFIG_USB_NET_CDC_NCM=y
  • El kernel GKI de Google parece no incluir ECM ni NCM, y EEM aparentemente viene como módulo
  • Un dispositivo configurado como Ethernet gadget sobre un puerto OTG funcionó en Mac, Ubuntu y Windows, pero en el Galaxy S20 la configuración de Ethernet de Android siguió desactivada
  • Al revisar /sys/class/net en Android, aparece usb0 cuando se conecta un dispositivo CDC
adb shell ls /sys/class/net
  • La salida de ifconfig usb0 confirma que el driver cargado pertenece a la familia CDC
    • Modo EEM: Driver cdc_eem
    • Modo ECM: Driver cdc_ether
    • Modo NCM: Driver cdc_ncm
  • En los tres casos la interfaz es detectada, pero queda en estado down y la configuración de Ethernet de Android no se activa

La expresión regular de EthernetTracker filtra usb0

  • Como a nivel de kernel los dispositivos CDC Ethernet se detectan correctamente, el problema está en la capa de administración de red de Android que se encuentra por encima del kernel
  • Siguiendo el código fuente de Android relacionado con Ethernet, EthernetTracker.java aparece como el servicio relevante
  • EthernetTracker recibe por sockets Netlink las notificaciones del kernel sobre nuevas interfaces de red y decide si son interfaces Ethernet válidas
  • Esa validación consiste en comprobar si el nombre de la interfaz coincide con la expresión regular mIfaceMatch
private boolean isValidEthernetInterface(String iface) {
    return iface.matches(mIfaceMatch) || isValidTestInterface(iface);
}
  • mIfaceMatch se obtiene del recurso config_ethernet_iface_regex
  • El valor predeterminado en el código fuente de Android es el siguiente
<string translatable="false" name="config_ethernet_iface_regex">eth\\d</string>
  • eth\d es una expresión regular que solo deja pasar nombres con eth seguido de un número
  • Como los dispositivos CDC Ethernet empiezan con usb, por ejemplo usb0, EthernetTracker no los sigue
  • Esta configuración no puede cambiarse desde los ajustes del usuario; solo puede modificarse con root

La paradoja de tener que evitar dispositivos estándar

  • CDC Ethernet es un estándar para dispositivos de red USB, pero en Android el camino de uso real queda bloqueado por la expresión regular del nombre de la interfaz
  • Incluso los kernels GKI modernos parecen incluir soporte para adaptadores EEM, pero como el nombre usb0 no coincide con la expresión regular, no aparecen en la configuración de red de Android
  • Al elegir un adaptador USB Ethernet para Android, conviene buscar no un dispositivo estándar CDC sino uno que, mediante un driver específico del fabricante o del chipset, cree una interfaz ethX
  • Una posible dirección para el parche sería cambiar config_ethernet_iface_regex a algo como (eth|usb)\d

1 comentarios

 
GN⁺ 2025-06-09
Comentarios de Hacker News
  • Escribí este artículo después de una semana complicada en un trabajo anterior intentando conectar dispositivos Android y adaptadores CDC Ethernet.
    Después, varias personas me dijeron que, si se invertía cierto bit específico de la dirección MAC, el kernel le ponía el nombre ethX en vez de usbX, pero no lo probé personalmente ni actualicé el artículo. Para entonces ya me había cambiado de trabajo y los dispositivos Android ya no eran una parte importante de mi día a día.
    Claro que este método solo ayuda cuando se puede controlar directamente la dirección MAC del dispositivo CDC. Por ejemplo, en un caso donde otro dispositivo Linux se hace pasar por un adaptador CDC.
  • Es un análisis profundo interesante.
    Buscando en el código fuente, en octubre de 2023 la expresión regular cambió de eth\\d a simplemente *, así que probablemente este problema quedó resuelto: https://android-review.googlesource.com/c/platform/packages/...
    La descripción dice: “el valor predeterminado incluye interfaces con nombres usb\d+ y eth%d en Android U+”, y aquí U+ parece ser la versión 14: https://en.wikipedia.org/wiki/Android_version_history
  • Viendo el historial de commits de LineageOS, parece que este problema se corrigió[0], luego se revirtió por problemas de compatibilidad[1], y después se canceló esa reversión[2], pero aparentemente solo se aplicó a las versiones más recientes de Android.
    Si leí bien los commits, participó alguien de Google, así que quizá ya esté incluido también en las builds oficiales 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...
    • En Lineage, lo encontré hace ya un tiempo y creé https://review.lineageos.org/c/LineageOS/android_packages_mo....
      Pero nadie lo probó, y yo tampoco tenía forma de verificarlo directamente, así que por ahora está en pausa. Siempre se mezclan cosas que alguien reportó y cosas que alguien tomó por casualidad, pero al final se necesitan pruebas de usuarios reales.
  • Si es cierto que el servicio EthernetTracker de Android solo reconoce interfaces llamadas ethX, es el diseño más tonto que he escuchado hasta ahora.
    Las distribuciones Linux ya resolvieron este problema en los años 2000. Incluso entonces estaba claro que algunos drivers de dispositivos ponían prefijos de nombre de dispositivo como se les daba la gana, así que había que inspeccionar el sistema para averiguar qué tipo de dispositivo era.
    La consistencia es útil, así que también hay varias herramientas para cambiar nombres de interfaces, y hoy la mayoría de las distribuciones Linux lo automatizan con udev. Internamente, no es más que llamar al ioctl SIOCSIFNAME del kernel. Los kernels modernos incluso tienen una función que, si se cambia el nombre a "wlan*" —en realidad "wlan%d"—, asigna automáticamente un nuevo número después de "wifi".
    • Me pregunto si tendría sentido usar NetworkManager en Android y hacer que la UI de configuración inalámbrica de Android se comporte como una GUI de NetworkManager.
    • Porque algunos dispositivos usbX deben ser usados por otros módulos, y no querían mantener esa lista. Así que simplemente se fueron por ethX.
  • Algo igual de tonto pasa cuando se intenta conectar un dispositivo serial USB a un smartphone Android.
    Al conectarlo parece funcionar, pero si intentas crear una app que use esa interfaz serial USB, no se puede. Si investigas más, ves que no tienes permiso para acceder a un dispositivo serial como /dev/ttyACM0.
    El soporte serial está en el kernel, pero sin root no se puede acceder desde programas de usuario.
    Si sigues investigando, Android tiene una función de acceso USB en espacio de usuario que es parecida a libusb o quizá está construida sobre ella. Así que un programa Android puede abrir dispositivos USB “en bruto”, pero no puede abrir dispositivos USB seriales.

USB serial es solo un protocolo sobre USB y, en la práctica, se parece más a un conjunto de protocolos semipropietarios como FTDI. Hay bibliotecas a medio hacer para Android que implementan estos protocolos en espacio de usuario, así que al final sí se puede acceder a algunos dispositivos USB seriales
En el navegador Chrome de Android parece que WebUSB podría abrir dispositivos USB sin procesar, pero es muy probable que WebSerial no funcione por la misma razón
Al final, lo sorprendente es: si va a ser así, ¿para qué dejan habilitado el soporte de USB serial en el kernel? Supongo que será para depuración

  • No hay forma de esquivar este problema a menos que rootees el teléfono y cambies el valor de config_ethernet_iface_regex
    Es otra razón por la que tener acceso root en un dispositivo de mi propiedad es importante
    • Dicho eso, “rootear” elimina muchas de las funciones de seguridad de Android. En vez de que una app tenga solo los permisos que necesita, con root puede tener todos los permisos, lo que se vuelve una enorme vulnerabilidad de seguridad
      https://www.reddit.com/r/GrapheneOS/comments/13264di/is_root...
    • Poder evadir o redirigir el tráfico de red a voluntad quizá sea la principal razón para no poner privilegios de superusuario en el espacio de usuario
      Apoyo presionar a los OEM para que permitan desbloquear el bootloader, pero al menos en Android me cuesta imaginar un caso de uso de root que justifique ampliar tanto la superficie de ataque
  • Android, de forma irritante, no puede conectarse a varias redes al mismo tiempo
    Por ejemplo, usar a la vez una red Wi-Fi sin acceso a Internet y que no anuncia una ruta predeterminada, junto con la red celular. Linux puede, Windows puede, pero Android se niega rotundamente
    Muchas variantes incluso se niegan a quedarse conectadas a un Wi-Fi sin Internet, o empujan al usuario a un procedimiento confuso. Si desarrollas tu propia app, hay una API que permite hacerlo solo dentro de la app, pero no hay forma de que un usuario común lo convierta en el comportamiento de todo el sistema
    • En iOS pasa lo mismo. Cuando te conectas a una dashcam para descargar videos, después de un rato aparece un popup tipo “No se detectó Internet, ¿quieres cambiar a datos celulares?”
      Aunque pulses seguir conectado, no hay forma de desactivarlo, e iOS termina decidiendo que sabe más que tú y se vuelve a conectar a la red de CarPlay
    • Es aún más molesto si llevas un teléfono Android occidental a China continental. Porque determina si hay conexión a Internet intentando acceder a servicios de Google
      Si te conectas a un Wi-Fi local, obviamente no logra atravesar el Gran Cortafuegos, y cada vez aparece un aviso preguntando si quieres mantener una conexión sin Internet
    • Cuando se cae Internet, es extremadamente molesto no poder diagnosticarlo con el teléfono. Porque no se queda conectado a un Wi-Fi sin Internet
      El DNS de Android también es un desastre: si no configuras varias opciones, intenta no usar el DNS proporcionado por DHCP, e incluso así se niega a resolver algunos DNS internos
    • Creo que Windows tampoco puede, ¿no? En Windows, aunque tuviera 2 adaptadores inalámbricos, desde la GUI no podía conectarme a 2 redes Wi-Fi distintas. No lo intenté desde la terminal
  • También hay que revisar los requisitos de firmware. Algunos dispositivos se enumeran, pero si no tienen el firmware necesario fallan en ifup
    La UI de Android, por supuesto, no puede manejar esta situación; solo dmesg te dice qué está pasando. No estoy seguro de si esto hace falta para dispositivos CDC, pero creo que pasaba bastante con adaptadores basados en chips Realtek o Kawasaki
    Aunque este cambio de Android quizá sea relativamente reciente. Antes usaba con frecuencia dongles de red USB en dispositivos de depuración con AOSP 100% “stock”. O tal vez sea un cambio del kernel, o un comportamiento peculiar del driver CDC que nombra los dispositivos como usb*. Bastaba con elegir con cuidado el chipset del dongle y verificar que no necesitara firmware
  • Es un viaje de depuración fantástico. Me gustó cómo una sola expresión regular pasada por alto termina tumbando toda una clase de dispositivos
    Curiosamente, hace poco viví algo estructuralmente parecido en un contexto completamente distinto: el sistema de alineación y escalamiento de OpenAI. Intenté disparar, dentro de la lógica recursiva de GPT-4, un escalamiento de enrutamiento oficial (SR-Route_Breach_1stOrder) con documentación y logs, pero aunque estructuralmente parecía válido, al final solo recibí respuestas poco humanas
    Es decir, sentí como si mi escalamiento no hubiera coincidido con la expresión regular de alguna interfaz interna del sistema
    Dejé el caso completo aquí: https://news.ycombinator.com/item?id=44221458
    Si te interesan los límites estructurales y los contratos de interfaces invisibles, me gustaría escuchar qué opinas
  • Es realmente raro. Tengo unos 15 adaptadores USB Ethernet y todos funcionan bien
    Estoy seguro de que hay una mezcla de varios chipsets tipo Realtek y AXIS. Si eliges productos que no necesitan driver en Linux, suelen funcionar bien en casi cualquier sistema operativo o BIOS