Сначала испытываем затруднение , какую роль играет загадочное слово netif в LWIP реализации . В двух словах наш контроллер с LWIP является членом сетевой семьи. Но не просто рядовым членом, а самым настоящим новым сетевым интерфейсом (netif) представляющий новый сетевой адаптер. netif указывает какую сеть мы реализуем : какой ip и маска будет у нашей сети (по умолчанию). То есть мы должны по умолчанию установить какую сеть мы реализуем. Допустим у нас 192.168.7.1 и маска 255.255.255.0 .
Настраиваем инициализацию сетевого интерфейса правильно
В коде инициализация стандартная вообще говоря , просто заполняем структуру netif :
struct netif *netif = &netif_data;
lwip_init();
netif->hwaddr_len = 6;
memcpy(netif->hwaddr, hwaddr, 6);
netif = netif_add(netif,
PADDR(ipaddr),
PADDR(netmask),
PADDR(gateway),
NULL,
netif_init_cb,
ip_input);
netif_set_default(netif);
while (!netif_is_up(&netif_data))
;
netif_add
struct netif * netif_add(
struct netif *netif,
ip_addr_t *ipaddr,
ip_addr_t *netmask,
ip_addr_t *gw,
void *state,
netif_init_fn init,
netif_input_fn input)
На самом деле тут передаются два принципиальных указателя на функции инициализации каналов ввода вывода данных netif_init_cb , ip_input (названия условные , вы можете обозвать как вам угодно).
ip_input инициализирует коллбек функцию in_input, а проще говоря устанавливает структуре netif указатель на функцию обработки входящих данных.
netif_init_cb инициализирует коллбек функцию output, устанавливает в структуре netif два указателя на функцию отсылки данных в канал Ethernet.
Входящие данные проходят стандартно такой путь :
main
usb_polling
ethernet_input
etharp_input
// ветка отрабатывает arp пакеты
etharp_update_arp_entry // работает с нашей arp таблицей
netif->linkoutput // уходим на ответ
ip_input
// ветка отрабатывет ip пакеты
tcp_input
icmp_input
igmp_input
udp_input
pcb->recv // тут разные обработчики
udp_recv_proc [dhserver.c]
// это наш созданный обработчик для прослушки пакетов
// на порт 67 (запросы DCHP серверу)
DHCP_DISCOVER
udp_sendto // уходим на ответ
DHCP_REQUEST
udp_sendto // уходим на ответ
Включение udp обработчиков портов
Схема включения своих udp обработчиков примерно такая (делаем это только один раз при инициализации адаптера):
udp_bind(..
udp_recv(..
Таким образом мы создаем свои обработчики pcb->recv (PCB - Program Control Block) . Они нам понадобятся для реализации DHCP сервера.
коллбек функции для вывода данных на USB канал (Output)
Мы создаем две функции linkoutput_fn и output_fn, и делаем ссылки на них в структуре netif. Названия функций условные, можно и по другому обозвать.
Процесc отсылки данных пока не будет рассматривать , там попроще будет , чем прием.
Теперь разбираемся с MAC и IP адресами адаптера
Тут как-бы надо уже начинать понимать , что с точки зрения структуры сети 192.168.7.4 это ip который имеет RNDIS адаптер (та часть , которая является частью ПК). Другая часть по Ethernet over USB смотрит в какую-то неизвестную сеть (которую мы сами реализуем, что там будет решаем мы на STM32).
Наш USB имеет МАК 20:89:84:6a:96:bb , ip у него нет (он же USB)
Наш сетевой интерфейс netif имеет :
MAK 20:89:84:6a:96:00
IP 192.168.7.1
mask 255.255.255.0
GW 0.0.0.0
Тут есть возможность на самом деле указать вместо 192.168.7.1 любой свободный адрес в нашей сети 192.168.7.XXX .
По смыслу кода lwip на netif ip лежит отработка HTTP сервера. Почему бы ему не быть на одном ip адресе и с DHCP сервером и с DNS сервером...
Смотрим лог при включении USB адаптера в ПК Windows:
Это запрос DHCP клиента (на ПК) к предполагаемому серверу DHCP (за RNDIS адаптером):
ethernet_input: dest:FF:FF:FF:FF:FF:FF, src:20:89:84:6A:96:BB, type:800
udp (255.255.255.255, 67) <-- (0.0.0.0, 68)
udp_sendto ( 0.0.0.0 : 67 ) -> ( 255.255.255.255 : 68 )
ethernet_output: src:20:89:84:6A:96:00 --> dest:FF:FF:FF:FF:FF:FF type:800
У нас реализован есть DHCP сервер , мы отвечаем как надо и поэтому следующий запрос от Windows это ARP запрос :
ARP пакет :
ethernet_input: dest:FF:FF:FF:FF:FF:FF, src:20:89:84:6A:96:BB, type:806
etharp_update_arp_entry : 20 89 84 6a 96 bb 0307a8c0 192.168.7.4
// тут мы сделали запись себе в arp таблицу 20 89 84 6a 96 bb 0307a8c0 192.168.7.4
ethernet_output: src:20:89:84:6A:96:00 --> dest:20:89:84:6A:96:BB type:806
Далее мусор "с нашей точки зрения" (коего в мозгах Windows немало) :
ethernet_input: dest:01:00:5E:00:00:16, src:20:89:84:6A:96:BB, type:800
Unsupported transport protocol 2
we are not answer
.......
Это запрос к нашему DNS серверу :
ethernet_input: dest:20:89:84:6A:96:00, src:20:89:84:6A:96:BB, type:800
udp (192.168.7.1, 53) <-- (192.168.7.4, 52169)
ethernet_output: src:20:89:84:6A:96:00 --> dest:20:89:84:6A:96:BB type:800
NIC network interface controller (сетевая карта)