.png)
Estou trabalhando em um projeto agora onde temos um sistema Linux embarcado executando algumas funcionalidades de controle de sensor/motor, e estamos criando um aplicativo GUI para permitir que o usuário controle o sistema. No futuro, poderemos executar ambos os aplicativos em um único sistema, mas, por enquanto, queremos poder instalar isso como uma atualização nas máquinas existentes, e as placas controladoras existentes não têm a capacidade de executar a GUI como ele foi projetado, então será executado em um SBC separado (atualmente estamos prototipando com umODroid C4executando o Android 9)
Elaboramos a API de comunicação entre os dois sistemas e tenho feito testes iniciais executando uma conexão Ethernet direta entre os dois sistemas com endereços IP estáticos, porém devido aos requisitos de implantação e limitações do Android preciso descobrir um diferente método de conexão para implantação real do produto. Precisamos que o cliente seja capaz de se conectar à Internet no sistema GUI via WiFi ou Ethernet, portanto, a porta Ethernet integrada do ODroid não pode ser usada para esse propósito e, além disso, o kernel do Android tem algum comportamento interno que permite apenas que uma única conexão de rede esteja ativa a qualquer momento.
A exceção às regras de priorização de rede do Android são as interfaces de rede USB. Tanto o sistema controlador Linux quanto o próprio dispositivo Android têm a capacidade de aparecer como uma interface de rede para um host remoto - no sistema controlador temos uma porta USB para gadgets disponível, e eu habilitei o g_ether
módulo do kernel em nossa imagem do sistema, e no Sistema GUI, temos uma porta USB OTG e posso ativar o tethering USB nas configurações do sistema Android.
Consegui obter comunicação entre qualquer um desses sistemas e meu sistema de desenvolvimento Windows usando suas respectivas interfaces, mas até agora não descobri como fazer com que uma das soluções se comunique com a outra.
Sistema Linux como interface remota (gadget USB com driver g_ether)
- Carregar o módulo do kernel g_ether no sistema Linux cria uma
usb0
interface:
# modprobe g_ether
# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.42.128.107 netmask 255.255.255.0 broadcast 10.42.128.255
inet6 fe80::206:cff:fe01:1027 prefixlen 64 scopeid 0x20<link>
ether 00:06:0c:01:10:27 txqueuelen 1000 (Ethernet)
RX packets 500 bytes 54062 (52.7 KiB)
RX errors 0 dropped 46 overruns 0 frame 0
TX packets 0 bytes 24423 (23.8 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 0 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
usb0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 fe80::24b:5bfc:8a9e:b148 prefixlen 64 scopeid 0x20<link>
ether 9a:8c:fa:85:ec:a1 txqueuelen 1000 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 1 bytes 96 (96.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
- Conectar um cabo USB da porta do gadget no sistema Linux a uma porta host no sistema Android cria imediatamente uma
usb0
interface no Android e gera um endereço IP para ausb0
interface no Linux:
Android:
odroidc4:/ # ifconfig usb0
usb0 Link encap:Ethernet HWaddr fa:4c:95:c0:8d:18 Driver cdc_subset
BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 TX bytes:0
Linux:
# ifconfig usb0
usb0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 169.254.119.94 netmask 255.255.0.0 broadcast 169.254.255.255
inet6 fe80::24b:5bfc:8a9e:b148 prefixlen 64 scopeid 0x20<link>
ether 9a:8c:fa:85:ec:a1 txqueuelen 1000 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 1 bytes 96 (96.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
- Abrir a interface no sistema Android não atribui um endereço IP, então tenho que atribuir um manualmente, usando o espaço 169.254/16 que o sistema Linux autoatribui
odroidc4:/ # ifconfig usb0 up
odroidc4:/ # ifconfig usb0
usb0 Link encap:Ethernet HWaddr fa:4c:95:c0:8d:18 Driver cdc_subset
inet6 addr: fe80::f84c:95ff:fec0:8d18/64 Scope: Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:117 errors:4 dropped:75 overruns:0 frame:4
TX packets:27 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:5080 TX bytes:4897
odroidc4:/ # ip addr add 169.254.1.1/16 broadcast 169.254.255.255 dev usb0
odroidc4:/ # ifconfig usb0
usb0 Link encap:Ethernet HWaddr fa:4c:95:c0:8d:18 Driver cdc_subset
inet addr:169.254.1.1 Bcast:169.254.255.255 Mask:255.255.0.0
inet6 addr: fe80::f84c:95ff:fec0:8d18/64 Scope: Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:117 errors:4 dropped:75 overruns:0 frame:4
TX packets:44 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:5080 TX bytes:8528
Tenho dois problemas neste momento: o primeiro é que o ping de um dispositivo do outro resulta em nenhuma resposta. Observar a contagem de pacotes no lado do Android faz parecer que ele está recebendo pings do lado do Linux, mas não está respondendo, o que pode ser causado pelo segundo problema, que é que as tabelas de roteamento não parecem funcionar como esperado no lado do Android. Dado que preciso que isso funcione enquanto também houver uma conexão ativa com a Internet no sistema Android, tenho a Ethernet conectada ao mesmo tempo, e é isso que vejo ao observar o roteamento:
odroidc4:/ # ip route list
169.254.0.0/16 dev usb0 proto kernel scope link src 169.254.1.1
10.42.128.0/24 dev eth0 proto kernel scope link src 10.42.128.166
odroidc4:/ # ip route get 169.254.119.94
169.254.119.94 via 10.42.128.2 dev eth0 table eth0 src 10.42.128.166 uid 0
cache
odroidc4:/ # ip route show table 0
default via 10.42.128.2 dev eth0 table eth0 proto static
...
Sistema Android como interface remota (tethering USB com porta OTG)
Este cenário parece me aproximar um pouco mais, pois consigo fazer a comunicação unilateral funcionar.
- Depois de adicionar os drivers necessários na minha imagem Linux, conectar um cabo da porta Android OTG a uma porta host Linux mostra o sistema reconhecendo o dispositivo USB em
dmesg
:
[ 235.710937] usb 1-2.3: new full-speed USB device number 7 using at91_ohci
[ 235.862304] rndis_host 1-2.3:1.0 usb0: register 'rndis_host' at usb-at91-2.3, RNDIS device, 32:1d:e8:fc:dd:8
- Uma
usb0
interface é imediatamente criada e recebe um endereço IP no lado do Linux:
# ifconfig usb0
usb0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 169.254.249.80 netmask 255.255.0.0 broadcast 169.254.255.255
inet6 fe80::e341:f9b1:b676:99b7 prefixlen 64 scopeid 0x20<link>
ether 32:1d:e8:fc:dd:80 txqueuelen 1000 (Ethernet)
RX packets 69 bytes 13572 (13.2 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 73 bytes 18251 (17.8 KiB)
TX errors 8 dropped 0 overruns 0 carrier 0 collisions 0
- No Android, com o tethering USB ativado nas configurações, a interface usb0 aparece, mas começa inativa. Trazê-lo à tona não fornece um endereço IP, então atribuí um manualmente, mas como no primeiro cenário, a tabela de roteamento não parece funcionar conforme o esperado:
odroidc4:/ # ifconfig usb0
usb0 Link encap:Ethernet HWaddr de:75:5c:41:2a:e6
BROADCAST MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 TX bytes:0
odroidc4:/ # ifconfig usb0 up
odroidc4:/ # ifconfig usb0
usb0 Link encap:Ethernet HWaddr de:75:5c:41:2a:e6
inet6 addr: fe80::dc75:5cff:fe41:2ae6/64 Scope: Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:10 errors:0 dropped:0 overruns:0 frame:0
TX packets:12 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:1090 TX bytes:2751
odroidc4:/ # ip addr add 169.254.1.1/16 broadcast 169.254.255.255 dev usb0
odroidc4:/ # ip route
10.42.128.0/24 dev eth0 proto kernel scope link src 10.42.128.166
169.254.0.0/16 dev usb0 proto kernel scope link src 169.254.1.1
odroidc4:/ # ip route get 169.254.249.80
169.254.249.80 via 10.42.128.2 dev eth0 table eth0 src 10.42.128.166 uid 0
cache
- No entanto, neste cenário, posso obter uma comunicação bem-sucedida originada no Android especificando manualmente a interface:
odroidc4:/ # ping -c 5 -I usb0 169.254.249.80
PING 169.254.249.80 (169.254.249.80) from 169.254.1.1 usb0: 56(84) bytes of data.
64 bytes from 169.254.249.80: icmp_seq=1 ttl=64 time=1.56 ms
64 bytes from 169.254.249.80: icmp_seq=2 ttl=64 time=1.89 ms
64 bytes from 169.254.249.80: icmp_seq=3 ttl=64 time=1.71 ms
64 bytes from 169.254.249.80: icmp_seq=4 ttl=64 time=1.75 ms
64 bytes from 169.254.249.80: icmp_seq=5 ttl=64 time=1.85 ms
--- 169.254.249.80 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4006ms
2|odroidc4:/ # ping6 -c5 ff02::1%usb0
PING ff02::1%usb0(ff02::1) 56 data bytes
64 bytes from fe80::dc75:5cff:fe41:2ae6: icmp_seq=1 ttl=64 time=0.202 ms
64 bytes from fe80::e341:f9b1:b676:99b7: icmp_seq=1 ttl=64 time=1.91 ms (DUP!)
64 bytes from fe80::dc75:5cff:fe41:2ae6: icmp_seq=2 ttl=64 time=0.196 ms
64 bytes from fe80::e341:f9b1:b676:99b7: icmp_seq=2 ttl=64 time=1.80 ms (DUP!)
64 bytes from fe80::dc75:5cff:fe41:2ae6: icmp_seq=3 ttl=64 time=0.199 ms
64 bytes from fe80::e341:f9b1:b676:99b7: icmp_seq=3 ttl=64 time=1.37 ms (DUP!)
64 bytes from fe80::dc75:5cff:fe41:2ae6: icmp_seq=4 ttl=64 time=0.199 ms
64 bytes from fe80::e341:f9b1:b676:99b7: icmp_seq=4 ttl=64 time=1.85 ms (DUP!)
64 bytes from fe80::dc75:5cff:fe41:2ae6: icmp_seq=5 ttl=64 time=0.205 ms
--- ff02::1%usb0 ping statistics ---
5 packets transmitted, 5 received, +4 duplicates, 0% packet loss, time 4004ms
rtt min/avg/max/mdev = 0.196/0.883/1.914/0.776 ms
- Ainda não consigo fazer com que nenhum tráfego originado do lado do Linux funcione, provavelmente por causa do problema de roteamento no Android, impedindo que o tráfego de retorno seja roteado corretamente:
# ping -c 5 -I usb0 169.254.1.1
PING 169.254.1.1 (169.254.1.1) from 169.254.249.80 usb0: 56(84) bytes of data.
--- 169.254.1.1 ping statistics ---
5 packets transmitted, 0 received, 100% packet loss, time 4295ms
# ping6 -c 5 ff02::1%usb0
PING ff02::1%usb0(ff02::1) 56 data bytes
64 bytes from fe80::e341:f9b1:b676:99b7: icmp_seq=1 ttl=64 time=0.522 ms
64 bytes from fe80::e341:f9b1:b676:99b7: icmp_seq=2 ttl=64 time=0.302 ms
64 bytes from fe80::e341:f9b1:b676:99b7: icmp_seq=3 ttl=64 time=0.376 ms
64 bytes from fe80::e341:f9b1:b676:99b7: icmp_seq=4 ttl=64 time=0.383 ms
64 bytes from fe80::e341:f9b1:b676:99b7: icmp_seq=5 ttl=64 time=0.385 ms
--- ff02::1%usb0 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4009ms
rtt min/avg/max/mdev = 0.302/0.393/0.522/0.074 ms
Em ambos os cenários, parece que a raiz do problema é que a tabela de roteamento na extremidade do Android não roteou corretamente o tráfego através da interface USB, e a extremidade do Android não atribui automaticamente um endereço IP enquanto a extremidade do Linux o faz. Com a interface do gadget Linux/host Android, posso entender um pouco esses problemas, mas com o tethering da porta Android OTG/host Linux, espero que ele seja roteado corretamente, já que o sistema Android está no controle da conexão tethering.
Responder1
Olá @rdowell,
Para corrigir esse problema, a tabela de rotas principal precisa ser adicionada ao seu dispositivo Android:
ip rule add from all lookup main pref 1