dhcp_client_misc.c
Go to the documentation of this file.
1 /**
2  * @file dhcp_client_misc.c
3  * @brief Helper functions for DHCP client
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2026 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.6.0
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL DHCP_TRACE_LEVEL
33 
34 //Dependencies
35 #include "core/net.h"
36 #include "dhcp/dhcp_client.h"
37 #include "dhcp/dhcp_client_fsm.h"
38 #include "dhcp/dhcp_client_misc.h"
39 #include "dhcp/dhcp_common.h"
40 #include "dhcp/dhcp_debug.h"
41 #include "mdns/mdns_responder.h"
42 #include "date_time.h"
43 #include "debug.h"
44 
45 //Check TCP/IP stack configuration
46 #if (IPV4_SUPPORT == ENABLED && DHCP_CLIENT_SUPPORT == ENABLED)
47 
48 //Requested DHCP options
49 const uint8_t dhcpOptionList[] =
50 {
58 };
59 
60 
61 /**
62  * @brief DHCP client timer handler
63  *
64  * This routine must be periodically called by the TCP/IP stack to manage
65  * DHCP client operation
66  *
67  * @param[in] context Pointer to the DHCP client context
68  **/
69 
71 {
72  //Make sure the DHCP client has been properly instantiated
73  if(context != NULL)
74  {
75  //DHCP client finite state machine
76  switch(context->state)
77  {
78  //INIT state?
79  case DHCP_STATE_INIT:
80  //This is the initialization state, where a client begins the process
81  //of acquiring a lease. It also returns here when a lease ends, or
82  //when a lease negotiation fails
83  dhcpClientStateInit(context);
84  break;
85 
86  //SELECTING state?
88  //The client is waiting to receive DHCPOFFER messages from one or more
89  //DHCP servers, so it can choose one
90  dhcpClientStateSelecting(context);
91  break;
92 
93  //REQUESTING state?
95  //The client is waiting to hear back from the server to which it sent
96  //its request
98  break;
99 
100  //INIT REBOOT state?
102  //When a client that already has a valid lease starts up after a
103  //power-down or reboot, it starts here instead of the INIT state
104  dhcpClientStateInitReboot(context);
105  break;
106 
107  //REBOOTING state?
109  //A client that has rebooted with an assigned address is waiting for
110  //a confirming reply from a server
111  dhcpClientStateRebooting(context);
112  break;
113 
114  //PROBING state?
115  case DHCP_STATE_PROBING:
116  //The client probes the newly received address
117  dhcpClientStateProbing(context);
118  break;
119 
120  //ANNOUNCING state?
122  //The client announces its new IP address
123  dhcpClientStateAnnouncing(context);
124  break;
125 
126  //BOUND state?
127  case DHCP_STATE_BOUND:
128  //Client has a valid lease and is in its normal operating state
129  dhcpClientStateBound(context);
130  break;
131 
132  //RENEWING state?
133  case DHCP_STATE_RENEWING:
134  //Client is trying to renew its lease. It regularly sends DHCPREQUEST
135  //messages with the server that gave it its current lease specified,
136  //and waits for a reply
137  dhcpClientStateRenewing(context);
138  break;
139 
140  //REBINDING state?
142  //The client has failed to renew its lease with the server that
143  //originally granted it, and now seeks a lease extension with any
144  //server that can hear it. It periodically sends DHCPREQUEST messages
145  //with no server specified until it gets a reply or the lease ends
146  dhcpClientStateRebinding(context);
147  break;
148 
149  //Invalid state?
150  default:
151  //Switch to the default state
152  context->state = DHCP_STATE_INIT;
153  break;
154  }
155  }
156 }
157 
158 
159 /**
160  * @brief Callback function for link change event
161  * @param[in] context Pointer to the DHCP client context
162  **/
163 
165 {
166  NetInterface *interface;
167 
168  //Make sure the DHCP client has been properly instantiated
169  if(context == NULL)
170  return;
171 
172  //Point to the underlying network interface
173  interface = context->interface;
174 
175  //Check whether the DHCP client is running
176  if(context->running)
177  {
178  //The host address is no longer valid
179  dhcpClientResetConfig(context);
180 
181 #if (MDNS_RESPONDER_SUPPORT == ENABLED)
182  //Restart mDNS probing process
183  mdnsResponderStartProbing(interface->mdnsResponderContext);
184 #endif
185  }
186 
187  //Check whether the client already has a valid lease
188  if(context->state >= DHCP_STATE_INIT_REBOOT)
189  {
190  //Switch to the INIT-REBOOT state
191  context->state = DHCP_STATE_INIT_REBOOT;
192  }
193  else
194  {
195  //Switch to the INIT state
196  context->state = DHCP_STATE_INIT;
197  }
198 
199  //Any registered callback?
200  if(context->linkChangeEvent != NULL)
201  {
202  //Release exclusive access
203  netUnlock(context->netContext);
204  //Invoke user callback function
205  context->linkChangeEvent(context, interface, interface->linkState);
206  //Get exclusive access
207  netLock(context->netContext);
208  }
209 }
210 
211 
212 /**
213  * @brief Send DHCPDISCOVER message
214  * @param[in] context Pointer to the DHCP client context
215  * @return Error code
216  **/
217 
219 {
220  error_t error;
221  size_t offset;
222  size_t length;
223  NetBuffer *buffer;
224  NetInterface *interface;
225  NetInterface *logicalInterface;
229  NetTxAncillary ancillary;
230 
231  //DHCP message type
232  const uint8_t type = DHCP_MSG_TYPE_DISCOVER;
233 
234  //Point to the underlying network interface
235  interface = context->interface;
236  //Point to the logical interface
237  logicalInterface = nicGetLogicalInterface(interface);
238 
239  //Allocate a memory buffer to hold the DHCP message
240  buffer = udpAllocBuffer(DHCP_MAX_MSG_SIZE, &offset);
241  //Failed to allocate buffer?
242  if(buffer == NULL)
243  return ERROR_OUT_OF_MEMORY;
244 
245  //Point to the beginning of the DHCP message
246  message = netBufferAt(buffer, offset, 0);
247 
248  //Clear memory buffer contents
250 
251  //Format DHCPDISCOVER message
254  message->hlen = sizeof(MacAddr);
255  message->xid = htonl(context->transactionId);
256  message->secs = dhcpClientComputeElapsedTime(context);
258  message->ciaddr = IPV4_UNSPECIFIED_ADDR;
259  message->chaddr = logicalInterface->macAddr;
260 
261  //Write magic cookie before setting any option
262  message->magicCookie = HTONL(DHCP_MAGIC_COOKIE);
263  //Properly terminate the options field
264  message->options[0] = DHCP_OPT_END;
265 
266  //Total length of the DHCP message
267  length = sizeof(DhcpMessage) + sizeof(uint8_t);
268 
269  //DHCP Message Type option
271  &type, sizeof(type));
272 
273  //Check whether rapid commit is enabled
274  if(context->rapidCommit)
275  {
276  //Include the Rapid Commit option if the client is prepared
277  //to perform the DHCPDISCOVER-DHCPACK message exchange
279  }
280 
281  //Any registered callback?
282  if(context->addOptionsCallback != NULL)
283  {
284  //Invoke user callback function
285  context->addOptionsCallback(context, message, &length,
287  }
288 
289  //The minimum length of BOOTP frames is 300 octets (refer to RFC 951,
290  //section 3)
292 
293  //Adjust the length of the multi-part buffer
294  netBufferSetLength(buffer, offset + length);
295 
296  //DHCP messages broadcast by a client prior to that client obtaining its
297  //IP address must have the source address field in the IP header set to 0
298  //(refer to RFC 2131, section 4.1)
299  srcIpAddr.length = sizeof(Ipv4Addr);
300  srcIpAddr.ipv4Addr = IPV4_UNSPECIFIED_ADDR;
301 
302  //Set destination IP address
303  destIpAddr.length = sizeof(Ipv4Addr);
304  destIpAddr.ipv4Addr = IPV4_BROADCAST_ADDR;
305 
306  //Debug message
307  TRACE_DEBUG("\r\n%s: Sending DHCP message (%" PRIuSIZE " bytes)...\r\n",
309 
310  //Dump the contents of the message for debugging purpose
312 
313  //Additional options can be passed to the stack along with the packet
314  ancillary = NET_DEFAULT_TX_ANCILLARY;
315 
316  //Broadcast DHCPDISCOVER message
317  error = udpSendBuffer(context->netContext, interface, &srcIpAddr,
318  DHCP_CLIENT_PORT, &destIpAddr, DHCP_SERVER_PORT, buffer, offset,
319  &ancillary);
320 
321  //Free previously allocated memory
322  netBufferFree(buffer);
323 
324  //Return status code
325  return error;
326 }
327 
328 
329 /**
330  * @brief Send DHCPREQUEST message
331  * @param[in] context Pointer to the DHCP client context
332  * @return Error code
333  **/
334 
336 {
337  uint_t i;
338  error_t error;
339  size_t offset;
340  size_t length;
341  NetBuffer *buffer;
342  NetInterface *interface;
343  NetInterface *logicalInterface;
347  NetTxAncillary ancillary;
348 
349  //DHCP message type
350  const uint8_t type = DHCP_MSG_TYPE_REQUEST;
351 
352  //Point to the underlying network interface
353  interface = context->interface;
354  //Point to the logical interface
355  logicalInterface = nicGetLogicalInterface(interface);
356 
357  //Index of the IP address in the list of addresses assigned to the interface
358  i = context->ipAddrIndex;
359 
360  //Allocate a memory buffer to hold the DHCP message
361  buffer = udpAllocBuffer(DHCP_MAX_MSG_SIZE, &offset);
362  //Failed to allocate buffer?
363  if(buffer == NULL)
364  return ERROR_OUT_OF_MEMORY;
365 
366  //Point to the beginning of the DHCP message
367  message = netBufferAt(buffer, offset, 0);
368 
369  //Clear memory buffer contents
371 
372  //Format DHCPREQUEST message
375  message->hlen = sizeof(MacAddr);
376  message->xid = htonl(context->transactionId);
377  message->secs = dhcpClientComputeElapsedTime(context);
378 
379  //The client IP address must be included if the client is fully configured
380  //and can respond to ARP requests
381  if(context->state == DHCP_STATE_RENEWING ||
382  context->state == DHCP_STATE_REBINDING)
383  {
384  message->flags = 0;
385  message->ciaddr = interface->ipv4Context.addrList[i].addr;
386  }
387  else
388  {
390  message->ciaddr = IPV4_UNSPECIFIED_ADDR;
391  }
392 
393  //Client hardware address
394  message->chaddr = logicalInterface->macAddr;
395  //Write magic cookie before setting any option
396  message->magicCookie = HTONL(DHCP_MAGIC_COOKIE);
397  //Properly terminate the options field
398  message->options[0] = DHCP_OPT_END;
399 
400  //Total length of the DHCP message
401  length = sizeof(DhcpMessage) + sizeof(uint8_t);
402 
403  //DHCP Message Type option
405  &type, sizeof(type));
406 
407  //Server Identifier option
408  if(context->state == DHCP_STATE_REQUESTING)
409  {
411  &context->serverIpAddr, sizeof(Ipv4Addr));
412  }
413 
414  //Requested IP Address option
415  if(context->state == DHCP_STATE_REQUESTING ||
416  context->state == DHCP_STATE_REBOOTING)
417  {
419  &context->requestedIpAddr, sizeof(Ipv4Addr));
420  }
421 
422  //Any registered callback?
423  if(context->addOptionsCallback != NULL)
424  {
425  //Invoke user callback function
426  context->addOptionsCallback(context, message, &length,
428  }
429 
430  //Parameter Request List option
432  {
433  //Use the default list of requested options
435  dhcpOptionList, sizeof(dhcpOptionList));
436  }
437 
438  //The minimum length of BOOTP frames is 300 octets (refer to RFC 951,
439  //section 3)
441 
442  //Adjust the length of the multi-part buffer
443  netBufferSetLength(buffer, offset + length);
444 
445  //IP address is being renewed?
446  if(context->state == DHCP_STATE_RENEWING)
447  {
448  //Set source IP address
449  srcIpAddr.length = sizeof(Ipv4Addr);
450  srcIpAddr.ipv4Addr = interface->ipv4Context.addrList[i].addr;
451 
452  //The client transmits the message directly to the server that initially
453  //granted the lease
454  destIpAddr.length = sizeof(Ipv4Addr);
455  destIpAddr.ipv4Addr = context->serverIpAddr;
456  }
457  else
458  {
459  //DHCP messages broadcast by a client prior to that client obtaining its
460  //IP address must have the source address field in the IP header set to 0
461  //(refer to RFC 2131, section 4.1)
462  srcIpAddr.length = sizeof(Ipv4Addr);
463  srcIpAddr.ipv4Addr = IPV4_UNSPECIFIED_ADDR;
464 
465  //Broadcast the message
466  destIpAddr.length = sizeof(Ipv4Addr);
467  destIpAddr.ipv4Addr = IPV4_BROADCAST_ADDR;
468  }
469 
470  //Debug message
471  TRACE_DEBUG("\r\n%s: Sending DHCP message (%" PRIuSIZE " bytes)...\r\n",
473 
474  //Dump the contents of the message for debugging purpose
476 
477  //Additional options can be passed to the stack along with the packet
478  ancillary = NET_DEFAULT_TX_ANCILLARY;
479 
480  //Send DHCPREQUEST message
481  error = udpSendBuffer(context->netContext, interface, &srcIpAddr,
482  DHCP_CLIENT_PORT, &destIpAddr, DHCP_SERVER_PORT, buffer, offset,
483  &ancillary);
484 
485  //Free previously allocated memory
486  netBufferFree(buffer);
487 
488  //Return status code
489  return error;
490 }
491 
492 
493 /**
494  * @brief Send DHCPDECLINE message
495  * @param[in] context Pointer to the DHCP client context
496  * @return Error code
497  **/
498 
500 {
501  error_t error;
502  size_t offset;
503  size_t length;
504  NetBuffer *buffer;
505  NetInterface *interface;
506  NetInterface *logicalInterface;
510  NetTxAncillary ancillary;
511 
512  //DHCP message type
513  const uint8_t type = DHCP_MSG_TYPE_DECLINE;
514 
515  //Point to the underlying network interface
516  interface = context->interface;
517  //Point to the logical interface
518  logicalInterface = nicGetLogicalInterface(interface);
519 
520  //Allocate a memory buffer to hold the DHCP message
521  buffer = udpAllocBuffer(DHCP_MAX_MSG_SIZE, &offset);
522  //Failed to allocate buffer?
523  if(buffer == NULL)
524  return ERROR_OUT_OF_MEMORY;
525 
526  //Point to the beginning of the DHCP message
527  message = netBufferAt(buffer, offset, 0);
528 
529  //Clear memory buffer contents
531 
532  //Format DHCPDECLINE message
535  message->hlen = sizeof(MacAddr);
536  message->xid = htonl(context->transactionId);
537  message->secs = 0;
538  message->flags = 0;
539  message->ciaddr = IPV4_UNSPECIFIED_ADDR;
540  message->chaddr = logicalInterface->macAddr;
541 
542  //Write magic cookie before setting any option
543  message->magicCookie = HTONL(DHCP_MAGIC_COOKIE);
544  //Properly terminate the options field
545  message->options[0] = DHCP_OPT_END;
546 
547  //Total length of the DHCP message
548  length = sizeof(DhcpMessage) + sizeof(uint8_t);
549 
550  //DHCP Message Type option
552  &type, sizeof(type));
553 
554  //Server Identifier option
556  &context->serverIpAddr, sizeof(Ipv4Addr));
557 
558  //Requested IP Address option
560  &context->requestedIpAddr, sizeof(Ipv4Addr));
561 
562  //Any registered callback?
563  if(context->addOptionsCallback != NULL)
564  {
565  //Invoke user callback function
566  context->addOptionsCallback(context, message, &length,
568  }
569 
570  //The minimum length of BOOTP frames is 300 octets (refer to RFC 951,
571  //section 3)
573 
574  //Adjust the length of the multi-part buffer
575  netBufferSetLength(buffer, offset + length);
576 
577  //Use the unspecified address as source address
578  srcIpAddr.length = sizeof(Ipv4Addr);
579  srcIpAddr.ipv4Addr = IPV4_UNSPECIFIED_ADDR;
580 
581  //Set destination IP address
582  destIpAddr.length = sizeof(Ipv4Addr);
583  destIpAddr.ipv4Addr = IPV4_BROADCAST_ADDR;
584 
585  //Debug message
586  TRACE_DEBUG("\r\n%s: Sending DHCP message (%" PRIuSIZE " bytes)...\r\n",
588 
589  //Dump the contents of the message for debugging purpose
591 
592  //Additional options can be passed to the stack along with the packet
593  ancillary = NET_DEFAULT_TX_ANCILLARY;
594 
595  //Broadcast DHCPDECLINE message
596  error = udpSendBuffer(context->netContext, interface, &srcIpAddr,
597  DHCP_CLIENT_PORT, &destIpAddr, DHCP_SERVER_PORT, buffer, offset,
598  &ancillary);
599 
600  //Free previously allocated memory
601  netBufferFree(buffer);
602 
603  //Return status code
604  return error;
605 }
606 
607 
608 /**
609  * @brief Send DHCPRELEASE message
610  * @param[in] context Pointer to the DHCP client context
611  * @return Error code
612  **/
613 
615 {
616  uint_t i;
617  error_t error;
618  size_t offset;
619  size_t length;
620  NetBuffer *buffer;
621  NetInterface *interface;
622  NetInterface *logicalInterface;
626  NetTxAncillary ancillary;
627 
628  //DHCP message type
629  const uint8_t type = DHCP_MSG_TYPE_RELEASE;
630 
631  //Point to the underlying network interface
632  interface = context->interface;
633  //Point to the logical interface
634  logicalInterface = nicGetLogicalInterface(interface);
635 
636  //Index of the IP address in the list of addresses assigned to the interface
637  i = context->ipAddrIndex;
638 
639  //Allocate a memory buffer to hold the DHCP message
640  buffer = udpAllocBuffer(DHCP_MAX_MSG_SIZE, &offset);
641  //Failed to allocate buffer?
642  if(buffer == NULL)
643  return ERROR_OUT_OF_MEMORY;
644 
645  //Point to the beginning of the DHCP message
646  message = netBufferAt(buffer, offset, 0);
647 
648  //Clear memory buffer contents
650 
651  //Format DHCP message
654  message->hlen = sizeof(MacAddr);
655  message->xid = htonl(context->transactionId);
656  message->secs = 0;
657  message->flags = 0;
658  message->ciaddr = interface->ipv4Context.addrList[i].addr;
659  message->chaddr = logicalInterface->macAddr;
660 
661  //Write magic cookie before setting any option
662  message->magicCookie = HTONL(DHCP_MAGIC_COOKIE);
663  //Properly terminate the options field
664  message->options[0] = DHCP_OPT_END;
665 
666  //Total length of the DHCP message
667  length = sizeof(DhcpMessage) + sizeof(uint8_t);
668 
669  //DHCP Message Type option
671  &type, sizeof(type));
672 
673  //Server Identifier option
675  &context->serverIpAddr, sizeof(Ipv4Addr));
676 
677  //Any registered callback?
678  if(context->addOptionsCallback != NULL)
679  {
680  //Invoke user callback function
681  context->addOptionsCallback(context, message, &length,
683  }
684 
685  //The minimum length of BOOTP frames is 300 octets (refer to RFC 951,
686  //section 3)
688 
689  //Adjust the length of the multi-part buffer
690  netBufferSetLength(buffer, offset + length);
691 
692  //Set source IP address
693  srcIpAddr.length = sizeof(Ipv4Addr);
694  srcIpAddr.ipv4Addr = interface->ipv4Context.addrList[i].addr;
695 
696  //The client unicasts DHCPRELEASE messages to the server (refer to RFC 2131,
697  //section 4.4.4)
698  destIpAddr.length = sizeof(Ipv4Addr);
699  destIpAddr.ipv4Addr = context->serverIpAddr;
700 
701  //Debug message
702  TRACE_DEBUG("\r\n%s: Sending DHCP message (%" PRIuSIZE " bytes)...\r\n",
704 
705  //Dump the contents of the message for debugging purpose
707 
708  //Additional options can be passed to the stack along with the packet
709  ancillary = NET_DEFAULT_TX_ANCILLARY;
710 
711  //Broadcast DHCP message
712  error = udpSendBuffer(context->netContext, interface, &srcIpAddr,
713  DHCP_CLIENT_PORT, &destIpAddr, DHCP_SERVER_PORT, buffer, offset,
714  &ancillary);
715 
716  //Free previously allocated memory
717  netBufferFree(buffer);
718 
719  //Return status code
720  return error;
721 }
722 
723 
724 /**
725  * @brief Process incoming DHCP message
726  * @param[in] interface Underlying network interface
727  * @param[in] pseudoHeader UDP pseudo header
728  * @param[in] udpHeader UDP header
729  * @param[in] buffer Multi-part buffer containing the incoming DHCP message
730  * @param[in] offset Offset to the first byte of the DHCP message
731  * @param[in] ancillary Additional options passed to the stack along with
732  * the packet
733  * @param[in] param Pointer to the DHCP client context
734  **/
735 
737  const IpPseudoHeader *pseudoHeader, const UdpHeader *udpHeader,
738  const NetBuffer *buffer, size_t offset, const NetRxAncillary *ancillary,
739  void *param)
740 {
741  size_t length;
742  DhcpClientContext *context;
744  DhcpOption *option;
745 
746  //Point to the DHCP client context
747  context = (DhcpClientContext *) param;
748 
749  //Retrieve the length of the DHCP message
750  length = netBufferGetLength(buffer) - offset;
751 
752  //Make sure the DHCP message is valid
753  if(length < sizeof(DhcpMessage) || length > DHCP_MAX_MSG_SIZE)
754  return;
755 
756  //Point to the beginning of the DHCP message
757  message = netBufferAt(buffer, offset, length);
758  //Sanity check
759  if(message == NULL)
760  return;
761 
762  //Debug message
763  TRACE_DEBUG("\r\n%s: DHCP message received (%" PRIuSIZE " bytes)...\r\n",
765 
766  //Dump the contents of the message for debugging purpose
768 
769  //The DHCP server shall respond with a BOOTREPLY opcode
770  if(message->op != DHCP_OPCODE_BOOTREPLY)
771  return;
772 
773  //Enforce hardware type
774  if(message->htype != DHCP_HARDWARE_TYPE_ETH)
775  return;
776 
777  //Check the length of the hardware address
778  if(message->hlen != sizeof(MacAddr))
779  return;
780 
781  //Check magic cookie
782  if(message->magicCookie != HTONL(DHCP_MAGIC_COOKIE))
783  return;
784 
785  //The DHCP Message Type option must be included in every DHCP message
787 
788  //Failed to retrieve the Message Type option?
789  if(option == NULL || option->length != 1)
790  return;
791 
792  //Check message type
793  switch(option->value[0])
794  {
795  case DHCP_MSG_TYPE_OFFER:
796  //Parse DHCPOFFER message
798  break;
799 
800  case DHCP_MSG_TYPE_ACK:
801  //Parse DHCPACK message
802  dhcpClientParseAck(context, message, length);
803  break;
804 
805  case DHCP_MSG_TYPE_NAK:
806  //Parse DHCPNAK message
807  dhcpClientParseNak(context, message, length);
808  break;
809 
810  default:
811  //Silently drop incoming message
812  break;
813  }
814 }
815 
816 
817 /**
818  * @brief Parse DHCPOFFER message
819  * @param[in] context Pointer to the DHCP client context
820  * @param[in] message Pointer to the incoming DHCP message
821  * @param[in] length Length of the incoming message to parse
822  **/
823 
825  const DhcpMessage *message, size_t length)
826 {
827  error_t error;
828  DhcpOption *serverIdOption;
829  NetInterface *interface;
830  NetInterface *logicalInterface;
831 
832  //Point to the underlying network interface
833  interface = context->interface;
834  //Point to the logical interface
835  logicalInterface = nicGetLogicalInterface(interface);
836 
837  //Discard any received packet that does not match the transaction ID
838  if(ntohl(message->xid) != context->transactionId)
839  return;
840 
841  //Make sure the IP address offered to the client is valid
842  if(message->yiaddr == IPV4_UNSPECIFIED_ADDR)
843  return;
844 
845  //Check MAC address
846  if(!macCompAddr(&message->chaddr, &logicalInterface->macAddr))
847  return;
848 
849  //Make sure that the DHCPOFFER message is received in response to
850  //a DHCPDISCOVER message
851  if(context->state != DHCP_STATE_SELECTING)
852  return;
853 
854  //A DHCP server always returns its own address in the Server Identifier option
855  serverIdOption = dhcpGetOption(message, length, DHCP_OPT_SERVER_ID);
856 
857  //Failed to retrieve the Server Identifier option?
858  if(serverIdOption == NULL || serverIdOption->length != 4)
859  return;
860 
861  //Any registered callback?
862  if(context->parseOptionsCallback != NULL)
863  {
864  //Invoke user callback function
865  error = context->parseOptionsCallback(context, message, length,
867  //Check status code
868  if(error)
869  return;
870  }
871 
872  //Record the IP address of the DHCP server
873  ipv4CopyAddr(&context->serverIpAddr, serverIdOption->value);
874  //Record the IP address offered to the client
875  context->requestedIpAddr = message->yiaddr;
876 
877  //Switch to the REQUESTING state
879 }
880 
881 
882 /**
883  * @brief Parse DHCPACK message
884  * @param[in] context Pointer to the DHCP client context
885  * @param[in] message Pointer to the incoming DHCP message
886  * @param[in] length Length of the incoming message to parse
887  **/
888 
890  const DhcpMessage *message, size_t length)
891 {
892  error_t error;
893  uint_t i;
894  uint_t j;
895  uint_t n;
896  DhcpOption *option;
897  DhcpOption *serverIdOption;
898  NetInterface *interface;
899  NetInterface *logicalInterface;
900  NetInterface *physicalInterface;
901 
902  //Point to the underlying network interface
903  interface = context->interface;
904  //Point to the logical interface
905  logicalInterface = nicGetLogicalInterface(interface);
906  //Point to the physical interface
907  physicalInterface = nicGetPhysicalInterface(interface);
908 
909  //Index of the IP address in the list of addresses assigned to the interface
910  i = context->ipAddrIndex;
911 
912  //Discard any received packet that does not match the transaction ID
913  if(ntohl(message->xid) != context->transactionId)
914  return;
915 
916  //Make sure the IP address assigned to the client is valid
917  if(message->yiaddr == IPV4_UNSPECIFIED_ADDR)
918  return;
919 
920  //Check MAC address
921  if(!macCompAddr(&message->chaddr, &logicalInterface->macAddr))
922  return;
923 
924  //A DHCP server always returns its own address in the Server Identifier option
925  serverIdOption = dhcpGetOption(message, length, DHCP_OPT_SERVER_ID);
926 
927  //Failed to retrieve the Server Identifier option?
928  if(serverIdOption == NULL || serverIdOption->length != 4)
929  return;
930 
931  //Check current state
932  if(context->state == DHCP_STATE_SELECTING)
933  {
934  //A DHCPACK message is not acceptable when rapid commit is disallowed
935  if(!context->rapidCommit)
936  return;
937 
938  //Search for the Rapid Commit option
940 
941  //A server must include this option in a DHCPACK message sent
942  //in a response to a DHCPDISCOVER message when completing the
943  //DHCPDISCOVER-DHCPACK message exchange
944  if(option == NULL || option->length != 0)
945  return;
946  }
947  else if(context->state == DHCP_STATE_REQUESTING ||
948  context->state == DHCP_STATE_RENEWING)
949  {
950  //Check the server identifier
951  if(!ipv4CompAddr(serverIdOption->value, &context->serverIpAddr))
952  return;
953  }
954  else if(context->state == DHCP_STATE_REBOOTING ||
955  context->state == DHCP_STATE_REBINDING)
956  {
957  //Do not check the server identifier
958  }
959  else
960  {
961  //Silently discard the DHCPACK message
962  return;
963  }
964 
965  //Retrieve IP Address Lease Time option
967 
968  //Failed to retrieve specified option?
969  if(option == NULL || option->length != 4)
970  return;
971 
972  //Any registered callback?
973  if(context->parseOptionsCallback != NULL)
974  {
975  //Invoke user callback function
976  error = context->parseOptionsCallback(context, message, length,
978  //Check status code
979  if(error)
980  return;
981  }
982 
983  //Record the lease time
984  context->leaseTime = LOAD32BE(option->value);
985 
986  //Retrieve Renewal Time Value option
988 
989  //Specified option found?
990  if(option != NULL && option->length == 4)
991  {
992  //This option specifies the time interval from address assignment
993  //until the client transitions to the RENEWING state
994  context->t1 = LOAD32BE(option->value);
995  }
996  else if(context->leaseTime != DHCP_INFINITE_TIME)
997  {
998  //By default, T1 is set to 50% of the lease time
999  context->t1 = context->leaseTime / 2;
1000  }
1001  else
1002  {
1003  //Infinite lease
1004  context->t1 = DHCP_INFINITE_TIME;
1005  }
1006 
1007  //Retrieve Rebinding Time value option
1009 
1010  //Specified option found?
1011  if(option != NULL && option->length == 4)
1012  {
1013  //This option specifies the time interval from address assignment
1014  //until the client transitions to the REBINDING state
1015  context->t2 = LOAD32BE(option->value);
1016  }
1017  else if(context->leaseTime != DHCP_INFINITE_TIME)
1018  {
1019  //By default, T2 is set to 87.5% of the lease time
1020  context->t2 = context->leaseTime * 7 / 8;
1021  }
1022  else
1023  {
1024  //Infinite lease
1025  context->t2 = DHCP_INFINITE_TIME;
1026  }
1027 
1028  //Retrieve Subnet Mask option
1030 
1031  //Option found?
1032  if(option != NULL && option->length == sizeof(Ipv4Addr))
1033  {
1034  //Save subnet mask
1035  ipv4CopyAddr(&interface->ipv4Context.addrList[i].subnetMask,
1036  option->value);
1037  }
1038 
1039  //Retrieve Router option
1041 
1042  //Option found?
1043  if(option != NULL && !(option->length % sizeof(Ipv4Addr)))
1044  {
1045  //Save default gateway
1046  if(option->length >= sizeof(Ipv4Addr))
1047  {
1048  ipv4CopyAddr(&interface->ipv4Context.addrList[i].defaultGateway,
1049  option->value);
1050  }
1051  }
1052 
1053  //Automatic DNS server configuration?
1054  if(!context->manualDnsConfig)
1055  {
1056  //Retrieve DNS Server option
1058 
1059  //Option found?
1060  if(option != NULL && !(option->length % sizeof(Ipv4Addr)))
1061  {
1062  //Get the number of addresses provided in the response
1063  n = option->length / sizeof(Ipv4Addr);
1064 
1065  //Loop through the list of addresses
1066  for(j = 0; j < n && j < IPV4_DNS_SERVER_LIST_SIZE; j++)
1067  {
1068  //Save DNS server address
1069  ipv4CopyAddr(&interface->ipv4Context.dnsServerList[j],
1070  option->value + j * sizeof(Ipv4Addr));
1071  }
1072  }
1073  }
1074 
1075  //Retrieve MTU option
1077 
1078  //Option found?
1079  if(option != NULL && option->length == 2)
1080  {
1081  //This option specifies the MTU to use on this interface
1082  n = LOAD16BE(option->value);
1083 
1084  //Make sure that the option's value is acceptable
1085  if(n >= IPV4_MINIMUM_MTU && n <= physicalInterface->nicDriver->mtu)
1086  {
1087  //Set the MTU to be used on the interface
1088  interface->ipv4Context.linkMtu = n;
1089  }
1090  }
1091 
1092  //Record the IP address of the DHCP server
1093  ipv4CopyAddr(&context->serverIpAddr, serverIdOption->value);
1094  //Record the IP address assigned to the client
1095  context->requestedIpAddr = message->yiaddr;
1096 
1097  //Save the time a which the lease was obtained
1098  context->leaseStartTime = osGetSystemTime();
1099 
1100  //Check current state
1101  if(context->state == DHCP_STATE_REQUESTING ||
1102  context->state == DHCP_STATE_REBOOTING)
1103  {
1104  //Use the IP address as a tentative address
1105  interface->ipv4Context.addrList[i].addr = message->yiaddr;
1106  interface->ipv4Context.addrList[i].state = IPV4_ADDR_STATE_TENTATIVE;
1107 
1108  //Clear conflict flag
1109  interface->ipv4Context.addrList[i].conflict = FALSE;
1110 
1111  //The client should probe the newly received address
1113  }
1114  else
1115  {
1116  //Assign the IP address to the client
1117  interface->ipv4Context.addrList[i].addr = message->yiaddr;
1118  interface->ipv4Context.addrList[i].state = IPV4_ADDR_STATE_VALID;
1119 
1120 #if (MDNS_RESPONDER_SUPPORT == ENABLED)
1121  //Restart mDNS probing process
1122  mdnsResponderStartProbing(interface->mdnsResponderContext);
1123 #endif
1124  //The client transitions to the BOUND state
1126  }
1127 }
1128 
1129 
1130 /**
1131  * @brief Parse DHCPNAK message
1132  * @param[in] context Pointer to the DHCP client context
1133  * @param[in] message Pointer to the incoming DHCP message
1134  * @param[in] length Length of the incoming message to parse
1135  **/
1136 
1138  const DhcpMessage *message, size_t length)
1139 {
1140  error_t error;
1141  DhcpOption *serverIdOption;
1142  NetInterface *interface;
1143  NetInterface *logicalInterface;
1144 
1145  //Point to the underlying network interface
1146  interface = context->interface;
1147  //Point to the logical interface
1148  logicalInterface = nicGetLogicalInterface(interface);
1149 
1150  //Discard any received packet that does not match the transaction ID
1151  if(ntohl(message->xid) != context->transactionId)
1152  return;
1153 
1154  //Check MAC address
1155  if(!macCompAddr(&message->chaddr, &logicalInterface->macAddr))
1156  return;
1157 
1158  //A DHCP server always returns its own address in the Server Identifier option
1159  serverIdOption = dhcpGetOption(message, length, DHCP_OPT_SERVER_ID);
1160 
1161  //Failed to retrieve the Server Identifier option?
1162  if(serverIdOption == NULL || serverIdOption->length != 4)
1163  return;
1164 
1165  //Check current state
1166  if(context->state == DHCP_STATE_REQUESTING ||
1167  context->state == DHCP_STATE_RENEWING)
1168  {
1169  //Check the server identifier
1170  if(!ipv4CompAddr(serverIdOption->value, &context->serverIpAddr))
1171  return;
1172  }
1173  else if(context->state == DHCP_STATE_REBOOTING ||
1174  context->state == DHCP_STATE_REBINDING)
1175  {
1176  //Do not check the server identifier
1177  }
1178  else
1179  {
1180  //Silently discard the DHCPNAK message
1181  return;
1182  }
1183 
1184  //Any registered callback?
1185  if(context->parseOptionsCallback != NULL)
1186  {
1187  //Invoke user callback function
1188  error = context->parseOptionsCallback(context, message, length,
1190  //Check status code
1191  if(error)
1192  return;
1193  }
1194 
1195  //The host address is no longer appropriate for the link
1196  dhcpClientResetConfig(context);
1197 
1198 #if (MDNS_RESPONDER_SUPPORT == ENABLED)
1199  //Restart mDNS probing process
1200  mdnsResponderStartProbing(interface->mdnsResponderContext);
1201 #endif
1202 
1203  //Restart DHCP configuration
1205 }
1206 
1207 
1208 /**
1209  * @brief Manage DHCP configuration timeout
1210  * @param[in] context Pointer to the DHCP client context
1211  **/
1212 
1214 {
1215  systime_t time;
1216 
1217  //Get current time
1218  time = osGetSystemTime();
1219 
1220  //Any registered callback?
1221  if(context->timeoutEvent != NULL)
1222  {
1223  //DHCP configuration timeout?
1224  if(timeCompare(time, context->configStartTime + context->configTimeout) >= 0)
1225  {
1226  //Ensure the callback function is only called once
1227  if(!context->timeoutEventDone)
1228  {
1229  //Release exclusive access
1230  netUnlock(context->netContext);
1231  //Invoke user callback function
1232  context->timeoutEvent(context, context->interface);
1233  //Get exclusive access
1234  netLock(context->netContext);
1235 
1236  //Set flag
1237  context->timeoutEventDone = TRUE;
1238  }
1239  }
1240  }
1241 }
1242 
1243 
1244 /**
1245  * @brief Compute the appropriate secs field
1246  *
1247  * Compute the number of seconds elapsed since the client began address
1248  * acquisition or renewal process
1249  *
1250  * @param[in] context Pointer to the DHCP client context
1251  * @return The elapsed time expressed in seconds
1252  **/
1253 
1255 {
1256  systime_t time;
1257 
1258  //Compute the time elapsed since the DHCP configuration process started
1259  time = (osGetSystemTime() - context->configStartTime) / 1000;
1260 
1261  //The value 0xFFFF is used to represent any elapsed time values
1262  //greater than the largest time value that can be represented
1263  time = MIN(time, 0xFFFF);
1264 
1265  //Convert the 16-bit value to network byte order
1266  return htons(time);
1267 }
1268 
1269 
1270 /**
1271  * @brief Update DHCP FSM state
1272  * @param[in] context Pointer to the DHCP client context
1273  * @param[in] newState New DHCP state to switch to
1274  * @param[in] delay Initial delay
1275  **/
1276 
1278  DhcpState newState, systime_t delay)
1279 {
1280  systime_t time;
1281 
1282  //Get current time
1283  time = osGetSystemTime();
1284 
1285 #if (DHCP_TRACE_LEVEL >= TRACE_LEVEL_INFO)
1286  //Sanity check
1287  if(newState <= DHCP_STATE_REBINDING)
1288  {
1289  //DHCP FSM states
1290  static const char_t *const stateLabel[] =
1291  {
1292  "INIT",
1293  "SELECTING",
1294  "REQUESTING",
1295  "INIT-REBOOT",
1296  "REBOOTING",
1297  "PROBING",
1298  "ANNOUNCING",
1299  "BOUND",
1300  "RENEWING",
1301  "REBINDING"
1302  };
1303 
1304  //Debug message
1305  TRACE_INFO("%s: DHCP client %s state\r\n",
1306  formatSystemTime(time, NULL), stateLabel[newState]);
1307  }
1308 #endif
1309 
1310  //Set time stamp
1311  context->timestamp = time;
1312  //Set initial delay
1313  context->timeout = delay;
1314  //Reset retransmission counter
1315  context->retransmitCount = 0;
1316  //Switch to the new state
1317  context->state = newState;
1318 
1319  //Any registered callback?
1320  if(context->stateChangeEvent != NULL)
1321  {
1322  //Release exclusive access
1323  netUnlock(context->netContext);
1324  //Invoke user callback function
1325  context->stateChangeEvent(context, context->interface, newState);
1326  //Get exclusive access
1327  netLock(context->netContext);
1328  }
1329 }
1330 
1331 
1332 /**
1333  * @brief Reset DHCP configuration
1334  * @param[in] context Pointer to the DHCP client context
1335  **/
1336 
1338 {
1339  uint_t i;
1340  uint_t j;
1341  NetInterface *interface;
1342 
1343  //Point to the underlying network interface
1344  interface = context->interface;
1345  //Index of the IP address in the list of addresses assigned to the interface
1346  i = context->ipAddrIndex;
1347 
1348  //The host address is not longer valid
1349  interface->ipv4Context.addrList[i].addr = IPV4_UNSPECIFIED_ADDR;
1350  interface->ipv4Context.addrList[i].state = IPV4_ADDR_STATE_INVALID;
1351 
1352  //Clear subnet mask
1353  interface->ipv4Context.addrList[i].subnetMask = IPV4_UNSPECIFIED_ADDR;
1354 
1355  //The default gateway is no longer valid
1356  interface->ipv4Context.addrList[i].defaultGateway = IPV4_UNSPECIFIED_ADDR;
1357 
1358  //Automatic DNS server configuration?
1359  if(!context->manualDnsConfig)
1360  {
1361  //Loop through the list of DNS servers
1362  for(j = 0; j < IPV4_DNS_SERVER_LIST_SIZE; j++)
1363  {
1364  //The DNS server is no longer valid
1365  interface->ipv4Context.dnsServerList[j] = IPV4_UNSPECIFIED_ADDR;
1366  }
1367  }
1368 }
1369 
1370 
1371 /**
1372  * @brief Dump DHCP configuration for debugging purpose
1373  * @param[in] context Pointer to the DHCP client context
1374  **/
1375 
1377 {
1378 #if (DHCP_TRACE_LEVEL >= TRACE_LEVEL_INFO)
1379  uint_t i;
1380  uint_t j;
1381  Ipv4Context *ipv4Context;
1382 
1383  //Point to the IPv4 context
1384  ipv4Context = &context->interface->ipv4Context;
1385  //Index of the IP address in the list of addresses assigned to the interface
1386  i = context->ipAddrIndex;
1387 
1388  //Debug message
1389  TRACE_INFO("\r\n");
1390  TRACE_INFO("DHCP configuration:\r\n");
1391 
1392  //Lease start time
1393  TRACE_INFO(" Lease Start Time = %s\r\n",
1394  formatSystemTime(context->leaseStartTime, NULL));
1395 
1396  //Lease time
1397  TRACE_INFO(" Lease Time = %" PRIu32 "s\r\n", context->leaseTime);
1398  //Renewal time
1399  TRACE_INFO(" T1 = %" PRIu32 "s\r\n", context->t1);
1400  //Rebinding time
1401  TRACE_INFO(" T2 = %" PRIu32 "s\r\n", context->t2);
1402 
1403  //Host address
1404  TRACE_INFO(" IPv4 Address = %s\r\n",
1405  ipv4AddrToString(ipv4Context->addrList[i].addr, NULL));
1406 
1407  //Subnet mask
1408  TRACE_INFO(" Subnet Mask = %s\r\n",
1409  ipv4AddrToString(ipv4Context->addrList[i].subnetMask, NULL));
1410 
1411  //Default gateway
1412  TRACE_INFO(" Default Gateway = %s\r\n",
1413  ipv4AddrToString(ipv4Context->addrList[i].defaultGateway, NULL));
1414 
1415  //DNS servers
1416  for(j = 0; j < IPV4_DNS_SERVER_LIST_SIZE; j++)
1417  {
1418  TRACE_INFO(" DNS Server %u = %s\r\n", j + 1,
1419  ipv4AddrToString(ipv4Context->dnsServerList[j], NULL));
1420  }
1421 
1422  //Maximum transmit unit
1423  TRACE_INFO(" MTU = %" PRIuSIZE "\r\n", ipv4Context->linkMtu);
1424  TRACE_INFO("\r\n");
1425 #endif
1426 }
1427 
1428 #endif
#define htons(value)
Definition: cpu_endian.h:413
error_t dhcpDumpMessage(const DhcpMessage *message, size_t length)
Dump DHCP message for debugging purpose.
Definition: dhcp_debug.c:158
Date and time management.
@ DHCP_OPT_SERVER_ID
Definition: dhcp_common.h:160
void netUnlock(NetContext *context)
Release exclusive access to the core of the TCP/IP stack.
Definition: net.c:319
Ipv4Addr addr
IPv4 address.
Definition: ipv4.h:411
DHCP client (Dynamic Host Configuration Protocol)
error_t dhcpClientSendRelease(DhcpClientContext *context)
Send DHCPRELEASE message.
const NetTxAncillary NET_DEFAULT_TX_ANCILLARY
Definition: net_misc.c:70
#define LOAD32BE(p)
Definition: cpu_endian.h:210
Ipv4Addr dnsServerList[IPV4_DNS_SERVER_LIST_SIZE]
DNS servers.
Definition: ipv4.h:459
@ DHCP_STATE_ANNOUNCING
Definition: dhcp_client.h:165
IP network address.
Definition: ip.h:90
void dhcpClientStateSelecting(DhcpClientContext *context)
SELECTING state.
void dhcpClientStateBound(DhcpClientContext *context)
BOUND state.
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
uint8_t message[]
Definition: chap.h:154
#define TRUE
Definition: os_port.h:50
@ DHCP_OPT_REQUESTED_IP_ADDR
Definition: dhcp_common.h:156
void dhcpClientParseAck(DhcpClientContext *context, const DhcpMessage *message, size_t length)
Parse DHCPACK message.
@ DHCP_MSG_TYPE_ACK
Definition: dhcp_common.h:93
#define DHCP_INFINITE_TIME
Definition: dhcp_common.h:53
uint8_t type
Definition: coap_common.h:176
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
void dhcpClientStateInitReboot(DhcpClientContext *context)
INIT-REBOOT state.
void dhcpClientStateInit(DhcpClientContext *context)
INIT state.
error_t dhcpClientSendDiscover(DhcpClientContext *context)
Send DHCPDISCOVER message.
Ipv4Addr srcIpAddr
Definition: ipcp.h:79
const char_t * formatSystemTime(systime_t time, char_t *str)
Format system time.
Definition: date_time.c:77
error_t dhcpClientSendRequest(DhcpClientContext *context)
Send DHCPREQUEST message.
#define timeCompare(t1, t2)
Definition: os_port.h:40
uint32_t Ipv4Addr
IPv4 network address.
Definition: ipv4.h:322
Helper functions for DHCP client.
void dhcpClientParseOffer(DhcpClientContext *context, const DhcpMessage *message, size_t length)
Parse DHCPOFFER message.
#define DHCP_MAX_MSG_SIZE
Definition: dhcp_common.h:46
#define DHCP_MAGIC_COOKIE
Definition: dhcp_common.h:51
void dhcpClientStateProbing(DhcpClientContext *context)
PROBING state.
IPv4 context.
Definition: ipv4.h:451
@ DHCP_OPT_ROUTER
Definition: dhcp_common.h:109
void dhcpClientCheckTimeout(DhcpClientContext *context)
Manage DHCP configuration timeout.
#define DhcpClientContext
Definition: dhcp_client.h:145
IP pseudo header.
Definition: ip.h:110
@ DHCP_OPT_END
Definition: dhcp_common.h:191
error_t dhcpAddOption(DhcpMessage *message, size_t *messageLen, uint8_t optionCode, const void *optionValue, size_t optionLen)
Append an option to a DHCP message.
Definition: dhcp_common.c:56
#define FALSE
Definition: os_port.h:46
error_t dhcpClientSendDecline(DhcpClientContext *context)
Send DHCPDECLINE message.
Ipv4Addr defaultGateway
Default gateway.
Definition: ipv4.h:415
void dhcpClientStateRebooting(DhcpClientContext *context)
REBOOTING state.
@ DHCP_STATE_INIT_REBOOT
Definition: dhcp_client.h:162
const uint8_t dhcpOptionList[]
#define htonl(value)
Definition: cpu_endian.h:414
void dhcpClientStateAnnouncing(DhcpClientContext *context)
ANNOUNCING state.
NetInterface * nicGetPhysicalInterface(NetInterface *interface)
Retrieve physical interface.
Definition: nic.c:87
#define HTONL(value)
Definition: cpu_endian.h:411
size_t linkMtu
Maximum transmission unit.
Definition: ipv4.h:452
error_t
Error codes.
Definition: error.h:43
@ IPV4_ADDR_STATE_TENTATIVE
An address whose uniqueness on a link is being verified.
Definition: ipv4.h:227
void dhcpClientStateRenewing(DhcpClientContext *context)
RENEWING state.
#define DHCP_MIN_MSG_SIZE
Definition: dhcp_common.h:44
#define IPV4_DNS_SERVER_LIST_SIZE
Definition: ipv4.h:87
#define NetRxAncillary
Definition: net_misc.h:40
#define NetInterface
Definition: net.h:40
void netBufferFree(NetBuffer *buffer)
Dispose a multi-part buffer.
Definition: net_mem.c:282
void dhcpClientChangeState(DhcpClientContext *context, DhcpState newState, systime_t delay)
Update DHCP FSM state.
@ DHCP_OPT_IP_ADDRESS_LEASE_TIME
Definition: dhcp_common.h:157
DhcpMessage
Definition: dhcp_common.h:226
@ DHCP_OPT_DHCP_MESSAGE_TYPE
Definition: dhcp_common.h:159
#define NetTxAncillary
Definition: net_misc.h:36
@ DHCP_MSG_TYPE_DECLINE
Definition: dhcp_common.h:92
error_t udpSendBuffer(NetContext *context, NetInterface *interface, const IpAddr *srcIpAddr, uint16_t srcPort, const IpAddr *destIpAddr, uint16_t destPort, NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send a UDP datagram.
Definition: udp.c:657
@ DHCP_FLAG_BROADCAST
Definition: dhcp_common.h:79
@ DHCP_STATE_REBOOTING
Definition: dhcp_client.h:163
Definitions common to DHCP client and server.
#define TRACE_INFO(...)
Definition: debug.h:105
uint8_t length
Definition: tcp.h:375
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
@ DHCP_STATE_REBINDING
Definition: dhcp_client.h:168
#define MIN(a, b)
Definition: os_port.h:63
NetBuffer * udpAllocBuffer(size_t length, size_t *offset)
Allocate a buffer to hold a UDP packet.
Definition: udp.c:948
DHCP client finite state machine.
void dhcpClientStateRebinding(DhcpClientContext *context)
REBINDING state.
#define IPV4_BROADCAST_ADDR
Definition: ipv4.h:130
MacAddr
Definition: ethernet.h:197
UdpHeader
Definition: udp.h:85
@ DHCP_STATE_REQUESTING
Definition: dhcp_client.h:161
uint32_t systime_t
System time.
@ DHCP_OPCODE_BOOTREPLY
Definition: dhcp_common.h:68
#define TRACE_DEBUG(...)
Definition: debug.h:119
#define MAX(a, b)
Definition: os_port.h:67
char char_t
Definition: compiler_port.h:55
@ DHCP_OPCODE_BOOTREQUEST
Definition: dhcp_common.h:67
@ DHCP_OPT_INTERFACE_MTU
Definition: dhcp_common.h:132
@ DHCP_STATE_BOUND
Definition: dhcp_client.h:166
Ipv4Addr subnetMask
Subnet mask.
Definition: ipv4.h:414
void dhcpClientProcessMessage(NetInterface *interface, const IpPseudoHeader *pseudoHeader, const UdpHeader *udpHeader, const NetBuffer *buffer, size_t offset, const NetRxAncillary *ancillary, void *param)
Process incoming DHCP message.
uint32_t time
#define ipv4CompAddr(ipAddr1, ipAddr2)
Definition: ipv4.h:170
@ DHCP_STATE_SELECTING
Definition: dhcp_client.h:160
@ DHCP_OPT_REBINDING_TIME_VALUE
Definition: dhcp_common.h:165
#define HTONS(value)
Definition: cpu_endian.h:410
uint8_t n
DhcpState
DHCP FSM states.
Definition: dhcp_client.h:158
@ DHCP_STATE_PROBING
Definition: dhcp_client.h:164
Ipv4AddrEntry addrList[IPV4_ADDR_LIST_SIZE]
IPv4 address list.
Definition: ipv4.h:458
Data logging functions for debugging purpose (DHCP)
void dhcpClientDumpConfig(DhcpClientContext *context)
Dump DHCP configuration for debugging purpose.
@ IPV4_ADDR_STATE_INVALID
An address that is not assigned to any interface.
Definition: ipv4.h:226
#define DHCP_SERVER_PORT
Definition: dhcp_common.h:40
void dhcpClientStateRequesting(DhcpClientContext *context)
REQUESTING state.
@ DHCP_OPT_SUBNET_MASK
Definition: dhcp_common.h:107
@ DHCP_OPT_DNS_SERVER
Definition: dhcp_common.h:112
error_t netBufferSetLength(NetBuffer *buffer, size_t length)
Adjust the length of a multi-part buffer.
Definition: net_mem.c:322
#define macCompAddr(macAddr1, macAddr2)
Definition: ethernet.h:130
@ DHCP_MSG_TYPE_OFFER
Definition: dhcp_common.h:90
DhcpOption
Definition: dhcp_common.h:238
@ DHCP_MSG_TYPE_REQUEST
Definition: dhcp_common.h:91
@ DHCP_MSG_TYPE_NAK
Definition: dhcp_common.h:94
#define ipv4CopyAddr(destIpAddr, srcIpAddr)
Definition: ipv4.h:166
void netLock(NetContext *context)
Get exclusive access to the core of the TCP/IP stack.
Definition: net.c:307
@ DHCP_STATE_INIT
Definition: dhcp_client.h:159
void * netBufferAt(const NetBuffer *buffer, size_t offset, size_t length)
Returns a pointer to a data segment.
Definition: net_mem.c:418
void dhcpClientTick(DhcpClientContext *context)
DHCP client timer handler.
@ IPV4_ADDR_STATE_VALID
An address assigned to an interface whose use is unrestricted.
Definition: ipv4.h:228
uint16_t dhcpClientComputeElapsedTime(DhcpClientContext *context)
Compute the appropriate secs field.
@ DHCP_OPT_PARAM_REQUEST_LIST
Definition: dhcp_common.h:161
void dhcpClientLinkChangeEvent(DhcpClientContext *context)
Callback function for link change event.
#define DHCP_HARDWARE_TYPE_ETH
Definition: dhcp_common.h:49
#define PRIuSIZE
unsigned int uint_t
Definition: compiler_port.h:57
#define LOAD16BE(p)
Definition: cpu_endian.h:186
@ DHCP_MSG_TYPE_DISCOVER
Definition: dhcp_common.h:89
#define osMemset(p, value, length)
Definition: os_port.h:138
TCP/IP stack core.
NetInterface * nicGetLogicalInterface(NetInterface *interface)
Retrieve logical interface.
Definition: nic.c:51
#define DHCP_CLIENT_PORT
Definition: dhcp_common.h:41
char_t * ipv4AddrToString(Ipv4Addr ipAddr, char_t *str)
Convert a binary IPv4 address to dot-decimal notation.
Definition: ipv4.c:1468
#define IPV4_MINIMUM_MTU
Definition: ipv4.h:109
@ DHCP_OPT_RENEWAL_TIME_VALUE
Definition: dhcp_common.h:164
void dhcpClientParseNak(DhcpClientContext *context, const DhcpMessage *message, size_t length)
Parse DHCPNAK message.
@ DHCP_MSG_TYPE_RELEASE
Definition: dhcp_common.h:95
#define ntohl(value)
Definition: cpu_endian.h:422
error_t mdnsResponderStartProbing(MdnsResponderContext *context)
Restart probing process.
void dhcpClientResetConfig(DhcpClientContext *context)
Reset DHCP configuration.
Debugging facilities.
@ DHCP_STATE_RENEWING
Definition: dhcp_client.h:167
DhcpOption * dhcpGetOption(const DhcpMessage *message, size_t length, uint8_t optionCode)
Search a DHCP message for a given option.
Definition: dhcp_common.c:118
@ DHCP_OPT_RAPID_COMMIT
Definition: dhcp_common.h:181
#define IPV4_UNSPECIFIED_ADDR
Definition: ipv4.h:128
mDNS responder (Multicast DNS)
systime_t osGetSystemTime(void)
Retrieve system time.
Ipv4Addr destIpAddr
Definition: ipcp.h:80