Зачем нам может понадобится сервер DHCP ? Например если наше устройство само является сетевым адаптером, то есть предоставляет доступ в какую-то сеть (а там DHCP сервера, DNS сервера, HTTP сервера и много еще каких серверов).
Что есть сеть в нашем понимании? Например устройство, через которое мы получаем доступ к новым ресурсам. Каким ресурсам - мы еще не знаем. И это нам предстоит выяснить стандартными протоколами DHCP , DNS ,...
Компьютер при включение обнаруживает новое оборудование , по типу устройства определяет ,что это сетевой адаптер. Сетевой адаптер отвечает по USB какой у него МАК адрес (это происходит еще до обмена по сети).
Первым делом потом ОС ПК делает запрос на порт 67 к предполагаемому серверу DHCP (с порта 68 DHCP клиент) . Потому , что ОС должна решить вопрос с выделением IP новому сетевому устройству . Но поскольку это устройство сетевой адаптер, то ОС предполагает , что за ним есть сеть , а там скорее всего может быть DHCP сервер, который по мнению ОС и выделит нашему адаптеру IP.
Нас самом деле сетевой адаптер должен ответить по протоколу DHCP
какой у него DNS сервер, DHCP сервер и IP шлюз.
То есть решается вопрос , кто будет выделять IP адаптеру.
И вот потом компьютер посылает в сетевой адаптер (в какую-то сеть за ним) пакет - кому принадлежит такой МАК адрес ответьте...
Поскольку у нас есть лог контроллера , то мы видим , что (под Windows 10) ОС посылает первый пакет широковещательный (ff:ff:ff:ff) на порт 67. То есть компьютер сначала проверяет есть ли в сети адаптера свой DHCP сервер.
Ищем реализацию DHCP сервера в исходниках LWIP
Поковыряли код lwip на предмет реализации сервера DHCP , но ничего не нашли.
Не путаем : dhcp_start - это КЛИЕНТ (на порт 68), то есть он сам запрашивает у сервера dhcp себе ip . А нам надо самим быть сервером DHCP.
Не путаем : LWIP_AUTOIP - это похоже на отработку конфликта со своим адресом
/* We have to check if a host already has configured our random created link local address and continuously check if there is a host with this IP-address so we can detect collisions */
Сервер DHCP надо встраивать в код самим
И для этого в LWIP есть продуманная технология : DHCP протокол это прием и ответ udb пакетами. Надо просто отрабатывать поступление запросов на порт 67 (dhcp сервер) с порта 68 (dhcp клиент)
Чтобы включить отработку запросов по udp делаем примерно так (udp_new , udp_bind , udp_recv) , один раз при инициализации (из примера Сергея Фетисова):
struct udp_pcb *pcb = udp_new();
err = udp_bind(pcb, IP_ADDR_ANY, c->port);
udp_recv(pcb, udp_recv_proc, NULL);
// назначает коллбек функцию udp_recv_proc
// для обработки пришедшего пакета на наш порт
pcb - Program Control Block .
Приходит пакет на 67 порт , мы его принимаем и отрабатываем примерно по такому пути вызываются функции (стек функций) :
main()
usb_polling()
ethernet_input()
ip4_input()
udp_input()
for_us = 1; // на 67 порту
pcb->recv //переход на коллбек = udp_recv_proc []
DHCP_DISCOVER // приходит первым к нам
udp_sendto()
.... // ловим следующих пакет ,
DHCP_REQUEST
udp_sendto()
Нюанс такой : (проверено для 2.1.2) оставляем включенным код LWIP_DHCP , т.е. #define LWIP_DHCP 1 надо оставлять.
Вот такой первый пакет приходит , отследить через WireShark его не успеваем , так как это именно начало обмена сразу после старта сетевого драйвера, а WireShark подключается только к уже инициализированному. Поэтому изучаем лог через SWO контроллера STM32:
ethernet_input: dest:FF:FF:FF:FF:FF:FF, src:20:89:84:6A:96:02, type:800
(ip dest 255.255.255.255 <- src 0.0.0.0)
for_us =1
DHCP_REQUEST
client ip : 0.0.0.0
your ip : 192.168.7.4 // здесь мы присваиваем ip сетевому адаптеру в Windows
server ip : 0.0.0.0
gw ip : 0.0.0.0
mac (client hardware address) :20:89:84:6a:96:02
---- dp_options ----
domain : stm
dns : 192.168.7.1
addr : 192.168.7.4
subnet : 255.255.255.0
mac : ff:ff:ff:00:00:00
udp_sendto ( 0.0.0.0 : 67 ) -> ( 255.255.255.255 : 68 )
USB -> PC 0064 [x0040] : 01 00 00 00 5a 02 00 00 24 00 00 00 2e 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ETHERNET: 00 00 00 00 00 00 00 00 ff ff ff ff ff ff 20 89 84 6a 96 03 08 00 45 00 02 20 00 02
USB -> PC 0064 [x0040] : 00 00 ff 11 f2 20 c0 a8 07 02 ff ff ff ff 00 43 00 44 02 0c 37 45 02 01 06 00 ff 2b d6 bd 00 00 00 00 00 00 00 00 c0 a8 07 04 00 00 00 00 00 00 00 00 20 89 84 6a 96 02 00 00 00 00 00 00 00 00
USB -> PC 0064 [x0040] : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
USB -> PC 0064 [x0040] : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
USB -> PC 0064 [x0040] : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
USB -> PC 0064 [x0040] : 00 00 63 82 53 63 35 01 05 36 04 c0 a8 07 01 33 04 00 01 51 80 01 04 ff ff ff 00 03 04 c0 a8 07 01 0f 03 73 74 6d 06 04 c0 a8 07 01 ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
USB -> PC 0064 [x0040] : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
USB -> PC 0064 [x0040] : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
USB -> PC 0064 [x0040] : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
USB -> PC 0026 [x001a] : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
USB <- PC 64[x40] : 01 00 00 00 56 00 00 00 24 00 00 00 2a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ff ff ff ff ff ff 20 89 84 6a 96 02 08 06 00 01 08 00 06 04
USB <- PC 22[x16] : 00 01 20 89 84 6a 96 02 c0 a8 07 04 00 00 00 00 00 00 c0 a8 07 01
Вот тут становится ясно почему такие параметры у сетевого адаптера в Windows . Наш RNDIS адаптер уже имеет нужные нам адреса :

Второй пакет Windows шлет уже с типом ARP , чтобы выяснить какой mac адрес у dhcp сервера (192.168.7.1)
ethernet_input: dest:FF:FF:FF:FF:FF:FF, src:20:89:84:6A:96:02, type:806
autoip_arp_reply()
etharp_input: hw type=256, hwlen=6, proto=8, protolen=4 opcode=256
arp dir:256 ( src : [ 20:89:84:6A:96:02 ] 192.168.7.4 -> dest : [ 00:00:00:00:00:00 ] 192.168.7.1 )
Далее ARP