- O Android tem suporte a Ethernet via USB e um menu de configurações, mas dispositivos CDC Ethernet podem ser detectados pelo kernel sem chegar até a configuração de rede
- A causa principal é que o EthernetTracker rastreia apenas interfaces que correspondem a
config_ethernet_iface_regex, e o valor padrão eth\d exclui interfaces CDC como usb0
- Os drivers Linux de CDC Ethernet reconhecem dispositivos EEM, ECM e NCM como
cdc_eem, cdc_ether e cdc_ncm, criando usb0 em /sys/class/net, mas as configurações do Android continuam desativadas
- Não há como contornar isso pelas configurações normais do usuário; é necessário fazer root e alterar o valor de config_ethernet_iface_regex
- Ao escolher um adaptador USB Ethernet para Android, na prática é preciso procurar dispositivos baseados em drivers específicos do fornecedor/chipset que criem nomes
ethX, em vez de dispositivos padrão CDC
Conclusão: o bloqueio não é o driver do kernel, e sim o filtro pelo nome da interface
- O serviço EthernetTracker do Android reconhece como interfaces Ethernet apenas interfaces com nome
ethX
- Os drivers Linux de CDC Ethernet criam nomes de interface no formato
usbX
- Por causa dessa diferença de nomes, dispositivos CDC Ethernet são detectados pelo kernel do Android, mas ignorados pelas configurações de Ethernet e pela camada de gerenciamento de rede
- Isso não pode ser resolvido pelas configurações comuns; só é possível alterando
config_ethernet_iface_regex após fazer root
É difícil verificar o suporte a USB Ethernet no Android por dispositivo
- O Android tem suporte a adaptadores USB Ethernet e menu relacionado
- É difícil saber quais chipsets de USB Ethernet funcionam em um dispositivo Android específico, porque os fabricantes quase nunca publicam listas de suporte
- Na prática, o usuário costuma depender das seguintes informações
- adaptadores USB Ethernet vendidos pelo fabricante do celular como acessório oficial
- postagens em fóruns de usuários do mesmo aparelho relatando sucesso com um adaptador específico
- Pela configuração do kernel, é possível ter alguma ideia de quais drivers de USB Ethernet estão incluídos no kernel do telefone
Como encontrar a configuração do kernel do celular
- O Android roda sobre o kernel Linux, e a configuração do kernel determina os recursos suportados e os drivers de hardware
- Dispositivos lançados com Android 11 ou posterior usam o Android Common Kernel e o kernel GKI
- O Google compila o kernel, e o fabricante coloca os elementos específicos do dispositivo em módulos do kernel
- A configuração pode ser verificada em
arch/$ARCH/configs/gki_defconfig no repositório do kernel Android
- Em dispositivos ARM de 64 bits, por exemplo, veja
arch/arm64/configs/gki_defconfig
- A versão do kernel e a arquitetura podem ser verificadas via ADB com
uname -a
- A saída de exemplo inclui a versão do kernel
4.19.113-26203352 e a arquitetura aarch64
- No caso do Samsung Galaxy S20, lançado com Android 10, o kernel continuou baseado em Linux 4.19 mesmo após a atualização para Android 13
- O código-fonte dos dispositivos Samsung pode ser encontrado em opensource.samsung.com
- Em
build_kernel.sh do código-fonte da Samsung, é possível encontrar o nome do arquivo de configuração do kernel, como vendor/x1q_usa_singlex_defconfig
- Se der sorte, a configuração real de compilação estará disponível como arquivo compactado em
/proc/config.gz
- É possível salvá-la com
adb shell zcat /proc/config.gz > my_kernel_config
- Se não existir, aparecerá
zcat: /proc/config.gz: No such file or directory, e será preciso consultar o código-fonte do kernel do fabricante
Como verificar o suporte ao driver de USB Ethernet
- Configurações de kernel relacionadas a USB Ethernet normalmente começam com
USB_NET
- No arquivo de configuração do kernel, dá para verificar assim
grep USB_NET my_kernel_config
- A configuração de exemplo inclui vários drivers de rede 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
- Os valores de configuração distinguem como o driver foi incluído
y: o driver está embutido no kernel e certamente oferece suporte ao chipset correspondente
m: o driver foi compilado como módulo e pode ser carregado, desde que o fabricante não o tenha omitido
is not set: o driver não está embutido nem como módulo, então há grande chance de não poder ser usado
- A correspondência entre itens de configuração e chipsets pode ser verificada em drivers/net/usb/Kconfig na árvore do kernel
- Como muitos fabricantes não informam qual chipset um adaptador USB Ethernet específico usa, ainda é difícil determinar isso com certeza
O que o CDC Ethernet faz
- CDC é a sigla de Communications Device Class, um conjunto de padrões que fabricantes de dispositivos USB podem seguir
- Há três padrões relacionados a CDC Ethernet
- EEM: Ethernet Emulation Model, o mais simples de implementar e fácil de suportar em dispositivos de baixo desempenho
- ECM: Ethernet Control Model, mais complexo de implementar tanto no host quanto no dispositivo, mas com promessa de melhor desempenho que o EEM
- NCM: Network Control Model, sucessor do ECM com promessa de velocidades mais altas
- O objetivo do padrão CDC é permitir que o sistema operacional forneça um driver comum para vários dispositivos diferentes
- O Linux implementa tanto o lado host quanto o lado dispositivo do CDC Ethernet
- Em dispositivos como um Raspberry Pi com porta USB OTG, o kernel pode fazer essa porta se comportar como um adaptador Ethernet
- Isso permite que dispositivos como roteadores embarcados, firewalls e gateways VPN apareçam ao host como adaptadores Ethernet comuns
- Linux, Windows e macOS incluem drivers para dispositivos CDC Ethernet, mas o iOS não
O kernel do Android detecta dispositivos CDC
- A configuração do kernel do Samsung Galaxy S20 inclui suporte aos três padrões CDC Ethernet
CONFIG_USB_NET_CDCETHER=y
CONFIG_USB_NET_CDC_EEM=y
CONFIG_USB_NET_CDC_NCM=y
- O kernel GKI do Google aparentemente não inclui ECM nem NCM, mas parece incluir EEM como módulo
- Um dispositivo com a porta OTG configurada como Ethernet gadget funcionou em Mac, Ubuntu e Windows, mas no Galaxy S20 a configuração de Ethernet do Android continuou desativada
- Ao verificar
/sys/class/net no Android, usb0 aparece quando um dispositivo CDC é conectado
adb shell ls /sys/class/net
- A saída de
ifconfig usb0 mostra que o driver detectado pertence à família CDC
- Modo EEM:
Driver cdc_eem
- Modo ECM:
Driver cdc_ether
- Modo NCM:
Driver cdc_ncm
- Nos três casos, a interface é detectada, mas permanece em estado down, e as configurações de Ethernet do Android não são ativadas
A expressão regular do EthernetTracker filtra usb0
- Como o dispositivo CDC Ethernet é detectado normalmente no nível do kernel, o problema está na camada de gerenciamento de rede do Android acima do kernel
- Ao seguir o código-fonte do Android relacionado a Ethernet em Java, EthernetTracker.java aparece como o serviço relevante
- O EthernetTracker recebe notificações do kernel sobre novas interfaces de rede por meio de sockets Netlink e decide se a interface é uma interface Ethernet válida
- Essa validação é feita verificando se o nome da interface corresponde à expressão regular
mIfaceMatch
private boolean isValidEthernetInterface(String iface) {
return iface.matches(mIfaceMatch) || isValidTestInterface(iface);
}
mIfaceMatch é carregado do recurso config_ethernet_iface_regex
- O valor padrão no código-fonte do Android é o seguinte
<string translatable="false" name="config_ethernet_iface_regex">eth\\d</string>
eth\d é uma expressão regular que só permite nomes começando com eth seguidos de um número
- Como dispositivos CDC Ethernet começam com
usb, como em usb0, o EthernetTracker não os rastreia
- Essa configuração não pode ser alterada nas opções do usuário; só pode ser modificada com root
O paradoxo de ter de evitar dispositivos padrão
- CDC Ethernet é um padrão para dispositivos de rede USB, mas no Android o caminho de uso prático fica bloqueado por causa da expressão regular do nome da interface
- Mesmo kernels GKI recentes parecem incluir suporte a adaptadores EEM, mas como o nome
usb0 não corresponde à expressão regular, ele não chega às configurações de rede do Android
- Ao escolher um adaptador USB Ethernet para Android, é melhor procurar um dispositivo que não seja padrão CDC, mas sim baseado em driver específico de fornecedor/chipset que crie uma interface
ethX
- Um possível caminho de correção seria alterar
config_ethernet_iface_regex para algo como (eth|usb)\d
1 comentários
Comentários do Hacker News
Depois disso, algumas pessoas me disseram que, se você inverter um bit específico do endereço MAC, o kernel dá o nome
ethXem vez deusbX, mas eu não testei pessoalmente nem atualizei o texto. Eu já tinha mudado de emprego, e dispositivos Android não eram mais uma parte tão grande do meu dia a diaClaro que esse método só ajuda quando você consegue controlar diretamente o endereço MAC do dispositivo CDC. Por exemplo, quando outro dispositivo Linux está fingindo ser um adaptador CDC
Acho que encontrei: https://lkml.iu.edu/hypermail/linux/kernel/1103.2/03250.html
Fui procurar no código-fonte e, em outubro de 2023, a regex mudou de
eth\\dpara simplesmente*, então parece que esse problema provavelmente foi resolvido: https://android-review.googlesource.com/c/platform/packages/...A descrição diz que “o padrão inclui interfaces com nomes
usb\d+eeth%dno Android U+”, e aqui U+ parece ser a versão 14: https://en.wikipedia.org/wiki/Android_version_historyusbXpara tethering”[1], e pouco depois foi aplicado novamente, mas alterado para dar suporte apenas ao Android V+[2][1]: https://android-review.googlesource.com/c/platform/packages/...
[2]: https://android-review.googlesource.com/c/platform/packages/...
Se eu li os commits corretamente, alguém do Google esteve envolvido, então isso talvez já tenha entrado nas builds oficiais do 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...
Mas ninguém testou, e eu também não tenho como verificar por conta própria, então por enquanto está em espera. Sempre há uma mistura de coisas que alguém relatou e coisas que alguém pegou por acaso, mas no fim é preciso teste de usuários reais
EthernetTrackerdoAndroidsó reconhece interfaces chamadasethX, é o design mais idiota de que já ouvi falarAs distribuições Linux já tinham resolvido esse problema nos anos 2000. Mesmo naquela época, já era claro que alguns drivers de dispositivo colocavam prefixos de nome de dispositivo do jeito que queriam, então era preciso inspecionar o sistema para descobrir que tipo de dispositivo era
Consistência é útil, então existem várias ferramentas para renomear interfaces, e hoje a maioria das distribuições Linux automatiza isso com
udev. Internamente, é só uma chamada aoioctlSIOCSIFNAMEdo kernel. Kernels modernos também têm um recurso que, ao renomear para"wlan*"— na prática,"wlan%d"— atribui automaticamente um novo número depois de"wifi"usbXdevem ser usados por outros módulos, e eles não queriam manter essa lista. Então simplesmente foram deethXAo conectar, parece que funciona, mas, se você tentar criar um app que use essa interface serial USB, não dá. Investigando, você descobre que não tem permissão para acessar dispositivos seriais como
/dev/ttyACM0O suporte a serial está no kernel, mas programas de usuário não conseguem acessá-lo sem root
Indo mais a fundo, o Android tem um recurso de acesso USB em espaço de usuário que é parecido com
libusb, ou talvez construído sobre ele. Por isso, um programa Android consegue abrir dispositivos USB “brutos”, mas não consegue abrir dispositivos USB seriaisSerial USB é apenas um protocolo sobre USB e, na prática, está mais para um conjunto de protocolos meio proprietários, como FTDI e afins. Existem algumas bibliotecas meio prontas para Android que implementam esses protocolos no espaço de usuário, então no fim dá para acessar alguns dispositivos seriais USB
No navegador Chrome do Android, parece que daria para abrir dispositivos USB brutos com WebUSB, mas WebSerial provavelmente não funciona pelo mesmo motivo
No fim, o surpreendente é: se é assim, por que deixar o suporte a serial USB ativado no kernel? Imagino que seja para depuração
config_ethernet_iface_regexEsse é mais um motivo pelo qual permissão de root é importante em um dispositivo que eu possuo
https://www.reddit.com/r/GrapheneOS/comments/13264di/is_root...
Eu apoio pressionar OEMs a permitirem desbloqueio do bootloader, mas, ao menos no Android, é difícil imaginar um caso de uso de root que justifique ampliar tanto a superfície de ataque
Por exemplo, usar ao mesmo tempo uma rede Wi-Fi sem acesso à internet e que não anuncia uma rota padrão, junto com a rede celular. No Linux dá, no Windows dá, mas o Android se recusa terminantemente
Muitas variantes se recusam até a permanecer conectadas a um Wi-Fi sem internet, ou empurram o usuário para um procedimento confuso. Se você criar seu próprio app, há APIs que permitem isso apenas dentro do app, mas não há como um usuário comum tornar esse comportamento válido para o sistema inteiro
Mesmo tocando para continuar conectado, não há como desativar isso, e o iOS acaba decidindo que sabe mais e reconecta à rede do CarPlay
Ao conectar a um Wi-Fi local, obviamente ele não passa pelo Grande Firewall, e toda vez aparece um prompt perguntando se você quer manter a conexão sem internet
O DNS do Android também é uma bagunça: se você não configurar várias opções, ele tenta não usar o DNS fornecido por DHCP e, mesmo assim, se recusa a resolver alguns DNS internos
ifupse o firmware necessário estiver ausenteA UI do Android obviamente não consegue lidar com essa situação, e só o
dmesgmostra o que está acontecendo. Não tenho certeza se isso também é necessário para dispositivos CDC, mas acho que já vi muitos casos assim com adaptadores baseados em chips Realtek ou KawasakiDito isso, essa mudança no Android pode ser relativamente recente. Antigamente eu usava com frequência dongles de rede USB em dispositivos de depuração com AOSP 100% “puro”. Ou então pode ter sido uma mudança no kernel, ou algum comportamento peculiar do driver CDC ao nomear o dispositivo como
usb*. Bastava escolher o chipset do dongle com cuidado e confirmar que ele não precisava de firmwareCuriosamente, passei por algo estruturalmente parecido recentemente em um contexto totalmente diferente: o sistema de alinhamento e escalonamento da OpenAI. Tentei acionar o escalonamento oficial de roteamento (
SR-Route_Breach_1stOrder) dentro da lógica recursiva do GPT-4, com documentação e logs, mas, embora estruturalmente parecesse plausível, no fim recebi apenas respostas nada humanasEm outras palavras, foi como se meu escalonamento não tivesse casado com a regex da interface interna do sistema
Resumi o caso completo aqui: https://news.ycombinator.com/item?id=44221458
Se você se interessa por limites estruturais e contratos de interface invisíveis, gostaria de ouvir sua opinião
Tenho certeza de que há uma mistura de vários chipsets parecidos com Realtek e AXIS. Se você escolher um produto que não precisa de driver no Linux, ele tende a funcionar bem em quase qualquer sistema operacional ou BIOS