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-2024 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.4.4
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 //Tick counter to handle periodic operations
50 
51 //Requested DHCP options
52 const uint8_t dhcpOptionList[] =
53 {
61 };
62 
63 
64 /**
65  * @brief DHCP client timer handler
66  *
67  * This routine must be periodically called by the TCP/IP stack to manage
68  * DHCP client operation
69  *
70  * @param[in] context Pointer to the DHCP client context
71  **/
72 
74 {
75  //Make sure the DHCP client has been properly instantiated
76  if(context != NULL)
77  {
78  //DHCP client finite state machine
79  switch(context->state)
80  {
81  //INIT state?
82  case DHCP_STATE_INIT:
83  //This is the initialization state, where a client begins the process
84  //of acquiring a lease. It also returns here when a lease ends, or
85  //when a lease negotiation fails
86  dhcpClientStateInit(context);
87  break;
88 
89  //SELECTING state?
91  //The client is waiting to receive DHCPOFFER messages from one or more
92  //DHCP servers, so it can choose one
93  dhcpClientStateSelecting(context);
94  break;
95 
96  //REQUESTING state?
98  //The client is waiting to hear back from the server to which it sent
99  //its request
100  dhcpClientStateRequesting(context);
101  break;
102 
103  //INIT REBOOT state?
105  //When a client that already has a valid lease starts up after a
106  //power-down or reboot, it starts here instead of the INIT state
107  dhcpClientStateInitReboot(context);
108  break;
109 
110  //REBOOTING state?
112  //A client that has rebooted with an assigned address is waiting for
113  //a confirming reply from a server
114  dhcpClientStateRebooting(context);
115  break;
116 
117  //PROBING state?
118  case DHCP_STATE_PROBING:
119  //The client probes the newly received address
120  dhcpClientStateProbing(context);
121  break;
122 
123  //ANNOUNCING state?
125  //The client announces its new IP address
126  dhcpClientStateAnnouncing(context);
127  break;
128 
129  //BOUND state?
130  case DHCP_STATE_BOUND:
131  //Client has a valid lease and is in its normal operating state
132  dhcpClientStateBound(context);
133  break;
134 
135  //RENEWING state?
136  case DHCP_STATE_RENEWING:
137  //Client is trying to renew its lease. It regularly sends DHCPREQUEST
138  //messages with the server that gave it its current lease specified,
139  //and waits for a reply
140  dhcpClientStateRenewing(context);
141  break;
142 
143  //REBINDING state?
145  //The client has failed to renew its lease with the server that
146  //originally granted it, and now seeks a lease extension with any
147  //server that can hear it. It periodically sends DHCPREQUEST messages
148  //with no server specified until it gets a reply or the lease ends
149  dhcpClientStateRebinding(context);
150  break;
151 
152  //Invalid state?
153  default:
154  //Switch to the default state
155  context->state = DHCP_STATE_INIT;
156  break;
157  }
158  }
159 }
160 
161 
162 /**
163  * @brief Callback function for link change event
164  * @param[in] context Pointer to the DHCP client context
165  **/
166 
168 {
169  NetInterface *interface;
170 
171  //Make sure the DHCP client has been properly instantiated
172  if(context == NULL)
173  return;
174 
175  //Point to the underlying network interface
176  interface = context->settings.interface;
177 
178  //Check whether the DHCP client is running
179  if(context->running)
180  {
181  //The host address is no longer valid
182  dhcpClientResetConfig(context);
183 
184 #if (MDNS_RESPONDER_SUPPORT == ENABLED)
185  //Restart mDNS probing process
186  mdnsResponderStartProbing(interface->mdnsResponderContext);
187 #endif
188  }
189 
190  //Check whether the client already has a valid lease
191  if(context->state >= DHCP_STATE_INIT_REBOOT)
192  {
193  //Switch to the INIT-REBOOT state
194  context->state = DHCP_STATE_INIT_REBOOT;
195  }
196  else
197  {
198  //Switch to the INIT state
199  context->state = DHCP_STATE_INIT;
200  }
201 
202  //Any registered callback?
203  if(context->settings.linkChangeEvent != NULL)
204  {
205  //Release exclusive access
207  //Invoke user callback function
208  context->settings.linkChangeEvent(context, interface, interface->linkState);
209  //Get exclusive access
211  }
212 }
213 
214 
215 /**
216  * @brief Send DHCPDISCOVER message
217  * @param[in] context Pointer to the DHCP client context
218  * @return Error code
219  **/
220 
222 {
223  error_t error;
224  size_t offset;
225  size_t length;
226  NetBuffer *buffer;
227  NetInterface *interface;
228  NetInterface *logicalInterface;
232  NetTxAncillary ancillary;
233 
234  //DHCP message type
235  const uint8_t type = DHCP_MSG_TYPE_DISCOVER;
236 
237  //Point to the underlying network interface
238  interface = context->settings.interface;
239  //Point to the logical interface
240  logicalInterface = nicGetLogicalInterface(interface);
241 
242  //Allocate a memory buffer to hold the DHCP message
243  buffer = udpAllocBuffer(DHCP_MAX_MSG_SIZE, &offset);
244  //Failed to allocate buffer?
245  if(buffer == NULL)
246  return ERROR_OUT_OF_MEMORY;
247 
248  //Point to the beginning of the DHCP message
249  message = netBufferAt(buffer, offset, 0);
250 
251  //Clear memory buffer contents
253 
254  //Format DHCPDISCOVER message
257  message->hlen = sizeof(MacAddr);
258  message->xid = htonl(context->transactionId);
259  message->secs = dhcpClientComputeElapsedTime(context);
261  message->ciaddr = IPV4_UNSPECIFIED_ADDR;
262  message->chaddr = logicalInterface->macAddr;
263 
264  //Write magic cookie before setting any option
265  message->magicCookie = HTONL(DHCP_MAGIC_COOKIE);
266  //Properly terminate the options field
267  message->options[0] = DHCP_OPT_END;
268 
269  //Total length of the DHCP message
270  length = sizeof(DhcpMessage) + sizeof(uint8_t);
271 
272  //DHCP Message Type option
274  &type, sizeof(type));
275 
276  //Check whether rapid commit is enabled
277  if(context->settings.rapidCommit)
278  {
279  //Include the Rapid Commit option if the client is prepared
280  //to perform the DHCPDISCOVER-DHCPACK message exchange
282  }
283 
284  //Any registered callback?
285  if(context->settings.addOptionsCallback != NULL)
286  {
287  //Invoke user callback function
288  context->settings.addOptionsCallback(context, message, &length,
290  }
291 
292  //The minimum length of BOOTP frames is 300 octets (refer to RFC 951,
293  //section 3)
295 
296  //Adjust the length of the multi-part buffer
297  netBufferSetLength(buffer, offset + length);
298 
299  //DHCP messages broadcast by a client prior to that client obtaining its
300  //IP address must have the source address field in the IP header set to 0
301  //(refer to RFC 2131, section 4.1)
302  srcIpAddr.length = sizeof(Ipv4Addr);
303  srcIpAddr.ipv4Addr = IPV4_UNSPECIFIED_ADDR;
304 
305  //Set destination IP address
306  destIpAddr.length = sizeof(Ipv4Addr);
307  destIpAddr.ipv4Addr = IPV4_BROADCAST_ADDR;
308 
309  //Debug message
310  TRACE_DEBUG("\r\n%s: Sending DHCP message (%" PRIuSIZE " bytes)...\r\n",
312 
313  //Dump the contents of the message for debugging purpose
315 
316  //Additional options can be passed to the stack along with the packet
317  ancillary = NET_DEFAULT_TX_ANCILLARY;
318 
319  //Broadcast DHCPDISCOVER message
320  error = udpSendBuffer(interface, &srcIpAddr, DHCP_CLIENT_PORT, &destIpAddr,
321  DHCP_SERVER_PORT, buffer, offset, &ancillary);
322 
323  //Free previously allocated memory
324  netBufferFree(buffer);
325 
326  //Return status code
327  return error;
328 }
329 
330 
331 /**
332  * @brief Send DHCPREQUEST message
333  * @param[in] context Pointer to the DHCP client context
334  * @return Error code
335  **/
336 
338 {
339  uint_t i;
340  error_t error;
341  size_t offset;
342  size_t length;
343  NetBuffer *buffer;
344  NetInterface *interface;
345  NetInterface *logicalInterface;
349  NetTxAncillary ancillary;
350 
351  //DHCP message type
352  const uint8_t type = DHCP_MSG_TYPE_REQUEST;
353 
354  //Point to the underlying network interface
355  interface = context->settings.interface;
356  //Point to the logical interface
357  logicalInterface = nicGetLogicalInterface(interface);
358 
359  //Index of the IP address in the list of addresses assigned to the interface
360  i = context->settings.ipAddrIndex;
361 
362  //Allocate a memory buffer to hold the DHCP message
363  buffer = udpAllocBuffer(DHCP_MAX_MSG_SIZE, &offset);
364  //Failed to allocate buffer?
365  if(buffer == NULL)
366  return ERROR_OUT_OF_MEMORY;
367 
368  //Point to the beginning of the DHCP message
369  message = netBufferAt(buffer, offset, 0);
370 
371  //Clear memory buffer contents
373 
374  //Format DHCPREQUEST message
377  message->hlen = sizeof(MacAddr);
378  message->xid = htonl(context->transactionId);
379  message->secs = dhcpClientComputeElapsedTime(context);
380 
381  //The client IP address must be included if the client is fully configured
382  //and can respond to ARP requests
383  if(context->state == DHCP_STATE_RENEWING ||
384  context->state == DHCP_STATE_REBINDING)
385  {
386  message->flags = 0;
387  message->ciaddr = interface->ipv4Context.addrList[i].addr;
388  }
389  else
390  {
392  message->ciaddr = IPV4_UNSPECIFIED_ADDR;
393  }
394 
395  //Client hardware address
396  message->chaddr = logicalInterface->macAddr;
397  //Write magic cookie before setting any option
398  message->magicCookie = HTONL(DHCP_MAGIC_COOKIE);
399  //Properly terminate the options field
400  message->options[0] = DHCP_OPT_END;
401 
402  //Total length of the DHCP message
403  length = sizeof(DhcpMessage) + sizeof(uint8_t);
404 
405  //DHCP Message Type option
407  &type, sizeof(type));
408 
409  //Server Identifier option
410  if(context->state == DHCP_STATE_REQUESTING)
411  {
413  &context->serverIpAddr, sizeof(Ipv4Addr));
414  }
415 
416  //Requested IP Address option
417  if(context->state == DHCP_STATE_REQUESTING ||
418  context->state == DHCP_STATE_REBOOTING)
419  {
421  &context->requestedIpAddr, sizeof(Ipv4Addr));
422  }
423 
424  //Any registered callback?
425  if(context->settings.addOptionsCallback != NULL)
426  {
427  //Invoke user callback function
428  context->settings.addOptionsCallback(context, message, &length,
430  }
431 
432  //Parameter Request List option
434  {
435  //Use the default list of requested options
437  dhcpOptionList, sizeof(dhcpOptionList));
438  }
439 
440  //The minimum length of BOOTP frames is 300 octets (refer to RFC 951,
441  //section 3)
443 
444  //Adjust the length of the multi-part buffer
445  netBufferSetLength(buffer, offset + length);
446 
447  //IP address is being renewed?
448  if(context->state == DHCP_STATE_RENEWING)
449  {
450  //Set source IP address
451  srcIpAddr.length = sizeof(Ipv4Addr);
452  srcIpAddr.ipv4Addr = interface->ipv4Context.addrList[i].addr;
453 
454  //The client transmits the message directly to the server that initially
455  //granted the lease
456  destIpAddr.length = sizeof(Ipv4Addr);
457  destIpAddr.ipv4Addr = context->serverIpAddr;
458  }
459  else
460  {
461  //DHCP messages broadcast by a client prior to that client obtaining its
462  //IP address must have the source address field in the IP header set to 0
463  //(refer to RFC 2131, section 4.1)
464  srcIpAddr.length = sizeof(Ipv4Addr);
465  srcIpAddr.ipv4Addr = IPV4_UNSPECIFIED_ADDR;
466 
467  //Broadcast the message
468  destIpAddr.length = sizeof(Ipv4Addr);
469  destIpAddr.ipv4Addr = IPV4_BROADCAST_ADDR;
470  }
471 
472  //Debug message
473  TRACE_DEBUG("\r\n%s: Sending DHCP message (%" PRIuSIZE " bytes)...\r\n",
475 
476  //Dump the contents of the message for debugging purpose
478 
479  //Additional options can be passed to the stack along with the packet
480  ancillary = NET_DEFAULT_TX_ANCILLARY;
481 
482  //Send DHCPREQUEST message
483  error = udpSendBuffer(interface, &srcIpAddr, DHCP_CLIENT_PORT, &destIpAddr,
484  DHCP_SERVER_PORT, buffer, offset, &ancillary);
485 
486  //Free previously allocated memory
487  netBufferFree(buffer);
488 
489  //Return status code
490  return error;
491 }
492 
493 
494 /**
495  * @brief Send DHCPDECLINE message
496  * @param[in] context Pointer to the DHCP client context
497  * @return Error code
498  **/
499 
501 {
502  error_t error;
503  size_t offset;
504  size_t length;
505  NetBuffer *buffer;
506  NetInterface *interface;
507  NetInterface *logicalInterface;
511  NetTxAncillary ancillary;
512 
513  //DHCP message type
514  const uint8_t type = DHCP_MSG_TYPE_DECLINE;
515 
516  //Point to the underlying network interface
517  interface = context->settings.interface;
518  //Point to the logical interface
519  logicalInterface = nicGetLogicalInterface(interface);
520 
521  //Allocate a memory buffer to hold the DHCP message
522  buffer = udpAllocBuffer(DHCP_MAX_MSG_SIZE, &offset);
523  //Failed to allocate buffer?
524  if(buffer == NULL)
525  return ERROR_OUT_OF_MEMORY;
526 
527  //Point to the beginning of the DHCP message
528  message = netBufferAt(buffer, offset, 0);
529 
530  //Clear memory buffer contents
532 
533  //Format DHCPDECLINE message
536  message->hlen = sizeof(MacAddr);
537  message->xid = htonl(context->transactionId);
538  message->secs = 0;
539  message->flags = 0;
540  message->ciaddr = IPV4_UNSPECIFIED_ADDR;
541  message->chaddr = logicalInterface->macAddr;
542 
543  //Write magic cookie before setting any option
544  message->magicCookie = HTONL(DHCP_MAGIC_COOKIE);
545  //Properly terminate the options field
546  message->options[0] = DHCP_OPT_END;
547 
548  //Total length of the DHCP message
549  length = sizeof(DhcpMessage) + sizeof(uint8_t);
550 
551  //DHCP Message Type option
553  &type, sizeof(type));
554 
555  //Server Identifier option
557  &context->serverIpAddr, sizeof(Ipv4Addr));
558 
559  //Requested IP Address option
561  &context->requestedIpAddr, sizeof(Ipv4Addr));
562 
563  //Any registered callback?
564  if(context->settings.addOptionsCallback != NULL)
565  {
566  //Invoke user callback function
567  context->settings.addOptionsCallback(context, message, &length,
569  }
570 
571  //The minimum length of BOOTP frames is 300 octets (refer to RFC 951,
572  //section 3)
574 
575  //Adjust the length of the multi-part buffer
576  netBufferSetLength(buffer, offset + length);
577 
578  //Use the unspecified address as source address
579  srcIpAddr.length = sizeof(Ipv4Addr);
580  srcIpAddr.ipv4Addr = IPV4_UNSPECIFIED_ADDR;
581 
582  //Set destination IP address
583  destIpAddr.length = sizeof(Ipv4Addr);
584  destIpAddr.ipv4Addr = IPV4_BROADCAST_ADDR;
585 
586  //Debug message
587  TRACE_DEBUG("\r\n%s: Sending DHCP message (%" PRIuSIZE " bytes)...\r\n",
589 
590  //Dump the contents of the message for debugging purpose
592 
593  //Additional options can be passed to the stack along with the packet
594  ancillary = NET_DEFAULT_TX_ANCILLARY;
595 
596  //Broadcast DHCPDECLINE message
597  error = udpSendBuffer(interface, &srcIpAddr, DHCP_CLIENT_PORT, &destIpAddr,
598  DHCP_SERVER_PORT, buffer, offset, &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->settings.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->settings.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->settings.addOptionsCallback != NULL)
679  {
680  //Invoke user callback function
681  context->settings.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(interface, &srcIpAddr, DHCP_CLIENT_PORT, &destIpAddr,
713  DHCP_SERVER_PORT, buffer, offset, &ancillary);
714 
715  //Free previously allocated memory
716  netBufferFree(buffer);
717 
718  //Return status code
719  return error;
720 }
721 
722 
723 /**
724  * @brief Process incoming DHCP message
725  * @param[in] interface Underlying network interface
726  * @param[in] pseudoHeader UDP pseudo header
727  * @param[in] udpHeader UDP header
728  * @param[in] buffer Multi-part buffer containing the incoming DHCP message
729  * @param[in] offset Offset to the first byte of the DHCP message
730  * @param[in] ancillary Additional options passed to the stack along with
731  * the packet
732  * @param[in] param Pointer to the DHCP client context
733  **/
734 
736  const IpPseudoHeader *pseudoHeader, const UdpHeader *udpHeader,
737  const NetBuffer *buffer, size_t offset, const NetRxAncillary *ancillary,
738  void *param)
739 {
740  size_t length;
741  DhcpClientContext *context;
743  DhcpOption *option;
744 
745  //Point to the DHCP client context
746  context = (DhcpClientContext *) param;
747 
748  //Retrieve the length of the DHCP message
749  length = netBufferGetLength(buffer) - offset;
750 
751  //Make sure the DHCP message is valid
752  if(length < sizeof(DhcpMessage) || length > DHCP_MAX_MSG_SIZE)
753  return;
754 
755  //Point to the beginning of the DHCP message
756  message = netBufferAt(buffer, offset, length);
757  //Sanity check
758  if(message == NULL)
759  return;
760 
761  //Debug message
762  TRACE_DEBUG("\r\n%s: DHCP message received (%" PRIuSIZE " bytes)...\r\n",
764 
765  //Dump the contents of the message for debugging purpose
767 
768  //The DHCP server shall respond with a BOOTREPLY opcode
769  if(message->op != DHCP_OPCODE_BOOTREPLY)
770  return;
771 
772  //Enforce hardware type
773  if(message->htype != DHCP_HARDWARE_TYPE_ETH)
774  return;
775 
776  //Check the length of the hardware address
777  if(message->hlen != sizeof(MacAddr))
778  return;
779 
780  //Check magic cookie
781  if(message->magicCookie != HTONL(DHCP_MAGIC_COOKIE))
782  return;
783 
784  //The DHCP Message Type option must be included in every DHCP message
786 
787  //Failed to retrieve the Message Type option?
788  if(option == NULL || option->length != 1)
789  return;
790 
791  //Check message type
792  switch(option->value[0])
793  {
794  case DHCP_MSG_TYPE_OFFER:
795  //Parse DHCPOFFER message
797  break;
798 
799  case DHCP_MSG_TYPE_ACK:
800  //Parse DHCPACK message
801  dhcpClientParseAck(context, message, length);
802  break;
803 
804  case DHCP_MSG_TYPE_NAK:
805  //Parse DHCPNAK message
806  dhcpClientParseNak(context, message, length);
807  break;
808 
809  default:
810  //Silently drop incoming message
811  break;
812  }
813 }
814 
815 
816 /**
817  * @brief Parse DHCPOFFER message
818  * @param[in] context Pointer to the DHCP client context
819  * @param[in] message Pointer to the incoming DHCP message
820  * @param[in] length Length of the incoming message to parse
821  **/
822 
824  const DhcpMessage *message, size_t length)
825 {
826  error_t error;
827  DhcpOption *serverIdOption;
828  NetInterface *interface;
829  NetInterface *logicalInterface;
830 
831  //Point to the underlying network interface
832  interface = context->settings.interface;
833  //Point to the logical interface
834  logicalInterface = nicGetLogicalInterface(interface);
835 
836  //Discard any received packet that does not match the transaction ID
837  if(ntohl(message->xid) != context->transactionId)
838  return;
839 
840  //Make sure the IP address offered to the client is valid
841  if(message->yiaddr == IPV4_UNSPECIFIED_ADDR)
842  return;
843 
844  //Check MAC address
845  if(!macCompAddr(&message->chaddr, &logicalInterface->macAddr))
846  return;
847 
848  //Make sure that the DHCPOFFER message is received in response to
849  //a DHCPDISCOVER message
850  if(context->state != DHCP_STATE_SELECTING)
851  return;
852 
853  //A DHCP server always returns its own address in the Server Identifier option
854  serverIdOption = dhcpGetOption(message, length, DHCP_OPT_SERVER_ID);
855 
856  //Failed to retrieve the Server Identifier option?
857  if(serverIdOption == NULL || serverIdOption->length != 4)
858  return;
859 
860  //Any registered callback?
861  if(context->settings.parseOptionsCallback != NULL)
862  {
863  //Invoke user callback function
864  error = context->settings.parseOptionsCallback(context, message, length,
866  //Check status code
867  if(error)
868  return;
869  }
870 
871  //Record the IP address of the DHCP server
872  ipv4CopyAddr(&context->serverIpAddr, serverIdOption->value);
873  //Record the IP address offered to the client
874  context->requestedIpAddr = message->yiaddr;
875 
876  //Switch to the REQUESTING state
878 }
879 
880 
881 /**
882  * @brief Parse DHCPACK message
883  * @param[in] context Pointer to the DHCP client context
884  * @param[in] message Pointer to the incoming DHCP message
885  * @param[in] length Length of the incoming message to parse
886  **/
887 
889  const DhcpMessage *message, size_t length)
890 {
891  error_t error;
892  uint_t i;
893  uint_t j;
894  uint_t n;
895  DhcpOption *option;
896  DhcpOption *serverIdOption;
897  NetInterface *interface;
898  NetInterface *logicalInterface;
899  NetInterface *physicalInterface;
900 
901  //Point to the underlying network interface
902  interface = context->settings.interface;
903  //Point to the logical interface
904  logicalInterface = nicGetLogicalInterface(interface);
905  //Point to the physical interface
906  physicalInterface = nicGetPhysicalInterface(interface);
907 
908  //Index of the IP address in the list of addresses assigned to the interface
909  i = context->settings.ipAddrIndex;
910 
911  //Discard any received packet that does not match the transaction ID
912  if(ntohl(message->xid) != context->transactionId)
913  return;
914 
915  //Make sure the IP address assigned to the client is valid
916  if(message->yiaddr == IPV4_UNSPECIFIED_ADDR)
917  return;
918 
919  //Check MAC address
920  if(!macCompAddr(&message->chaddr, &logicalInterface->macAddr))
921  return;
922 
923  //A DHCP server always returns its own address in the Server Identifier option
924  serverIdOption = dhcpGetOption(message, length, DHCP_OPT_SERVER_ID);
925 
926  //Failed to retrieve the Server Identifier option?
927  if(serverIdOption == NULL || serverIdOption->length != 4)
928  return;
929 
930  //Check current state
931  if(context->state == DHCP_STATE_SELECTING)
932  {
933  //A DHCPACK message is not acceptable when rapid commit is disallowed
934  if(!context->settings.rapidCommit)
935  return;
936 
937  //Search for the Rapid Commit option
939 
940  //A server must include this option in a DHCPACK message sent
941  //in a response to a DHCPDISCOVER message when completing the
942  //DHCPDISCOVER-DHCPACK message exchange
943  if(option == NULL || option->length != 0)
944  return;
945  }
946  else if(context->state == DHCP_STATE_REQUESTING ||
947  context->state == DHCP_STATE_RENEWING)
948  {
949  //Check the server identifier
950  if(!ipv4CompAddr(serverIdOption->value, &context->serverIpAddr))
951  return;
952  }
953  else if(context->state == DHCP_STATE_REBOOTING ||
954  context->state == DHCP_STATE_REBINDING)
955  {
956  //Do not check the server identifier
957  }
958  else
959  {
960  //Silently discard the DHCPACK message
961  return;
962  }
963 
964  //Retrieve IP Address Lease Time option
966 
967  //Failed to retrieve specified option?
968  if(option == NULL || option->length != 4)
969  return;
970 
971  //Any registered callback?
972  if(context->settings.parseOptionsCallback != NULL)
973  {
974  //Invoke user callback function
975  error = context->settings.parseOptionsCallback(context, message, length,
977  //Check status code
978  if(error)
979  return;
980  }
981 
982  //Record the lease time
983  context->leaseTime = LOAD32BE(option->value);
984 
985  //Retrieve Renewal Time Value option
987 
988  //Specified option found?
989  if(option != NULL && option->length == 4)
990  {
991  //This option specifies the time interval from address assignment
992  //until the client transitions to the RENEWING state
993  context->t1 = LOAD32BE(option->value);
994  }
995  else if(context->leaseTime != DHCP_INFINITE_TIME)
996  {
997  //By default, T1 is set to 50% of the lease time
998  context->t1 = context->leaseTime / 2;
999  }
1000  else
1001  {
1002  //Infinite lease
1003  context->t1 = DHCP_INFINITE_TIME;
1004  }
1005 
1006  //Retrieve Rebinding Time value option
1008 
1009  //Specified option found?
1010  if(option != NULL && option->length == 4)
1011  {
1012  //This option specifies the time interval from address assignment
1013  //until the client transitions to the REBINDING state
1014  context->t2 = LOAD32BE(option->value);
1015  }
1016  else if(context->leaseTime != DHCP_INFINITE_TIME)
1017  {
1018  //By default, T2 is set to 87.5% of the lease time
1019  context->t2 = context->leaseTime * 7 / 8;
1020  }
1021  else
1022  {
1023  //Infinite lease
1024  context->t2 = DHCP_INFINITE_TIME;
1025  }
1026 
1027  //Retrieve Subnet Mask option
1029 
1030  //Option found?
1031  if(option != NULL && option->length == sizeof(Ipv4Addr))
1032  {
1033  //Save subnet mask
1034  ipv4CopyAddr(&interface->ipv4Context.addrList[i].subnetMask,
1035  option->value);
1036  }
1037 
1038  //Retrieve Router option
1040 
1041  //Option found?
1042  if(option != NULL && !(option->length % sizeof(Ipv4Addr)))
1043  {
1044  //Save default gateway
1045  if(option->length >= sizeof(Ipv4Addr))
1046  {
1047  ipv4CopyAddr(&interface->ipv4Context.addrList[i].defaultGateway,
1048  option->value);
1049  }
1050  }
1051 
1052  //Automatic DNS server configuration?
1053  if(!context->settings.manualDnsConfig)
1054  {
1055  //Retrieve DNS Server option
1057 
1058  //Option found?
1059  if(option != NULL && !(option->length % sizeof(Ipv4Addr)))
1060  {
1061  //Get the number of addresses provided in the response
1062  n = option->length / sizeof(Ipv4Addr);
1063 
1064  //Loop through the list of addresses
1065  for(j = 0; j < n && j < IPV4_DNS_SERVER_LIST_SIZE; j++)
1066  {
1067  //Save DNS server address
1068  ipv4CopyAddr(&interface->ipv4Context.dnsServerList[j],
1069  option->value + j * sizeof(Ipv4Addr));
1070  }
1071  }
1072  }
1073 
1074  //Retrieve MTU option
1076 
1077  //Option found?
1078  if(option != NULL && option->length == 2)
1079  {
1080  //This option specifies the MTU to use on this interface
1081  n = LOAD16BE(option->value);
1082 
1083  //Make sure that the option's value is acceptable
1084  if(n >= IPV4_MINIMUM_MTU && n <= physicalInterface->nicDriver->mtu)
1085  {
1086  //Set the MTU to be used on the interface
1087  interface->ipv4Context.linkMtu = n;
1088  }
1089  }
1090 
1091  //Record the IP address of the DHCP server
1092  ipv4CopyAddr(&context->serverIpAddr, serverIdOption->value);
1093  //Record the IP address assigned to the client
1094  context->requestedIpAddr = message->yiaddr;
1095 
1096  //Save the time a which the lease was obtained
1097  context->leaseStartTime = osGetSystemTime();
1098 
1099  //Check current state
1100  if(context->state == DHCP_STATE_REQUESTING ||
1101  context->state == DHCP_STATE_REBOOTING)
1102  {
1103  //Use the IP address as a tentative address
1104  interface->ipv4Context.addrList[i].addr = message->yiaddr;
1105  interface->ipv4Context.addrList[i].state = IPV4_ADDR_STATE_TENTATIVE;
1106 
1107  //Clear conflict flag
1108  interface->ipv4Context.addrList[i].conflict = FALSE;
1109 
1110  //The client should probe the newly received address
1112  }
1113  else
1114  {
1115  //Assign the IP address to the client
1116  interface->ipv4Context.addrList[i].addr = message->yiaddr;
1117  interface->ipv4Context.addrList[i].state = IPV4_ADDR_STATE_VALID;
1118 
1119 #if (MDNS_RESPONDER_SUPPORT == ENABLED)
1120  //Restart mDNS probing process
1121  mdnsResponderStartProbing(interface->mdnsResponderContext);
1122 #endif
1123  //The client transitions to the BOUND state
1125  }
1126 }
1127 
1128 
1129 /**
1130  * @brief Parse DHCPNAK message
1131  * @param[in] context Pointer to the DHCP client context
1132  * @param[in] message Pointer to the incoming DHCP message
1133  * @param[in] length Length of the incoming message to parse
1134  **/
1135 
1137  const DhcpMessage *message, size_t length)
1138 {
1139  error_t error;
1140  DhcpOption *serverIdOption;
1141  NetInterface *interface;
1142  NetInterface *logicalInterface;
1143 
1144  //Point to the underlying network interface
1145  interface = context->settings.interface;
1146  //Point to the logical interface
1147  logicalInterface = nicGetLogicalInterface(interface);
1148 
1149  //Discard any received packet that does not match the transaction ID
1150  if(ntohl(message->xid) != context->transactionId)
1151  return;
1152 
1153  //Check MAC address
1154  if(!macCompAddr(&message->chaddr, &logicalInterface->macAddr))
1155  return;
1156 
1157  //A DHCP server always returns its own address in the Server Identifier option
1158  serverIdOption = dhcpGetOption(message, length, DHCP_OPT_SERVER_ID);
1159 
1160  //Failed to retrieve the Server Identifier option?
1161  if(serverIdOption == NULL || serverIdOption->length != 4)
1162  return;
1163 
1164  //Check current state
1165  if(context->state == DHCP_STATE_REQUESTING ||
1166  context->state == DHCP_STATE_RENEWING)
1167  {
1168  //Check the server identifier
1169  if(!ipv4CompAddr(serverIdOption->value, &context->serverIpAddr))
1170  return;
1171  }
1172  else if(context->state == DHCP_STATE_REBOOTING ||
1173  context->state == DHCP_STATE_REBINDING)
1174  {
1175  //Do not check the server identifier
1176  }
1177  else
1178  {
1179  //Silently discard the DHCPNAK message
1180  return;
1181  }
1182 
1183  //Any registered callback?
1184  if(context->settings.parseOptionsCallback != NULL)
1185  {
1186  //Invoke user callback function
1187  error = context->settings.parseOptionsCallback(context, message, length,
1189  //Check status code
1190  if(error)
1191  return;
1192  }
1193 
1194  //The host address is no longer appropriate for the link
1195  dhcpClientResetConfig(context);
1196 
1197 #if (MDNS_RESPONDER_SUPPORT == ENABLED)
1198  //Restart mDNS probing process
1199  mdnsResponderStartProbing(interface->mdnsResponderContext);
1200 #endif
1201 
1202  //Restart DHCP configuration
1204 }
1205 
1206 
1207 /**
1208  * @brief Manage DHCP configuration timeout
1209  * @param[in] context Pointer to the DHCP client context
1210  **/
1211 
1213 {
1214  systime_t time;
1215  NetInterface *interface;
1216 
1217  //Point to the underlying network interface
1218  interface = context->settings.interface;
1219 
1220  //Get current time
1221  time = osGetSystemTime();
1222 
1223  //Any registered callback?
1224  if(context->settings.timeoutEvent != NULL)
1225  {
1226  //DHCP configuration timeout?
1227  if(timeCompare(time, context->configStartTime + context->settings.timeout) >= 0)
1228  {
1229  //Ensure the callback function is only called once
1230  if(!context->timeoutEventDone)
1231  {
1232  //Release exclusive access
1234  //Invoke user callback function
1235  context->settings.timeoutEvent(context, interface);
1236  //Get exclusive access
1238 
1239  //Set flag
1240  context->timeoutEventDone = TRUE;
1241  }
1242  }
1243  }
1244 }
1245 
1246 
1247 /**
1248  * @brief Compute the appropriate secs field
1249  *
1250  * Compute the number of seconds elapsed since the client began address
1251  * acquisition or renewal process
1252  *
1253  * @param[in] context Pointer to the DHCP client context
1254  * @return The elapsed time expressed in seconds
1255  **/
1256 
1258 {
1259  systime_t time;
1260 
1261  //Compute the time elapsed since the DHCP configuration process started
1262  time = (osGetSystemTime() - context->configStartTime) / 1000;
1263 
1264  //The value 0xFFFF is used to represent any elapsed time values
1265  //greater than the largest time value that can be represented
1266  time = MIN(time, 0xFFFF);
1267 
1268  //Convert the 16-bit value to network byte order
1269  return htons(time);
1270 }
1271 
1272 
1273 /**
1274  * @brief Update DHCP FSM state
1275  * @param[in] context Pointer to the DHCP client context
1276  * @param[in] newState New DHCP state to switch to
1277  * @param[in] delay Initial delay
1278  **/
1279 
1281  DhcpState newState, systime_t delay)
1282 {
1283  systime_t time;
1284 
1285  //Get current time
1286  time = osGetSystemTime();
1287 
1288 #if (DHCP_TRACE_LEVEL >= TRACE_LEVEL_INFO)
1289  //Sanity check
1290  if(newState <= DHCP_STATE_REBINDING)
1291  {
1292  //DHCP FSM states
1293  static const char_t *const stateLabel[] =
1294  {
1295  "INIT",
1296  "SELECTING",
1297  "REQUESTING",
1298  "INIT-REBOOT",
1299  "REBOOTING",
1300  "PROBING",
1301  "ANNOUNCING",
1302  "BOUND",
1303  "RENEWING",
1304  "REBINDING"
1305  };
1306 
1307  //Debug message
1308  TRACE_INFO("%s: DHCP client %s state\r\n",
1309  formatSystemTime(time, NULL), stateLabel[newState]);
1310  }
1311 #endif
1312 
1313  //Set time stamp
1314  context->timestamp = time;
1315  //Set initial delay
1316  context->timeout = delay;
1317  //Reset retransmission counter
1318  context->retransmitCount = 0;
1319  //Switch to the new state
1320  context->state = newState;
1321 
1322  //Any registered callback?
1323  if(context->settings.stateChangeEvent != NULL)
1324  {
1325  NetInterface *interface;
1326 
1327  //Point to the underlying network interface
1328  interface = context->settings.interface;
1329 
1330  //Release exclusive access
1332  //Invoke user callback function
1333  context->settings.stateChangeEvent(context, interface, newState);
1334  //Get exclusive access
1336  }
1337 }
1338 
1339 
1340 /**
1341  * @brief Reset DHCP configuration
1342  * @param[in] context Pointer to the DHCP client context
1343  **/
1344 
1346 {
1347  uint_t i;
1348  uint_t j;
1349  NetInterface *interface;
1350 
1351  //Point to the underlying network interface
1352  interface = context->settings.interface;
1353  //Index of the IP address in the list of addresses assigned to the interface
1354  i = context->settings.ipAddrIndex;
1355 
1356  //The host address is not longer valid
1357  interface->ipv4Context.addrList[i].addr = IPV4_UNSPECIFIED_ADDR;
1358  interface->ipv4Context.addrList[i].state = IPV4_ADDR_STATE_INVALID;
1359 
1360  //Clear subnet mask
1361  interface->ipv4Context.addrList[i].subnetMask = IPV4_UNSPECIFIED_ADDR;
1362 
1363  //The default gateway is no longer valid
1364  interface->ipv4Context.addrList[i].defaultGateway = IPV4_UNSPECIFIED_ADDR;
1365 
1366  //Automatic DNS server configuration?
1367  if(!context->settings.manualDnsConfig)
1368  {
1369  //Loop through the list of DNS servers
1370  for(j = 0; j < IPV4_DNS_SERVER_LIST_SIZE; j++)
1371  {
1372  //The DNS server is no longer valid
1373  interface->ipv4Context.dnsServerList[j] = IPV4_UNSPECIFIED_ADDR;
1374  }
1375  }
1376 }
1377 
1378 
1379 /**
1380  * @brief Dump DHCP configuration for debugging purpose
1381  * @param[in] context Pointer to the DHCP client context
1382  **/
1383 
1385 {
1386 #if (DHCP_TRACE_LEVEL >= TRACE_LEVEL_INFO)
1387  uint_t i;
1388  uint_t j;
1389  NetInterface *interface;
1390  Ipv4Context *ipv4Context;
1391 
1392  //Point to the underlying network interface
1393  interface = context->settings.interface;
1394  //Point to the IPv4 context
1395  ipv4Context = &interface->ipv4Context;
1396 
1397  //Index of the IP address in the list of addresses assigned to the interface
1398  i = context->settings.ipAddrIndex;
1399 
1400  //Debug message
1401  TRACE_INFO("\r\n");
1402  TRACE_INFO("DHCP configuration:\r\n");
1403 
1404  //Lease start time
1405  TRACE_INFO(" Lease Start Time = %s\r\n",
1406  formatSystemTime(context->leaseStartTime, NULL));
1407 
1408  //Lease time
1409  TRACE_INFO(" Lease Time = %" PRIu32 "s\r\n", context->leaseTime);
1410  //Renewal time
1411  TRACE_INFO(" T1 = %" PRIu32 "s\r\n", context->t1);
1412  //Rebinding time
1413  TRACE_INFO(" T2 = %" PRIu32 "s\r\n", context->t2);
1414 
1415  //Host address
1416  TRACE_INFO(" IPv4 Address = %s\r\n",
1417  ipv4AddrToString(ipv4Context->addrList[i].addr, NULL));
1418 
1419  //Subnet mask
1420  TRACE_INFO(" Subnet Mask = %s\r\n",
1421  ipv4AddrToString(ipv4Context->addrList[i].subnetMask, NULL));
1422 
1423  //Default gateway
1424  TRACE_INFO(" Default Gateway = %s\r\n",
1425  ipv4AddrToString(ipv4Context->addrList[i].defaultGateway, NULL));
1426 
1427  //DNS servers
1428  for(j = 0; j < IPV4_DNS_SERVER_LIST_SIZE; j++)
1429  {
1430  TRACE_INFO(" DNS Server %u = %s\r\n", j + 1,
1431  ipv4AddrToString(ipv4Context->dnsServerList[j], NULL));
1432  }
1433 
1434  //Maximum transmit unit
1435  TRACE_INFO(" MTU = %" PRIuSIZE "\r\n", interface->ipv4Context.linkMtu);
1436  TRACE_INFO("\r\n");
1437 #endif
1438 }
1439 
1440 #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
DHCP client (Dynamic Host Configuration Protocol)
error_t dhcpClientSendRelease(DhcpClientContext *context)
Send DHCPRELEASE message.
const NetTxAncillary NET_DEFAULT_TX_ANCILLARY
Definition: net_misc.c:71
#define netMutex
Definition: net_legacy.h:195
#define LOAD32BE(p)
Definition: cpu_endian.h:210
@ 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:297
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:426
@ 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.
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:85
#define HTONL(value)
Definition: cpu_endian.h:411
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:203
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:76
#define NetRxAncillary
Definition: net_misc.h:40
#define NetInterface
Definition: net.h:36
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
error_t udpSendBuffer(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:658
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
@ 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:95
uint8_t length
Definition: tcp.h:368
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:119
MacAddr
Definition: ethernet.h:195
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:107
#define MAX(a, b)
Definition: os_port.h:67
char char_t
Definition: compiler_port.h:48
@ 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
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:159
@ 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
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
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:202
#define DHCP_SERVER_PORT
Definition: dhcp_common.h:40
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
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
systime_t dhcpClientTickCounter
#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:155
@ 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:204
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:50
#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:135
TCP/IP stack core.
NetInterface * nicGetLogicalInterface(NetInterface *interface)
Retrieve logical interface.
Definition: nic.c:53
#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:1457
#define IPV4_MINIMUM_MTU
Definition: ipv4.h:98
@ 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:117
mDNS responder (Multicast DNS)
systime_t osGetSystemTime(void)
Retrieve system time.
Ipv4Addr destIpAddr
Definition: ipcp.h:80