@@ -227,12 +227,69 @@ 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+ ip4_addr_t giaddr = get_ip (dhcp -> dp_giaddr );
238+ ip4_addr_t ciaddr = get_ip (dhcp -> dp_ciaddr );
239+ bool giaddr_zero = ip4_addr_isany_val (giaddr );
240+ bool ciaddr_zero = ip4_addr_isany_val (ciaddr );
241+ bool broadcast_flag = (dhcp -> dp_flags & htons (0x8000 )) != 0 ;
242+ ip_addr_t dest_addr ;
243+
244+ if (!giaddr_zero ) {
245+ // If giaddr is not zero, send to giaddr (relay agent)
246+ ip_addr_set_ip4_u32 (& dest_addr , giaddr .addr );
247+ return dest_addr ;
248+ }
249+
250+ if (is_nak ) {
251+ // RFC 2131: "In all cases, when 'giaddr' is zero,
252+ // the server broadcasts any DHCPNAK messages to 0xffffffff"
253+ goto dest_broadcast ;
254+ }
255+
256+ if (!ciaddr_zero ) {
257+ // RFC 2131: "If the 'giaddr' field is zero and the 'ciaddr' field is nonzero,
258+ // then the server unicasts DHCPOFFER and DHCPACK messages to the address in 'ciaddr'"
259+ ip_addr_set_ip4_u32 (& dest_addr , ciaddr .addr );
260+ return dest_addr ;
261+ }
262+
263+ if (broadcast_flag ) {
264+ // RFC 2131: "If 'giaddr' is zero and 'ciaddr' is zero, and the broadcast bit is set,
265+ // then the server broadcasts DHCPOFFER and DHCPACK messages to 0xffffffff"
266+ goto dest_broadcast ;
267+ }
268+
269+ // RFC 2131: "If the broadcast bit is not set and 'giaddr' is zero and 'ciaddr' is zero,
270+ // then the server unicasts DHCPOFFER and DHCPACK messages to the client's hardware
271+ // address and 'yiaddr' address"
272+ if (yiaddr && !ip4_addr_isany (yiaddr )) {
273+ ip_addr_set_ip4_u32 (& dest_addr , yiaddr -> addr );
274+ // TODO: This requires ARP table manipulation to associate yiaddr with client MAC
275+ // For now, fall back to broadcast as this is complex to implement correctly
276+ goto dest_broadcast ;
277+ }
278+
279+ dest_broadcast :
280+ ip_addr_set_ip4_u32 (& dest_addr ,
281+ ip4_addr_get_u32 (netif_ip4_addr (netif )) | ~ip4_addr_get_u32 (netif_ip4_netmask (netif )));
282+ return dest_addr ;
283+
284+ }
285+
230286static void udp_recv_proc (void * arg , struct udp_pcb * upcb , struct pbuf * p , const ip_addr_t * addr , u16_t port )
231287{
232288 uint8_t * ptr ;
233289 dhcp_entry_t * entry ;
234290 struct pbuf * pp ;
235291 struct netif * netif = netif_get_by_index (p -> if_idx );
292+ ip_addr_t dest_addr ;
236293
237294 (void )arg ;
238295 (void )addr ;
@@ -254,7 +311,6 @@ static void udp_recv_proc(void *arg, struct udp_pcb *upcb, struct pbuf *p, const
254311 entry = entry_by_mac (dhcp_data .dp_chaddr );
255312 if (entry == NULL ) entry = vacant_address ();
256313 if (entry == NULL ) break ;
257-
258314 dhcp_data .dp_op = 2 ; /* reply */
259315 dhcp_data .dp_secs = 0 ;
260316 dhcp_data .dp_flags = 0 ;
@@ -275,7 +331,9 @@ static void udp_recv_proc(void *arg, struct udp_pcb *upcb, struct pbuf *p, const
275331 pp = pbuf_alloc (PBUF_TRANSPORT , sizeof (dhcp_data ), PBUF_POOL );
276332 if (pp == NULL ) break ;
277333 memcpy (pp -> payload , & dhcp_data , sizeof (dhcp_data ));
278- udp_sendto (upcb , pp , IP_ADDR_BROADCAST , port );
334+ // RFC 2131 compliant destination selection for DHCP OFFER
335+ dest_addr = get_dhcp_destination (netif , & dhcp_data , & entry -> addr , false);
336+ udp_sendto (upcb , pp , & dest_addr , port );
279337 pbuf_free (pp );
280338 break ;
281339
@@ -319,7 +377,9 @@ static void udp_recv_proc(void *arg, struct udp_pcb *upcb, struct pbuf *p, const
319377 if (pp == NULL ) break ;
320378 memcpy (entry -> mac , dhcp_data .dp_chaddr , 6 );
321379 memcpy (pp -> payload , & dhcp_data , sizeof (dhcp_data ));
322- udp_sendto (upcb , pp , IP_ADDR_BROADCAST , port );
380+ // RFC 2131 compliant destination selection for DHCP ACK
381+ dest_addr = get_dhcp_destination (netif , & dhcp_data , & entry -> addr , false);
382+ udp_sendto (upcb , pp , & dest_addr , port );
323383 pbuf_free (pp );
324384 break ;
325385
0 commit comments