DHCP сервер

Зачем нам может понадобится сервер 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 адаптер уже имеет нужные нам адреса :

фотка 1

Второй пакет 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