скрытое меню

Инициализируем сетевой интерфейс netif

Сначала испытываем затруднение , какую роль играет загадочное слово 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).

фотка 1

Наш 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 (сетевая карта)