@@ -227,12 +227,67 @@ int fill_options(void *dest,
227227 return ptr - (uint8_t * )dest ;
228228}
229229
230+
231+ /*
232+ * RFC 2131 Section 4.1 compliant destination address selection
233+ */
234+ static ip_addr_t get_dhcp_destination (struct netif * netif , const DHCP_TYPE * dhcp ,
235+ const ip4_addr_t * yiaddr , bool is_nak )
236+ {
237+ bool giaddr_zero = ip4_addr_isany_val (* ((ip4_addr_t * )dhcp -> dp_giaddr ));
238+ bool ciaddr_zero = ip4_addr_isany_val (* ((ip4_addr_t * )dhcp -> dp_ciaddr ));
239+ bool broadcast_flag = (dhcp -> dp_flags & htons (0x8000 )) != 0 ;
240+ ip_addr_t dest_addr ;
241+
242+ if (!giaddr_zero ) {
243+ // If giaddr is not zero, send to giaddr (relay agent)
244+ ip_addr_set_ip4_u32 (& dest_addr , get_ip (dhcp -> dp_giaddr ).addr );
245+ return dest_addr ;
246+ }
247+
248+ if (is_nak ) {
249+ // RFC 2131: "In all cases, when 'giaddr' is zero,
250+ // the server broadcasts any DHCPNAK messages to 0xffffffff"
251+ goto dest_broadcast ;
252+ }
253+
254+ if (!ciaddr_zero ) {
255+ // RFC 2131: "If the 'giaddr' field is zero and the 'ciaddr' field is nonzero,
256+ // then the server unicasts DHCPOFFER and DHCPACK messages to the address in 'ciaddr'"
257+ ip_addr_set_ip4_u32 (& dest_addr , get_ip (dhcp -> dp_ciaddr ).addr );
258+ return dest_addr ;
259+ }
260+
261+ if (broadcast_flag ) {
262+ // RFC 2131: "If 'giaddr' is zero and 'ciaddr' is zero, and the broadcast bit is set,
263+ // then the server broadcasts DHCPOFFER and DHCPACK messages to 0xffffffff"
264+ goto dest_broadcast ;
265+ }
266+
267+ // RFC 2131: "If the broadcast bit is not set and 'giaddr' is zero and 'ciaddr' is zero,
268+ // then the server unicasts DHCPOFFER and DHCPACK messages to the client's hardware
269+ // address and 'yiaddr' address"
270+ if (yiaddr && !ip4_addr_isany (yiaddr )) {
271+ ip_addr_set_ip4_u32 (& dest_addr , yiaddr -> addr );
272+ // TODO: This requires ARP table manipulation to associate yiaddr with client MAC
273+ // For now, fall back to broadcast as this is complex to implement correctly
274+ goto dest_broadcast ;
275+ }
276+
277+ dest_broadcast :
278+ ip_addr_set_ip4_u32 (& dest_addr ,
279+ ip4_addr_get_u32 (netif_ip4_addr (netif )) | ~ip4_addr_get_u32 (netif_ip4_netmask (netif )));
280+ return dest_addr ;
281+
282+ }
283+
230284static void udp_recv_proc (void * arg , struct udp_pcb * upcb , struct pbuf * p , const ip_addr_t * addr , u16_t port )
231285{
232286 uint8_t * ptr ;
233287 dhcp_entry_t * entry ;
234288 struct pbuf * pp ;
235289 struct netif * netif = netif_get_by_index (p -> if_idx );
290+ ip_addr_t dest_addr ;
236291
237292 (void )arg ;
238293 (void )addr ;
@@ -254,7 +309,6 @@ static void udp_recv_proc(void *arg, struct udp_pcb *upcb, struct pbuf *p, const
254309 entry = entry_by_mac (dhcp_data .dp_chaddr );
255310 if (entry == NULL ) entry = vacant_address ();
256311 if (entry == NULL ) break ;
257-
258312 dhcp_data .dp_op = 2 ; /* reply */
259313 dhcp_data .dp_secs = 0 ;
260314 dhcp_data .dp_flags = 0 ;
@@ -275,7 +329,9 @@ static void udp_recv_proc(void *arg, struct udp_pcb *upcb, struct pbuf *p, const
275329 pp = pbuf_alloc (PBUF_TRANSPORT , sizeof (dhcp_data ), PBUF_POOL );
276330 if (pp == NULL ) break ;
277331 memcpy (pp -> payload , & dhcp_data , sizeof (dhcp_data ));
278- udp_sendto (upcb , pp , IP_ADDR_BROADCAST , port );
332+ // RFC 2131 compliant destination selection for DHCP OFFER
333+ dest_addr = get_dhcp_destination (netif , & dhcp_data , & entry -> addr , false);
334+ udp_sendto (upcb , pp , & dest_addr , port );
279335 pbuf_free (pp );
280336 break ;
281337
@@ -319,7 +375,9 @@ static void udp_recv_proc(void *arg, struct udp_pcb *upcb, struct pbuf *p, const
319375 if (pp == NULL ) break ;
320376 memcpy (entry -> mac , dhcp_data .dp_chaddr , 6 );
321377 memcpy (pp -> payload , & dhcp_data , sizeof (dhcp_data ));
322- udp_sendto (upcb , pp , IP_ADDR_BROADCAST , port );
378+ // RFC 2131 compliant destination selection for DHCP ACK
379+ dest_addr = get_dhcp_destination (netif , & dhcp_data , & entry -> addr , false);
380+ udp_sendto (upcb , pp , & dest_addr , port );
323381 pbuf_free (pp );
324382 break ;
325383
0 commit comments