dhcp_client.c
Go to the documentation of this file.
1 /**
2  * @file dhcp_client.c
3  * @brief DHCP client (Dynamic Host Configuration Protocol)
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2020 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  * @section Description
28  *
29  * The Dynamic Host Configuration Protocol is used to provide configuration
30  * parameters to hosts. Refer to the following RFCs for complete details:
31  * - RFC 2131: Dynamic Host Configuration Protocol
32  * - RFC 2132: DHCP Options and BOOTP Vendor Extensions
33  * - RFC 4039: Rapid Commit Option for the DHCP version 4
34  *
35  * @author Oryx Embedded SARL (www.oryx-embedded.com)
36  * @version 1.9.8
37  **/
38 
39 //Switch to the appropriate trace level
40 #define TRACE_LEVEL DHCP_TRACE_LEVEL
41 
42 //Dependencies
43 #include "core/net.h"
44 #include "dhcp/dhcp_client.h"
45 #include "dhcp/dhcp_common.h"
46 #include "dhcp/dhcp_debug.h"
47 #include "mdns/mdns_responder.h"
48 #include "date_time.h"
49 #include "debug.h"
50 
51 //Check TCP/IP stack configuration
52 #if (IPV4_SUPPORT == ENABLED && DHCP_CLIENT_SUPPORT == ENABLED)
53 
54 //Tick counter to handle periodic operations
56 
57 //Requested DHCP options
58 const uint8_t dhcpOptionList[] =
59 {
67 };
68 
69 
70 /**
71  * @brief Initialize settings with default values
72  * @param[out] settings Structure that contains DHCP client settings
73  **/
74 
76 {
77  //Use default interface
78  settings->interface = netGetDefaultInterface();
79  //Index of the IP address to be configured
80  settings->ipAddrIndex = 0;
81 
82 #if (DHCP_CLIENT_HOSTNAME_OPTION_SUPPORT == ENABLED)
83  //Use default host name
84  osStrcpy(settings->hostname, "");
85 #endif
86 
87 #if (DHCP_CLIENT_ID_OPTION_SUPPORT == ENABLED)
88  //Use default client identifier
89  settings->clientIdLength = 0;
90 #endif
91 
92  //Support for quick configuration using rapid commit
93  settings->rapidCommit = FALSE;
94  //Use the DNS servers provided by the DHCP server
95  settings->manualDnsConfig = FALSE;
96  //DHCP configuration timeout
97  settings->timeout = 0;
98  //DHCP configuration timeout event
99  settings->timeoutEvent = NULL;
100  //Link state change event
101  settings->linkChangeEvent = NULL;
102  //FSM state change event
103  settings->stateChangeEvent = NULL;
104 }
105 
106 
107 /**
108  * @brief DHCP client initialization
109  * @param[in] context Pointer to the DHCP client context
110  * @param[in] settings DHCP client specific settings
111  * @return Error code
112  **/
113 
115 {
116  error_t error;
117  size_t n;
119 
120  //Debug message
121  TRACE_INFO("Initializing DHCP client...\r\n");
122 
123  //Ensure the parameters are valid
124  if(context == NULL || settings == NULL)
126 
127  //The DHCP client must be bound to a valid interface
128  if(settings->interface == NULL)
130 
131  //Point to the underlying network interface
132  interface = settings->interface;
133 
134  //Clear the DHCP client context
135  osMemset(context, 0, sizeof(DhcpClientContext));
136  //Save user settings
137  context->settings = *settings;
138 
139 #if (DHCP_CLIENT_HOSTNAME_OPTION_SUPPORT == ENABLED)
140  //No DHCP host name defined?
141  if(settings->hostname[0] == '\0')
142  {
143  //Use default host name
144  n = osStrlen(interface->hostname);
145  //Limit the length of the string
147 
148  //Copy host name
149  osStrncpy(context->settings.hostname, interface->hostname, n);
150  //Properly terminate the string with a NULL character
151  context->settings.hostname[n] = '\0';
152  }
153 #endif
154 
155  //Callback function to be called when a DHCP message is received
156  error = udpAttachRxCallback(interface, DHCP_CLIENT_PORT,
157  dhcpClientProcessMessage, context);
158  //Failed to register callback function?
159  if(error)
160  return error;
161 
162  //DHCP client is currently suspended
163  context->running = FALSE;
164  //Initialize state machine
165  context->state = DHCP_STATE_INIT;
166 
167  //Attach the DHCP client context to the network interface
168  interface->dhcpClientContext = context;
169 
170  //Successful initialization
171  return NO_ERROR;
172 }
173 
174 
175 /**
176  * @brief Start DHCP client
177  * @param[in] context Pointer to the DHCP client context
178  * @return Error code
179  **/
180 
182 {
183  uint_t i;
184  NetInterface *interface;
185 
186  //Make sure the DHCP client context is valid
187  if(context == NULL)
189 
190  //Debug message
191  TRACE_INFO("Starting DHCP client...\r\n");
192 
193  //Get exclusive access
195 
196  //Point to the underlying network interface
197  interface = context->settings.interface;
198  //Index of the IP address in the list of addresses assigned to the interface
199  i = context->settings.ipAddrIndex;
200 
201  //The host address is not longer valid
202  interface->ipv4Context.addrList[i].addr = IPV4_UNSPECIFIED_ADDR;
203  interface->ipv4Context.addrList[i].state = IPV4_ADDR_STATE_INVALID;
204 
205  //Clear subnet mask
206  interface->ipv4Context.addrList[i].subnetMask = IPV4_UNSPECIFIED_ADDR;
207 
208  //Start DHCP client
209  context->running = TRUE;
210  //Initialize state machine
211  context->state = DHCP_STATE_INIT;
212 
213  //Release exclusive access
215 
216  //Successful processing
217  return NO_ERROR;
218 }
219 
220 
221 /**
222  * @brief Stop DHCP client
223  * @param[in] context Pointer to the DHCP client context
224  * @return Error code
225  **/
226 
228 {
229  //Make sure the DHCP client context is valid
230  if(context == NULL)
232 
233  //Debug message
234  TRACE_INFO("Stopping DHCP client...\r\n");
235 
236  //Get exclusive access
238 
239  //Stop DHCP client
240  context->running = FALSE;
241  //Reinitialize state machine
242  context->state = DHCP_STATE_INIT;
243 
244  //Release exclusive access
246 
247  //Successful processing
248  return NO_ERROR;
249 }
250 
251 
252 /**
253  * @brief Retrieve current state
254  * @param[in] context Pointer to the DHCP client context
255  * @return Current DHCP client state
256  **/
257 
259 {
260  DhcpState state;
261 
262  //Get exclusive access
264  //Get current state
265  state = context->state;
266  //Release exclusive access
268 
269  //Return current state
270  return state;
271 }
272 
273 
274 /**
275  * @brief DHCP client timer handler
276  *
277  * This routine must be periodically called by the TCP/IP stack to
278  * manage DHCP client operation
279  *
280  * @param[in] context Pointer to the DHCP client context
281  **/
282 
283 
285 {
286  //Make sure the DHCP client has been properly instantiated
287  if(context == NULL)
288  return;
289 
290  //DHCP client finite state machine
291  switch(context->state)
292  {
293  //Process INIT state
294  case DHCP_STATE_INIT:
295  //This is the initialization state, where a client begins the process of
296  //acquiring a lease. It also returns here when a lease ends, or when a
297  //lease negotiation fails
298  dhcpClientStateInit(context);
299  break;
300  //Process SELECTING state
302  //The client is waiting to receive DHCPOFFER messages from one or more
303  //DHCP servers, so it can choose one
304  dhcpClientStateSelecting(context);
305  break;
306  //Process REQUESTING state
308  //The client is waiting to hear back from the server to which
309  //it sent its request
310  dhcpClientStateRequesting(context);
311  break;
312  //Process INIT REBOOT state
314  //When a client that already has a valid lease starts up after a
315  //power-down or reboot, it starts here instead of the INIT state
316  dhcpClientStateInitReboot(context);
317  break;
318  //Process REBOOTING state
320  //A client that has rebooted with an assigned address is waiting for
321  //a confirming reply from a server
322  dhcpClientStateRebooting(context);
323  break;
324  //Process PROBING state
325  case DHCP_STATE_PROBING:
326  //The client probes the newly received address
327  dhcpClientStateProbing(context);
328  break;
329  //Process BOUND state
330  case DHCP_STATE_BOUND:
331  //Client has a valid lease and is in its normal operating state
332  dhcpClientStateBound(context);
333  break;
334  //Process RENEWING state
335  case DHCP_STATE_RENEWING:
336  //Client is trying to renew its lease. It regularly sends DHCPREQUEST messages with
337  //the server that gave it its current lease specified, and waits for a reply
338  dhcpClientStateRenewing(context);
339  break;
340  //Process REBINDING state
342  //The client has failed to renew its lease with the server that originally granted it,
343  //and now seeks a lease extension with any server that can hear it. It periodically sends
344  //DHCPREQUEST messages with no server specified until it gets a reply or the lease ends
345  dhcpClientStateRebinding(context);
346  break;
347  //Invalid state...
348  default:
349  //Switch to the INIT state
350  context->state = DHCP_STATE_INIT;
351  break;
352  }
353 }
354 
355 
356 /**
357  * @brief Callback function for link change event
358  * @param[in] context Pointer to the DHCP client context
359  **/
360 
362 {
363  uint_t i;
364  NetInterface *interface;
365 
366  //Make sure the DHCP client has been properly instantiated
367  if(context == NULL)
368  return;
369 
370  //Point to the underlying network interface
371  interface = context->settings.interface;
372  //Index of the IP address in the list of addresses assigned to the interface
373  i = context->settings.ipAddrIndex;
374 
375  //Check whether the DHCP client is running
376  if(context->running)
377  {
378  //The host address is no longer valid
379  interface->ipv4Context.addrList[i].addr = IPV4_UNSPECIFIED_ADDR;
380  interface->ipv4Context.addrList[i].state = IPV4_ADDR_STATE_INVALID;
381 
382  //Clear subnet mask
383  interface->ipv4Context.addrList[i].subnetMask = IPV4_UNSPECIFIED_ADDR;
384 
385 #if (MDNS_RESPONDER_SUPPORT == ENABLED)
386  //Restart mDNS probing process
387  mdnsResponderStartProbing(interface->mdnsResponderContext);
388 #endif
389  }
390 
391  //Check whether the client already has a valid lease
392  if(context->state >= DHCP_STATE_INIT_REBOOT)
393  {
394  //Switch to the INIT-REBOOT state
395  context->state = DHCP_STATE_INIT_REBOOT;
396  }
397  else
398  {
399  //Switch to the INIT state
400  context->state = DHCP_STATE_INIT;
401  }
402 
403  //Any registered callback?
404  if(context->settings.linkChangeEvent != NULL)
405  {
406  //Release exclusive access
408  //Invoke user callback function
409  context->settings.linkChangeEvent(context, interface, interface->linkState);
410  //Get exclusive access
412  }
413 }
414 
415 
416 /**
417  * @brief INIT state
418  *
419  * This is the initialization state, where a client begins the process of
420  * acquiring a lease. It also returns here when a lease ends, or when a
421  * lease negotiation fails
422  *
423  * @param[in] context Pointer to the DHCP client context
424  **/
425 
427 {
428  systime_t delay;
429  NetInterface *interface;
430 
431  //Point to the underlying network interface
432  interface = context->settings.interface;
433 
434  //Check whether the DHCP client is running
435  if(context->running)
436  {
437  //Wait for the link to be up before starting DHCP configuration
438  if(interface->linkState)
439  {
440  //The client should wait for a random time to desynchronize
441  //the use of DHCP at startup
443 
444  //Record the time at which the client started the address
445  //acquisition process
446  context->configStartTime = osGetSystemTime();
447  //Clear flag
448  context->timeoutEventDone = FALSE;
449 
450  //Switch to the SELECTING state
452  }
453  }
454 }
455 
456 
457 /**
458  * @brief SELECTING state
459  *
460  * The client is waiting to receive DHCPOFFER messages from
461  * one or more DHCP servers, so it can choose one
462  *
463  * @param[in] context Pointer to the DHCP client context
464  **/
465 
467 {
468  systime_t time;
469 
470  //Get current time
471  time = osGetSystemTime();
472 
473  //Check current time
474  if(timeCompare(time, context->timestamp + context->timeout) >= 0)
475  {
476  //Check retransmission counter
477  if(context->retransmitCount == 0)
478  {
479  //A transaction identifier is used by the client to
480  //match incoming DHCP messages with pending requests
481  context->transactionId = netGetRand();
482 
483  //Send a DHCPDISCOVER message
484  dhcpClientSendDiscover(context);
485 
486  //Initial timeout value
487  context->retransmitTimeout = DHCP_CLIENT_DISCOVER_INIT_RT;
488  }
489  else
490  {
491  //Send a DHCPDISCOVER message
492  dhcpClientSendDiscover(context);
493 
494  //The timeout value is doubled for each subsequent retransmission
495  context->retransmitTimeout *= 2;
496 
497  //Limit the timeout value to a maximum of 64 seconds
498  if(context->retransmitTimeout > DHCP_CLIENT_DISCOVER_MAX_RT)
499  context->retransmitTimeout = DHCP_CLIENT_DISCOVER_MAX_RT;
500  }
501 
502  //Save the time at which the message was sent
503  context->timestamp = time;
504 
505  //The timeout value should be randomized by the value of a uniform
506  //number chosen from the range -1 to +1
507  context->timeout = context->retransmitTimeout +
509 
510  //Increment retransmission counter
511  context->retransmitCount++;
512  }
513 
514  //Manage DHCP configuration timeout
515  dhcpClientCheckTimeout(context);
516 }
517 
518 
519 /**
520  * @brief REQUESTING state
521  *
522  * The client is waiting to hear back from the server
523  * to which it sent its request
524  *
525  * @param[in] context Pointer to the DHCP client context
526  **/
527 
529 {
530  systime_t time;
531 
532  //Get current time
533  time = osGetSystemTime();
534 
535  //Check current time
536  if(timeCompare(time, context->timestamp + context->timeout) >= 0)
537  {
538  //Check retransmission counter
539  if(context->retransmitCount == 0)
540  {
541  //A transaction identifier is used by the client to
542  //match incoming DHCP messages with pending requests
543  context->transactionId = netGetRand();
544 
545  //Send a DHCPREQUEST message
546  dhcpClientSendRequest(context);
547 
548  //Initial timeout value
549  context->retransmitTimeout = DHCP_CLIENT_REQUEST_INIT_RT;
550 
551  //Save the time at which the message was sent
552  context->timestamp = time;
553 
554  //The timeout value should be randomized by the value of a uniform
555  //number chosen from the range -1 to +1
556  context->timeout = context->retransmitTimeout +
558 
559  //Increment retransmission counter
560  context->retransmitCount++;
561  }
562  else if(context->retransmitCount < DHCP_CLIENT_REQUEST_MAX_RC)
563  {
564  //Send a DHCPREQUEST message
565  dhcpClientSendRequest(context);
566 
567  //The timeout value is doubled for each subsequent retransmission
568  context->retransmitTimeout *= 2;
569 
570  //Limit the timeout value to a maximum of 64 seconds
571  if(context->retransmitTimeout > DHCP_CLIENT_REQUEST_MAX_RT)
572  context->retransmitTimeout = DHCP_CLIENT_REQUEST_MAX_RT;
573 
574  //Save the time at which the message was sent
575  context->timestamp = time;
576 
577  //The timeout value should be randomized by the value of a uniform
578  //number chosen from the range -1 to +1
579  context->timeout = context->retransmitTimeout +
581 
582  //Increment retransmission counter
583  context->retransmitCount++;
584  }
585  else
586  {
587  //If the client does not receive a response within a reasonable
588  //period of time, then it restarts the initialization procedure
590  }
591  }
592 
593  //Manage DHCP configuration timeout
594  dhcpClientCheckTimeout(context);
595 }
596 
597 
598 /**
599  * @brief INIT-REBOOT state
600  *
601  * When a client that already has a valid lease starts up after a
602  * power-down or reboot, it starts here instead of the INIT state
603  *
604  * @param[in] context Pointer to the DHCP client context
605  **/
606 
608 {
609  systime_t delay;
610  NetInterface *interface;
611 
612  //Point to the underlying network interface
613  interface = context->settings.interface;
614 
615  //Check whether the DHCP client is running
616  if(context->running)
617  {
618  //Wait for the link to be up before starting DHCP configuration
619  if(interface->linkState)
620  {
621  //The client should wait for a random time to desynchronize
622  //the use of DHCP at startup
624 
625  //Record the time at which the client started the address
626  //acquisition process
627  context->configStartTime = osGetSystemTime();
628  //Clear flag
629  context->timeoutEventDone = FALSE;
630 
631  //Switch to the REBOOTING state
633  }
634  }
635 }
636 
637 
638 /**
639  * @brief REBOOTING state
640  *
641  * A client that has rebooted with an assigned address is
642  * waiting for a confirming reply from a server
643  *
644  * @param[in] context Pointer to the DHCP client context
645  **/
646 
648 {
649  systime_t time;
650 
651  //Get current time
652  time = osGetSystemTime();
653 
654  //Check current time
655  if(timeCompare(time, context->timestamp + context->timeout) >= 0)
656  {
657  //Check retransmission counter
658  if(context->retransmitCount == 0)
659  {
660  //A transaction identifier is used by the client to
661  //match incoming DHCP messages with pending requests
662  context->transactionId = netGetRand();
663 
664  //Send a DHCPREQUEST message
665  dhcpClientSendRequest(context);
666 
667  //Initial timeout value
668  context->retransmitTimeout = DHCP_CLIENT_REQUEST_INIT_RT;
669 
670  //Save the time at which the message was sent
671  context->timestamp = time;
672 
673  //The timeout value should be randomized by the value of a uniform
674  //number chosen from the range -1 to +1
675  context->timeout = context->retransmitTimeout +
677 
678  //Increment retransmission counter
679  context->retransmitCount++;
680  }
681  else if(context->retransmitCount < DHCP_CLIENT_REQUEST_MAX_RC)
682  {
683  //Send a DHCPREQUEST message
684  dhcpClientSendRequest(context);
685 
686  //The timeout value is doubled for each subsequent retransmission
687  context->retransmitTimeout *= 2;
688 
689  //Limit the timeout value to a maximum of 64 seconds
690  if(context->retransmitTimeout > DHCP_CLIENT_REQUEST_MAX_RT)
691  context->retransmitTimeout = DHCP_CLIENT_REQUEST_MAX_RT;
692 
693  //Save the time at which the message was sent
694  context->timestamp = time;
695 
696  //The timeout value should be randomized by the value of a uniform
697  //number chosen from the range -1 to +1
698  context->timeout = context->retransmitTimeout +
700 
701  //Increment retransmission counter
702  context->retransmitCount++;
703  }
704  else
705  {
706  //If the client does not receive a response within a reasonable
707  //period of time, then it restarts the initialization procedure
709  }
710  }
711 
712  //Manage DHCP configuration timeout
713  dhcpClientCheckTimeout(context);
714 }
715 
716 
717 /**
718  * @brief PROBING state
719  *
720  * The client probes the newly received address
721  *
722  * @param[in] context Pointer to the DHCP client context
723  **/
724 
726 {
727  uint_t i;
728  systime_t time;
729  NetInterface *interface;
730 
731  //Point to the underlying network interface
732  interface = context->settings.interface;
733  //Index of the IP address in the list of addresses assigned to the interface
734  i = context->settings.ipAddrIndex;
735 
736  //Get current time
737  time = osGetSystemTime();
738 
739  //Check current time
740  if(timeCompare(time, context->timestamp + context->timeout) >= 0)
741  {
742  //The address is already in use?
743  if(interface->ipv4Context.addrList[i].conflict)
744  {
745  //If the client detects that the address is already in use, the
746  //client must send a DHCPDECLINE message to the server and
747  //restarts the configuration process
748  dhcpClientSendDecline(context);
749 
750  //The client should wait a minimum of ten seconds before
751  //restarting the configuration process to avoid excessive
752  //network traffic in case of looping
754  }
755  //Probing is on-going?
756  else if(context->retransmitCount < DHCP_CLIENT_PROBE_NUM)
757  {
758  //Conflict detection is done using ARP probes
759  arpSendProbe(interface, interface->ipv4Context.addrList[i].addr);
760 
761  //Save the time at which the packet was sent
762  context->timestamp = time;
763  //Delay until repeated probe
764  context->timeout = DHCP_CLIENT_PROBE_DELAY;
765  //Increment retransmission counter
766  context->retransmitCount++;
767  }
768  //Probing is complete?
769  else
770  {
771  //The use of the IPv4 address is now unrestricted
772  interface->ipv4Context.addrList[i].state = IPV4_ADDR_STATE_VALID;
773 
774 #if (MDNS_RESPONDER_SUPPORT == ENABLED)
775  //Restart mDNS probing process
776  mdnsResponderStartProbing(interface->mdnsResponderContext);
777 #endif
778  //Dump current DHCP configuration for debugging purpose
779  dhcpClientDumpConfig(context);
780 
781  //The client transitions to the BOUND state
783  }
784  }
785 }
786 
787 
788 /**
789  * @brief BOUND state
790  *
791  * Client has a valid lease and is in its normal operating state
792  *
793  * @param[in] context Pointer to the DHCP client context
794  **/
795 
797 {
798  systime_t t1;
799  systime_t time;
800 
801  //Get current time
802  time = osGetSystemTime();
803 
804  //A client will never attempt to extend the lifetime
805  //of the address when T1 set to 0xFFFFFFFF
806  if(context->t1 != DHCP_INFINITE_TIME)
807  {
808  //Convert T1 to milliseconds
809  if(context->t1 < (MAX_DELAY / 1000))
810  t1 = context->t1 * 1000;
811  else
812  t1 = MAX_DELAY;
813 
814  //Check the time elapsed since the lease was obtained
815  if(timeCompare(time, context->leaseStartTime + t1) >= 0)
816  {
817  //Record the time at which the client started the address renewal process
818  context->configStartTime = time;
819 
820  //Enter the RENEWING state
822  }
823  }
824 }
825 
826 
827 /**
828  * @brief RENEWING state
829  *
830  * Client is trying to renew its lease. It regularly sends
831  * DHCPREQUEST messages with the server that gave it its current
832  * lease specified, and waits for a reply
833  *
834  * @param[in] context Pointer to the DHCP client context
835  **/
836 
838 {
839  systime_t t2;
840  systime_t time;
841 
842  //Get current time
843  time = osGetSystemTime();
844 
845  //Check current time
846  if(timeCompare(time, context->timestamp + context->timeout) >= 0)
847  {
848  //Convert T2 to milliseconds
849  if(context->t2 < (MAX_DELAY / 1000))
850  t2 = context->t2 * 1000;
851  else
852  t2 = MAX_DELAY;
853 
854  //Check whether T2 timer has expired
855  if(timeCompare(time, context->leaseStartTime + t2) < 0)
856  {
857  //First DHCPREQUEST message?
858  if(context->retransmitCount == 0)
859  {
860  //A transaction identifier is used by the client to
861  //match incoming DHCP messages with pending requests
862  context->transactionId = netGetRand();
863  }
864 
865  //Send a DHCPREQUEST message
866  dhcpClientSendRequest(context);
867 
868  //Save the time at which the message was sent
869  context->timestamp = time;
870 
871  //Compute the remaining time until T2 expires
872  context->timeout = context->leaseStartTime + t2 - time;
873 
874  //The client should wait one-half of the remaining time until T2, down to
875  //a minimum of 60 seconds, before retransmitting the DHCPREQUEST message
876  if(context->timeout > (2 * DHCP_CLIENT_REQUEST_MIN_DELAY))
877  context->timeout /= 2;
878 
879  //Increment retransmission counter
880  context->retransmitCount++;
881  }
882  else
883  {
884  //If no DHCPACK arrives before time T2, the client moves to REBINDING
886  }
887  }
888 }
889 
890 
891 /**
892  * @brief REBINDING state
893  *
894  * The client has failed to renew its lease with the server that originally
895  * granted it, and now seeks a lease extension with any server that can
896  * hear it. It periodically sends DHCPREQUEST messages with no server specified
897  * until it gets a reply or the lease ends
898  *
899  * @param[in] context Pointer to the DHCP client context
900  **/
901 
903 {
904  uint_t i;
905  systime_t time;
906  systime_t leaseTime;
907  NetInterface *interface;
908 
909  //Point to the underlying network interface
910  interface = context->settings.interface;
911  //Index of the IP address in the list of addresses assigned to the interface
912  i = context->settings.ipAddrIndex;
913 
914  //Get current time
915  time = osGetSystemTime();
916 
917  //Check current time
918  if(timeCompare(time, context->timestamp + context->timeout) >= 0)
919  {
920  //Convert the lease time to milliseconds
921  if(context->leaseTime < (MAX_DELAY / 1000))
922  leaseTime = context->leaseTime * 1000;
923  else
924  leaseTime = MAX_DELAY;
925 
926  //Check whether the lease has expired
927  if(timeCompare(time, context->leaseStartTime + leaseTime) < 0)
928  {
929  //First DHCPREQUEST message?
930  if(context->retransmitCount == 0)
931  {
932  //A transaction identifier is used by the client to
933  //match incoming DHCP messages with pending requests
934  context->transactionId = netGetRand();
935  }
936 
937  //Send a DHCPREQUEST message
938  dhcpClientSendRequest(context);
939 
940  //Save the time at which the message was sent
941  context->timestamp = time;
942 
943  //Compute the remaining time until the lease expires
944  context->timeout = context->leaseStartTime + leaseTime - time;
945 
946  //The client should wait one-half of the remaining lease time, down to a
947  //minimum of 60 seconds, before retransmitting the DHCPREQUEST message
948  if(context->timeout > (2 * DHCP_CLIENT_REQUEST_MIN_DELAY))
949  context->timeout /= 2;
950 
951  //Increment retransmission counter
952  context->retransmitCount++;
953  }
954  else
955  {
956  //The host address is no longer valid...
957  interface->ipv4Context.addrList[i].addr = IPV4_UNSPECIFIED_ADDR;
958  interface->ipv4Context.addrList[i].state = IPV4_ADDR_STATE_INVALID;
959 
960  //Clear subnet mask
961  interface->ipv4Context.addrList[i].subnetMask = IPV4_UNSPECIFIED_ADDR;
962 
963 #if (MDNS_RESPONDER_SUPPORT == ENABLED)
964  //Restart mDNS probing process
965  mdnsResponderStartProbing(interface->mdnsResponderContext);
966 #endif
967 
968  //If the lease expires before the client receives
969  //a DHCPACK, the client moves to INIT state
971  }
972  }
973 }
974 
975 
976 /**
977  * @brief Send DHCPDISCOVER message
978  * @param[in] context Pointer to the DHCP client context
979  * @return Error code
980  **/
981 
983 {
984  error_t error;
985  size_t offset;
986  NetBuffer *buffer;
987  NetInterface *interface;
988  NetInterface *logicalInterface;
992  NetTxAncillary ancillary;
993 #if (DHCP_CLIENT_HOSTNAME_OPTION_SUPPORT == ENABLED)
994  size_t length;
995 #endif
996 
997  //DHCP message type
998  const uint8_t messageType = DHCP_MESSAGE_TYPE_DISCOVER;
999 
1000  //Point to the underlying network interface
1001  interface = context->settings.interface;
1002  //Point to the logical interface
1003  logicalInterface = nicGetLogicalInterface(interface);
1004 
1005  //Allocate a memory buffer to hold the DHCP message
1006  buffer = udpAllocBuffer(DHCP_MIN_MSG_SIZE, &offset);
1007  //Failed to allocate buffer?
1008  if(buffer == NULL)
1009  return ERROR_OUT_OF_MEMORY;
1010 
1011  //Point to the beginning of the DHCP message
1012  message = netBufferAt(buffer, offset);
1013  //Clear memory buffer contents
1015 
1016  //Format DHCPDISCOVER message
1019  message->hlen = sizeof(MacAddr);
1020  message->xid = htonl(context->transactionId);
1021  message->secs = dhcpClientComputeElapsedTime(context);
1022  message->flags = HTONS(DHCP_FLAG_BROADCAST);
1023  message->ciaddr = IPV4_UNSPECIFIED_ADDR;
1024  message->chaddr = logicalInterface->macAddr;
1025 
1026  //Write magic cookie before setting any option
1027  message->magicCookie = HTONL(DHCP_MAGIC_COOKIE);
1028  //Properly terminate options field
1029  message->options[0] = DHCP_OPT_END;
1030 
1031  //DHCP Message Type option
1033  &messageType, sizeof(messageType));
1034 
1035 #if (DHCP_CLIENT_HOSTNAME_OPTION_SUPPORT == ENABLED)
1036  //Retrieve the length of the host name
1037  length = osStrlen(context->settings.hostname);
1038 
1039  //Any host name defined?
1040  if(length > 0)
1041  {
1042  //The Host Name option specifies the name of the client
1044  context->settings.hostname, length);
1045  }
1046 #endif
1047 
1048 #if (DHCP_CLIENT_ID_OPTION_SUPPORT == ENABLED)
1049  //Any client identifier defined?
1050  if(context->settings.clientIdLength > 0)
1051  {
1052  //DHCP servers use this value to index their database of address bindings
1054  context->settings.clientId, context->settings.clientIdLength);
1055  }
1056 #endif
1057 
1058  //Check whether rapid commit is enabled
1059  if(context->settings.rapidCommit)
1060  {
1061  //Include the Rapid Commit option if the client is prepared
1062  //to perform the DHCPDISCOVER-DHCPACK message exchange
1064  }
1065 
1066  //DHCP messages broadcast by a client prior to that client obtaining its
1067  //IP address must have the source address field in the IP header set to 0
1068  //(refer to RFC 2131, section 4.1)
1069  srcIpAddr.length = sizeof(Ipv4Addr);
1070  srcIpAddr.ipv4Addr = IPV4_UNSPECIFIED_ADDR;
1071 
1072  //Set destination IP address
1073  destIpAddr.length = sizeof(Ipv4Addr);
1074  destIpAddr.ipv4Addr = IPV4_BROADCAST_ADDR;
1075 
1076  //Debug message
1077  TRACE_DEBUG("\r\n%s: Sending DHCP message (%" PRIuSIZE " bytes)...\r\n",
1079 
1080  //Dump the contents of the message for debugging purpose
1082 
1083  //Additional options can be passed to the stack along with the packet
1084  ancillary = NET_DEFAULT_TX_ANCILLARY;
1085 
1086  //Broadcast DHCPDISCOVER message
1087  error = udpSendBuffer(interface, &srcIpAddr, DHCP_CLIENT_PORT, &destIpAddr,
1088  DHCP_SERVER_PORT, buffer, offset, &ancillary);
1089 
1090  //Free previously allocated memory
1091  netBufferFree(buffer);
1092  //Return status code
1093  return error;
1094 }
1095 
1096 
1097 /**
1098  * @brief Send DHCPREQUEST message
1099  * @param[in] context Pointer to the DHCP client context
1100  * @return Error code
1101  **/
1102 
1104 {
1105  uint_t i;
1106  error_t error;
1107  size_t offset;
1108  NetBuffer *buffer;
1109  NetInterface *interface;
1110  NetInterface *logicalInterface;
1112  IpAddr srcIpAddr;
1114  NetTxAncillary ancillary;
1115 #if (DHCP_CLIENT_HOSTNAME_OPTION_SUPPORT == ENABLED)
1116  size_t length;
1117 #endif
1118 
1119  //DHCP message type
1120  const uint8_t messageType = DHCP_MESSAGE_TYPE_REQUEST;
1121 
1122  //Point to the underlying network interface
1123  interface = context->settings.interface;
1124  //Point to the logical interface
1125  logicalInterface = nicGetLogicalInterface(interface);
1126 
1127  //Index of the IP address in the list of addresses assigned to the interface
1128  i = context->settings.ipAddrIndex;
1129 
1130  //Allocate a memory buffer to hold the DHCP message
1131  buffer = udpAllocBuffer(DHCP_MIN_MSG_SIZE, &offset);
1132  //Failed to allocate buffer?
1133  if(buffer == NULL)
1134  return ERROR_OUT_OF_MEMORY;
1135 
1136  //Point to the beginning of the DHCP message
1137  message = netBufferAt(buffer, offset);
1138  //Clear memory buffer contents
1140 
1141  //Format DHCPREQUEST message
1144  message->hlen = sizeof(MacAddr);
1145  message->xid = htonl(context->transactionId);
1146  message->secs = dhcpClientComputeElapsedTime(context);
1147 
1148  //The client IP address must be included if the client is fully configured
1149  //and can respond to ARP requests
1150  if(context->state == DHCP_STATE_RENEWING ||
1151  context->state == DHCP_STATE_REBINDING)
1152  {
1153  message->flags = 0;
1154  message->ciaddr = interface->ipv4Context.addrList[i].addr;
1155  }
1156  else
1157  {
1158  message->flags = HTONS(DHCP_FLAG_BROADCAST);
1159  message->ciaddr = IPV4_UNSPECIFIED_ADDR;
1160  }
1161 
1162  //Client hardware address
1163  message->chaddr = logicalInterface->macAddr;
1164  //Write magic cookie before setting any option
1165  message->magicCookie = HTONL(DHCP_MAGIC_COOKIE);
1166  //Properly terminate options field
1167  message->options[0] = DHCP_OPT_END;
1168 
1169  //DHCP Message Type option
1171  &messageType, sizeof(messageType));
1172 
1173 #if (DHCP_CLIENT_HOSTNAME_OPTION_SUPPORT == ENABLED)
1174  //Retrieve the length of the host name
1175  length = osStrlen(context->settings.hostname);
1176 
1177  //Any host name defined?
1178  if(length > 0)
1179  {
1180  //The Host Name option specifies the name of the client
1182  context->settings.hostname, length);
1183  }
1184 #endif
1185 
1186 #if (DHCP_CLIENT_ID_OPTION_SUPPORT == ENABLED)
1187  //Any client identifier defined?
1188  if(context->settings.clientIdLength > 0)
1189  {
1190  //DHCP servers use this value to index their database of address bindings
1192  context->settings.clientId, context->settings.clientIdLength);
1193  }
1194 #endif
1195 
1196  //Server Identifier option
1197  if(context->state == DHCP_STATE_REQUESTING)
1198  {
1200  &context->serverIpAddr, sizeof(Ipv4Addr));
1201  }
1202 
1203  //Requested IP Address option
1204  if(context->state == DHCP_STATE_REQUESTING ||
1205  context->state == DHCP_STATE_REBOOTING)
1206  {
1208  &context->requestedIpAddr, sizeof(Ipv4Addr));
1209  }
1210 
1211  //Parameter Request List option
1213  dhcpOptionList, sizeof(dhcpOptionList));
1214 
1215  //IP address is being renewed?
1216  if(context->state == DHCP_STATE_RENEWING)
1217  {
1218  //Set source IP address
1219  srcIpAddr.length = sizeof(Ipv4Addr);
1220  srcIpAddr.ipv4Addr = interface->ipv4Context.addrList[i].addr;
1221 
1222  //The client transmits the message directly to the server that initially
1223  //granted the lease
1224  destIpAddr.length = sizeof(Ipv4Addr);
1225  destIpAddr.ipv4Addr = context->serverIpAddr;
1226  }
1227  else
1228  {
1229  //DHCP messages broadcast by a client prior to that client obtaining its
1230  //IP address must have the source address field in the IP header set to 0
1231  //(refer to RFC 2131, section 4.1)
1232  srcIpAddr.length = sizeof(Ipv4Addr);
1233  srcIpAddr.ipv4Addr = IPV4_UNSPECIFIED_ADDR;
1234 
1235  //Broadcast the message
1236  destIpAddr.length = sizeof(Ipv4Addr);
1237  destIpAddr.ipv4Addr = IPV4_BROADCAST_ADDR;
1238  }
1239 
1240  //Debug message
1241  TRACE_DEBUG("\r\n%s: Sending DHCP message (%" PRIuSIZE " bytes)...\r\n",
1243 
1244  //Dump the contents of the message for debugging purpose
1246 
1247  //Additional options can be passed to the stack along with the packet
1248  ancillary = NET_DEFAULT_TX_ANCILLARY;
1249 
1250  //Send DHCPREQUEST message
1251  error = udpSendBuffer(interface, &srcIpAddr, DHCP_CLIENT_PORT, &destIpAddr,
1252  DHCP_SERVER_PORT, buffer, offset, &ancillary);
1253 
1254  //Free previously allocated memory
1255  netBufferFree(buffer);
1256  //Return status code
1257  return error;
1258 }
1259 
1260 
1261 /**
1262  * @brief Send DHCPDECLINE message
1263  * @param[in] context Pointer to the DHCP client context
1264  * @return Error code
1265  **/
1266 
1268 {
1269  error_t error;
1270  size_t offset;
1271  NetBuffer *buffer;
1272  NetInterface *interface;
1273  NetInterface *logicalInterface;
1275  IpAddr srcIpAddr;
1277  NetTxAncillary ancillary;
1278 
1279  //DHCP message type
1280  const uint8_t messageType = DHCP_MESSAGE_TYPE_DECLINE;
1281 
1282  //Point to the underlying network interface
1283  interface = context->settings.interface;
1284  //Point to the logical interface
1285  logicalInterface = nicGetLogicalInterface(interface);
1286 
1287  //Allocate a memory buffer to hold the DHCP message
1288  buffer = udpAllocBuffer(DHCP_MIN_MSG_SIZE, &offset);
1289  //Failed to allocate buffer?
1290  if(buffer == NULL)
1291  return ERROR_OUT_OF_MEMORY;
1292 
1293  //Point to the beginning of the DHCP message
1294  message = netBufferAt(buffer, offset);
1295  //Clear memory buffer contents
1297 
1298  //Format DHCPDECLINE message
1301  message->hlen = sizeof(MacAddr);
1302  message->xid = htonl(context->transactionId);
1303  message->secs = 0;
1304  message->flags = 0;
1305  message->ciaddr = IPV4_UNSPECIFIED_ADDR;
1306  message->chaddr = logicalInterface->macAddr;
1307 
1308  //Write magic cookie before setting any option
1309  message->magicCookie = HTONL(DHCP_MAGIC_COOKIE);
1310  //Properly terminate options field
1311  message->options[0] = DHCP_OPT_END;
1312 
1313  //DHCP Message Type option
1315  &messageType, sizeof(messageType));
1316  //Server Identifier option
1318  &context->serverIpAddr, sizeof(Ipv4Addr));
1319  //Requested IP Address option
1321  &context->requestedIpAddr, sizeof(Ipv4Addr));
1322 
1323  //Use the unspecified address as source address
1324  srcIpAddr.length = sizeof(Ipv4Addr);
1325  srcIpAddr.ipv4Addr = IPV4_UNSPECIFIED_ADDR;
1326 
1327  //Set destination IP address
1328  destIpAddr.length = sizeof(Ipv4Addr);
1329  destIpAddr.ipv4Addr = IPV4_BROADCAST_ADDR;
1330 
1331  //Debug message
1332  TRACE_DEBUG("\r\n%s: Sending DHCP message (%" PRIuSIZE " bytes)...\r\n",
1334 
1335  //Dump the contents of the message for debugging purpose
1337 
1338  //Additional options can be passed to the stack along with the packet
1339  ancillary = NET_DEFAULT_TX_ANCILLARY;
1340 
1341  //Broadcast DHCPDECLINE message
1342  error = udpSendBuffer(interface, &srcIpAddr, DHCP_CLIENT_PORT, &destIpAddr,
1343  DHCP_SERVER_PORT, buffer, offset, &ancillary);
1344 
1345  //Free previously allocated memory
1346  netBufferFree(buffer);
1347  //Return status code
1348  return error;
1349 }
1350 
1351 
1352 /**
1353  * @brief Process incoming DHCP message
1354  * @param[in] interface Underlying network interface
1355  * @param[in] pseudoHeader UDP pseudo header
1356  * @param[in] udpHeader UDP header
1357  * @param[in] buffer Multi-part buffer containing the incoming DHCP message
1358  * @param[in] offset Offset to the first byte of the DHCP message
1359  * @param[in] ancillary Additional options passed to the stack along with
1360  * the packet
1361  * @param[in] param Pointer to the DHCP client context
1362  **/
1363 
1365  const IpPseudoHeader *pseudoHeader, const UdpHeader *udpHeader,
1366  const NetBuffer *buffer, size_t offset, const NetRxAncillary *ancillary,
1367  void *param)
1368 {
1369  size_t length;
1370  DhcpClientContext *context;
1372  DhcpOption *option;
1373 
1374  //Point to the DHCP client context
1375  context = (DhcpClientContext *) param;
1376 
1377  //Retrieve the length of the DHCP message
1378  length = netBufferGetLength(buffer) - offset;
1379 
1380  //Make sure the DHCP message is valid
1381  if(length < sizeof(DhcpMessage))
1382  return;
1384  return;
1385 
1386  //Point to the beginning of the DHCP message
1387  message = netBufferAt(buffer, offset);
1388  //Sanity check
1389  if(message == NULL)
1390  return;
1391 
1392  //Debug message
1393  TRACE_DEBUG("\r\n%s: DHCP message received (%" PRIuSIZE " bytes)...\r\n",
1395 
1396  //Dump the contents of the message for debugging purpose
1398 
1399  //The DHCP server shall respond with a BOOTREPLY opcode
1400  if(message->op != DHCP_OPCODE_BOOTREPLY)
1401  return;
1402  //Enforce hardware type
1403  if(message->htype != DHCP_HARDWARE_TYPE_ETH)
1404  return;
1405  //Check the length of the hardware address
1406  if(message->hlen != sizeof(MacAddr))
1407  return;
1408  //Check magic cookie
1409  if(message->magicCookie != HTONL(DHCP_MAGIC_COOKIE))
1410  return;
1411 
1412  //The DHCP Message Type option must be included in every DHCP message
1414 
1415  //Failed to retrieve the Message Type option?
1416  if(option == NULL || option->length != 1)
1417  return;
1418 
1419  //Check message type
1420  switch(option->value[0])
1421  {
1423  //Parse DHCPOFFER message
1424  dhcpClientParseOffer(context, message, length);
1425  break;
1426  case DHCP_MESSAGE_TYPE_ACK:
1427  //Parse DHCPACK message
1428  dhcpClientParseAck(context, message, length);
1429  break;
1430  case DHCP_MESSAGE_TYPE_NAK:
1431  //Parse DHCPNAK message
1432  dhcpClientParseNak(context, message, length);
1433  break;
1434  default:
1435  //Silently drop incoming message
1436  break;
1437  }
1438 }
1439 
1440 
1441 /**
1442  * @brief Parse DHCPOFFER message
1443  * @param[in] context Pointer to the DHCP client context
1444  * @param[in] message Pointer to the incoming DHCP message
1445  * @param[in] length Length of the incoming message to parse
1446  **/
1447 
1449  const DhcpMessage *message, size_t length)
1450 {
1451  DhcpOption *serverIdOption;
1452  NetInterface *interface;
1453  NetInterface *logicalInterface;
1454 
1455  //Point to the underlying network interface
1456  interface = context->settings.interface;
1457  //Point to the logical interface
1458  logicalInterface = nicGetLogicalInterface(interface);
1459 
1460  //Discard any received packet that does not match the transaction ID
1461  if(ntohl(message->xid) != context->transactionId)
1462  return;
1463  //Make sure the IP address offered to the client is valid
1464  if(message->yiaddr == IPV4_UNSPECIFIED_ADDR)
1465  return;
1466  //Check MAC address
1467  if(!macCompAddr(&message->chaddr, &logicalInterface->macAddr))
1468  return;
1469 
1470  //Make sure that the DHCPOFFER message is received in response to
1471  //a DHCPDISCOVER message
1472  if(context->state != DHCP_STATE_SELECTING)
1473  return;
1474 
1475  //A DHCP server always returns its own address in the Server Identifier option
1477 
1478  //Failed to retrieve the Server Identifier option?
1479  if(serverIdOption == NULL || serverIdOption->length != 4)
1480  return;
1481 
1482  //Record the IP address of the DHCP server
1483  ipv4CopyAddr(&context->serverIpAddr, serverIdOption->value);
1484  //Record the IP address offered to the client
1485  context->requestedIpAddr = message->yiaddr;
1486 
1487  //Switch to the REQUESTING state
1489 }
1490 
1491 
1492 /**
1493  * @brief Parse DHCPACK message
1494  * @param[in] context Pointer to the DHCP client context
1495  * @param[in] message Pointer to the incoming DHCP message
1496  * @param[in] length Length of the incoming message to parse
1497  * @return Error code
1498  **/
1499 
1501  const DhcpMessage *message, size_t length)
1502 {
1503  uint_t i;
1504  uint_t j;
1505  uint_t n;
1506  DhcpOption *option;
1507  DhcpOption *serverIdOption;
1508  NetInterface *interface;
1509  NetInterface *logicalInterface;
1510  NetInterface *physicalInterface;
1511 
1512  //Point to the underlying network interface
1513  interface = context->settings.interface;
1514  //Point to the logical interface
1515  logicalInterface = nicGetLogicalInterface(interface);
1516  //Point to the physical interface
1517  physicalInterface = nicGetPhysicalInterface(interface);
1518 
1519  //Index of the IP address in the list of addresses assigned to the interface
1520  i = context->settings.ipAddrIndex;
1521 
1522  //Discard any received packet that does not match the transaction ID
1523  if(ntohl(message->xid) != context->transactionId)
1524  return;
1525  //Make sure the IP address assigned to the client is valid
1526  if(message->yiaddr == IPV4_UNSPECIFIED_ADDR)
1527  return;
1528  //Check MAC address
1529  if(!macCompAddr(&message->chaddr, &logicalInterface->macAddr))
1530  return;
1531 
1532  //A DHCP server always returns its own address in the Server Identifier option
1534 
1535  //Failed to retrieve the Server Identifier option?
1536  if(serverIdOption == NULL || serverIdOption->length != 4)
1537  return;
1538 
1539  //Check current state
1540  if(context->state == DHCP_STATE_SELECTING)
1541  {
1542  //A DHCPACK message is not acceptable when rapid commit is disallowed
1543  if(!context->settings.rapidCommit)
1544  return;
1545 
1546  //Search for the Rapid Commit option
1548 
1549  //A server must include this option in a DHCPACK message sent
1550  //in a response to a DHCPDISCOVER message when completing the
1551  //DHCPDISCOVER-DHCPACK message exchange
1552  if(option == NULL || option->length != 0)
1553  return;
1554  }
1555  else if(context->state == DHCP_STATE_REQUESTING ||
1556  context->state == DHCP_STATE_RENEWING)
1557  {
1558  //Check the server identifier
1559  if(!ipv4CompAddr(serverIdOption->value, &context->serverIpAddr))
1560  return;
1561  }
1562  else if(context->state == DHCP_STATE_REBOOTING ||
1563  context->state == DHCP_STATE_REBINDING)
1564  {
1565  //Do not check the server identifier
1566  }
1567  else
1568  {
1569  //Silently discard the DHCPACK message
1570  return;
1571  }
1572 
1573  //Retrieve IP Address Lease Time option
1575 
1576  //Failed to retrieve specified option?
1577  if(option == NULL || option->length != 4)
1578  return;
1579 
1580  //Record the lease time
1581  context->leaseTime = LOAD32BE(option->value);
1582 
1583  //Retrieve Renewal Time Value option
1585 
1586  //Specified option found?
1587  if(option != NULL && option->length == 4)
1588  {
1589  //This option specifies the time interval from address assignment
1590  //until the client transitions to the RENEWING state
1591  context->t1 = LOAD32BE(option->value);
1592  }
1593  else if(context->leaseTime != DHCP_INFINITE_TIME)
1594  {
1595  //By default, T1 is set to 50% of the lease time
1596  context->t1 = context->leaseTime / 2;
1597  }
1598  else
1599  {
1600  //Infinite lease
1601  context->t1 = DHCP_INFINITE_TIME;
1602  }
1603 
1604  //Retrieve Rebinding Time value option
1606 
1607  //Specified option found?
1608  if(option != NULL && option->length == 4)
1609  {
1610  //This option specifies the time interval from address assignment
1611  //until the client transitions to the REBINDING state
1612  context->t2 = LOAD32BE(option->value);
1613  }
1614  else if(context->leaseTime != DHCP_INFINITE_TIME)
1615  {
1616  //By default, T2 is set to 87.5% of the lease time
1617  context->t2 = context->leaseTime * 7 / 8;
1618  }
1619  else
1620  {
1621  //Infinite lease
1622  context->t2 = DHCP_INFINITE_TIME;
1623  }
1624 
1625  //Retrieve Subnet Mask option
1627 
1628  //The specified option has been found?
1629  if(option != NULL && option->length == sizeof(Ipv4Addr))
1630  {
1631  //Save subnet mask
1632  ipv4CopyAddr(&interface->ipv4Context.addrList[i].subnetMask,
1633  option->value);
1634  }
1635 
1636  //Retrieve Router option
1638 
1639  //The specified option has been found?
1640  if(option != NULL && !(option->length % sizeof(Ipv4Addr)))
1641  {
1642  //Save default gateway
1643  if(option->length >= sizeof(Ipv4Addr))
1644  {
1645  ipv4CopyAddr(&interface->ipv4Context.addrList[i].defaultGateway,
1646  option->value);
1647  }
1648  }
1649 
1650  //Use the DNS servers provided by the DHCP server?
1651  if(!context->settings.manualDnsConfig)
1652  {
1653  //Retrieve DNS Server option
1655 
1656  //The specified option has been found?
1657  if(option != NULL && !(option->length % sizeof(Ipv4Addr)))
1658  {
1659  //Get the number of addresses provided in the response
1660  n = option->length / sizeof(Ipv4Addr);
1661 
1662  //Loop through the list of addresses
1663  for(j = 0; j < n && j < IPV4_DNS_SERVER_LIST_SIZE; j++)
1664  {
1665  //Save DNS server address
1666  ipv4CopyAddr(&interface->ipv4Context.dnsServerList[j],
1667  option->value + j * sizeof(Ipv4Addr));
1668  }
1669  }
1670  }
1671 
1672  //Retrieve MTU option
1674 
1675  //The specified option has been found?
1676  if(option != NULL && option->length == 2)
1677  {
1678  //This option specifies the MTU to use on this interface
1679  n = LOAD16BE(option->value);
1680 
1681  //Make sure that the option's value is acceptable
1682  if(n >= IPV4_MINIMUM_MTU && n <= physicalInterface->nicDriver->mtu)
1683  {
1684  //Set the MTU to be used on the interface
1685  interface->ipv4Context.linkMtu = n;
1686  }
1687  }
1688 
1689  //Record the IP address of the DHCP server
1690  ipv4CopyAddr(&context->serverIpAddr, serverIdOption->value);
1691  //Record the IP address assigned to the client
1692  context->requestedIpAddr = message->yiaddr;
1693 
1694  //Save the time a which the lease was obtained
1695  context->leaseStartTime = osGetSystemTime();
1696 
1697  //Check current state
1698  if(context->state == DHCP_STATE_REQUESTING ||
1699  context->state == DHCP_STATE_REBOOTING)
1700  {
1701  //Use the IP address as a tentative address
1702  interface->ipv4Context.addrList[i].addr = message->yiaddr;
1703  interface->ipv4Context.addrList[i].state = IPV4_ADDR_STATE_TENTATIVE;
1704 
1705  //Clear conflict flag
1706  interface->ipv4Context.addrList[i].conflict = FALSE;
1707 
1708  //The client should probe the newly received address
1710  }
1711  else
1712  {
1713  //Assign the IP address to the client
1714  interface->ipv4Context.addrList[i].addr = message->yiaddr;
1715  interface->ipv4Context.addrList[i].state = IPV4_ADDR_STATE_VALID;
1716 
1717 #if (MDNS_RESPONDER_SUPPORT == ENABLED)
1718  //Restart mDNS probing process
1719  mdnsResponderStartProbing(interface->mdnsResponderContext);
1720 #endif
1721  //The client transitions to the BOUND state
1723  }
1724 }
1725 
1726 
1727 /**
1728  * @brief Parse DHCPNAK message
1729  * @param[in] context Pointer to the DHCP client context
1730  * @param[in] message Pointer to the incoming DHCP message
1731  * @param[in] length Length of the incoming message to parse
1732  * @return Error code
1733  **/
1734 
1736  const DhcpMessage *message, size_t length)
1737 {
1738  uint_t i;
1739  DhcpOption *serverIdOption;
1740  NetInterface *interface;
1741  NetInterface *logicalInterface;
1742 
1743  //Point to the underlying network interface
1744  interface = context->settings.interface;
1745  //Point to the logical interface
1746  logicalInterface = nicGetLogicalInterface(interface);
1747 
1748  //Index of the IP address in the list of addresses assigned to the interface
1749  i = context->settings.ipAddrIndex;
1750 
1751  //Discard any received packet that does not match the transaction ID
1752  if(ntohl(message->xid) != context->transactionId)
1753  return;
1754  //Check MAC address
1755  if(!macCompAddr(&message->chaddr, &logicalInterface->macAddr))
1756  return;
1757 
1758  //A DHCP server always returns its own address in the Server Identifier option
1760 
1761  //Failed to retrieve the Server Identifier option?
1762  if(serverIdOption == NULL || serverIdOption->length != 4)
1763  return;
1764 
1765  //Check current state
1766  if(context->state == DHCP_STATE_REQUESTING ||
1767  context->state == DHCP_STATE_RENEWING)
1768  {
1769  //Check the server identifier
1770  if(!ipv4CompAddr(serverIdOption->value, &context->serverIpAddr))
1771  return;
1772  }
1773  else if(context->state == DHCP_STATE_REBOOTING ||
1774  context->state == DHCP_STATE_REBINDING)
1775  {
1776  //Do not check the server identifier
1777  }
1778  else
1779  {
1780  //Silently discard the DHCPNAK message
1781  return;
1782  }
1783 
1784  //The host address is no longer appropriate for the link
1785  interface->ipv4Context.addrList[i].addr = IPV4_UNSPECIFIED_ADDR;
1786  interface->ipv4Context.addrList[i].state = IPV4_ADDR_STATE_INVALID;
1787 
1788  //Clear subnet mask
1789  interface->ipv4Context.addrList[i].subnetMask = IPV4_UNSPECIFIED_ADDR;
1790 
1791 #if (MDNS_RESPONDER_SUPPORT == ENABLED)
1792  //Restart mDNS probing process
1793  mdnsResponderStartProbing(interface->mdnsResponderContext);
1794 #endif
1795 
1796  //Restart DHCP configuration
1798 }
1799 
1800 
1801 /**
1802  * @brief Manage DHCP configuration timeout
1803  * @param[in] context Pointer to the DHCP client context
1804  **/
1805 
1807 {
1808  systime_t time;
1809  NetInterface *interface;
1810 
1811  //Point to the underlying network interface
1812  interface = context->settings.interface;
1813 
1814  //Get current time
1815  time = osGetSystemTime();
1816 
1817  //Any registered callback?
1818  if(context->settings.timeoutEvent != NULL)
1819  {
1820  //DHCP configuration timeout?
1821  if(timeCompare(time, context->configStartTime + context->settings.timeout) >= 0)
1822  {
1823  //Ensure the callback function is only called once
1824  if(!context->timeoutEventDone)
1825  {
1826  //Release exclusive access
1828  //Invoke user callback function
1829  context->settings.timeoutEvent(context, interface);
1830  //Get exclusive access
1832 
1833  //Set flag
1834  context->timeoutEventDone = TRUE;
1835  }
1836  }
1837  }
1838 }
1839 
1840 
1841 /**
1842  * @brief Compute the appropriate secs field
1843  *
1844  * Compute the number of seconds elapsed since the client began
1845  * address acquisition or renewal process
1846  *
1847  * @param[in] context Pointer to the DHCP client context
1848  * @return The elapsed time expressed in seconds
1849  **/
1850 
1852 {
1853  systime_t time;
1854 
1855  //Compute the time elapsed since the DHCP configuration process started
1856  time = (osGetSystemTime() - context->configStartTime) / 1000;
1857 
1858  //The value 0xFFFF is used to represent any elapsed time values
1859  //greater than the largest time value that can be represented
1860  time = MIN(time, 0xFFFF);
1861 
1862  //Convert the 16-bit value to network byte order
1863  return htons(time);
1864 }
1865 
1866 
1867 /**
1868  * @brief Update DHCP FSM state
1869  * @param[in] context Pointer to the DHCP client context
1870  * @param[in] newState New DHCP state to switch to
1871  * @param[in] delay Initial delay
1872  **/
1873 
1875  DhcpState newState, systime_t delay)
1876 {
1877  systime_t time;
1878 
1879  //Get current time
1880  time = osGetSystemTime();
1881 
1882 #if (DHCP_TRACE_LEVEL >= TRACE_LEVEL_INFO)
1883  //Sanity check
1884  if(newState <= DHCP_STATE_REBINDING)
1885  {
1886  //DHCP FSM states
1887  static const char_t *stateLabel[] =
1888  {
1889  "INIT",
1890  "SELECTING",
1891  "REQUESTING",
1892  "INIT-REBOOT",
1893  "REBOOTING",
1894  "PROBING",
1895  "BOUND",
1896  "RENEWING",
1897  "REBINDING"
1898  };
1899 
1900  //Debug message
1901  TRACE_INFO("%s: DHCP client %s state\r\n",
1902  formatSystemTime(time, NULL), stateLabel[newState]);
1903  }
1904 #endif
1905 
1906  //Set time stamp
1907  context->timestamp = time;
1908  //Set initial delay
1909  context->timeout = delay;
1910  //Reset retransmission counter
1911  context->retransmitCount = 0;
1912  //Switch to the new state
1913  context->state = newState;
1914 
1915  //Any registered callback?
1916  if(context->settings.stateChangeEvent != NULL)
1917  {
1918  NetInterface *interface;
1919 
1920  //Point to the underlying network interface
1921  interface = context->settings.interface;
1922 
1923  //Release exclusive access
1925  //Invoke user callback function
1926  context->settings.stateChangeEvent(context, interface, newState);
1927  //Get exclusive access
1929  }
1930 }
1931 
1932 
1933 /**
1934  * @brief Dump DHCP configuration for debugging purpose
1935  * @param[in] context Pointer to the DHCP client context
1936  **/
1937 
1939 {
1940 #if (DHCP_TRACE_LEVEL >= TRACE_LEVEL_INFO)
1941  uint_t i;
1942  uint_t j;
1943  NetInterface *interface;
1944  Ipv4Context *ipv4Context;
1945 
1946  //Point to the underlying network interface
1947  interface = context->settings.interface;
1948  //Point to the IPv4 context
1949  ipv4Context = &interface->ipv4Context;
1950 
1951  //Index of the IP address in the list of addresses assigned to the interface
1952  i = context->settings.ipAddrIndex;
1953 
1954  //Debug message
1955  TRACE_INFO("\r\n");
1956  TRACE_INFO("DHCP configuration:\r\n");
1957 
1958  //Lease start time
1959  TRACE_INFO(" Lease Start Time = %s\r\n",
1960  formatSystemTime(context->leaseStartTime, NULL));
1961 
1962  //Lease time
1963  TRACE_INFO(" Lease Time = %" PRIu32 "s\r\n", context->leaseTime);
1964  //Renewal time
1965  TRACE_INFO(" T1 = %" PRIu32 "s\r\n", context->t1);
1966  //Rebinding time
1967  TRACE_INFO(" T2 = %" PRIu32 "s\r\n", context->t2);
1968 
1969  //Host address
1970  TRACE_INFO(" IPv4 Address = %s\r\n",
1971  ipv4AddrToString(ipv4Context->addrList[i].addr, NULL));
1972 
1973  //Subnet mask
1974  TRACE_INFO(" Subnet Mask = %s\r\n",
1975  ipv4AddrToString(ipv4Context->addrList[i].subnetMask, NULL));
1976 
1977  //Default gateway
1978  TRACE_INFO(" Default Gateway = %s\r\n",
1979  ipv4AddrToString(ipv4Context->addrList[i].defaultGateway, NULL));
1980 
1981  //DNS servers
1982  for(j = 0; j < IPV4_DNS_SERVER_LIST_SIZE; j++)
1983  {
1984  TRACE_INFO(" DNS Server %u = %s\r\n", j + 1,
1985  ipv4AddrToString(ipv4Context->dnsServerList[j], NULL));
1986  }
1987 
1988  //Maximum transmit unit
1989  TRACE_INFO(" MTU = %" PRIuSIZE "\r\n", interface->ipv4Context.linkMtu);
1990  TRACE_INFO("\r\n");
1991 #endif
1992 }
1993 
1994 #endif
void dhcpClientStateRebinding(DhcpClientContext *context)
REBINDING state.
Definition: dhcp_client.c:902
uint8_t length
Definition: coap_common.h:190
#define htons(value)
Definition: cpu_endian.h:413
void dhcpClientChangeState(DhcpClientContext *context, DhcpState newState, systime_t delay)
Update DHCP FSM state.
Definition: dhcp_client.c:1874
void dhcpClientParseOffer(DhcpClientContext *context, const DhcpMessage *message, size_t length)
Parse DHCPOFFER message.
Definition: dhcp_client.c:1448
error_t dhcpDumpMessage(const DhcpMessage *message, size_t length)
Dump DHCP message for debugging purpose.
Definition: dhcp_debug.c:158
Date and time management.
#define DHCP_CLIENT_PROBE_DELAY
Definition: dhcp_client.h:140
void dhcpClientStateRenewing(DhcpClientContext *context)
RENEWING state.
Definition: dhcp_client.c:837
DHCP client (Dynamic Host Configuration Protocol)
const NetTxAncillary NET_DEFAULT_TX_ANCILLARY
Definition: net_misc.c:68
#define netMutex
Definition: net_legacy.h:266
#define LOAD32BE(p)
Definition: cpu_endian.h:210
DhcpLinkChangeCallback linkChangeEvent
Link state change event.
Definition: dhcp_client.h:223
IP network address.
Definition: ip.h:78
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:88
const uint8_t dhcpOptionList[]
Definition: dhcp_client.c:58
error_t dhcpClientStop(DhcpClientContext *context)
Stop DHCP client.
Definition: dhcp_client.c:227
void dhcpClientStateBound(DhcpClientContext *context)
BOUND state.
Definition: dhcp_client.c:796
#define TRUE
Definition: os_port.h:50
bool_t rapidCommit
Quick configuration using rapid commit.
Definition: dhcp_client.h:219
__start_packed struct @5 MacAddr
MAC address.
DhcpTimeoutCallback timeoutEvent
DHCP configuration timeout event.
Definition: dhcp_client.h:222
error_t dhcpClientSendDecline(DhcpClientContext *context)
Send DHCPDECLINE message.
Definition: dhcp_client.c:1267
__start_packed struct @22 DhcpOption
DHCP option.
#define DHCP_INFINITE_TIME
Definition: dhcp_common.h:53
#define DHCP_CLIENT_REQUEST_MIN_DELAY
Definition: dhcp_client.h:126
#define osStrlen(s)
Definition: os_port.h:152
Ipv4Addr srcIpAddr
Definition: ipcp.h:77
const char_t * formatSystemTime(systime_t time, char_t *str)
Format system time.
Definition: date_time.c:77
#define timeCompare(t1, t2)
Definition: os_port.h:42
uint32_t Ipv4Addr
IPv4 network address.
Definition: ipv4.h:239
#define DHCP_MAX_MSG_SIZE
Definition: dhcp_common.h:46
__start_packed struct @21 DhcpMessage
DHCP message.
systime_t dhcpClientTickCounter
Definition: dhcp_client.c:55
#define DHCP_MAGIC_COOKIE
Definition: dhcp_common.h:51
IPv4 context.
Definition: ipv4.h:338
#define DhcpClientContext
Definition: dhcp_client.h:154
error_t dhcpClientStart(DhcpClientContext *context)
Start DHCP client.
Definition: dhcp_client.c:181
IP pseudo header.
Definition: ip.h:97
void dhcpClientCheckTimeout(DhcpClientContext *context)
Manage DHCP configuration timeout.
Definition: dhcp_client.c:1806
#define FALSE
Definition: os_port.h:46
Invalid parameter.
Definition: error.h:47
#define htonl(value)
Definition: cpu_endian.h:414
uint_t ipAddrIndex
Index of the IP address to be configured.
Definition: dhcp_client.h:211
NetInterface * nicGetPhysicalInterface(NetInterface *interface)
Retrieve physical interface.
Definition: nic.c:84
#define HTONL(value)
Definition: cpu_endian.h:411
error_t
Error codes.
Definition: error.h:42
An address whose uniqueness on a link is being verified.
Definition: ipv4.h:190
void dhcpClientParseNak(DhcpClientContext *context, const DhcpMessage *message, size_t length)
Parse DHCPNAK message.
Definition: dhcp_client.c:1735
void dhcpClientDumpConfig(DhcpClientContext *context)
Dump DHCP configuration for debugging purpose.
Definition: dhcp_client.c:1938
#define DHCP_CLIENT_MAX_HOSTNAME_LEN
Definition: dhcp_client.h:63
void * netBufferAt(const NetBuffer *buffer, size_t offset)
Returns a pointer to the data at the specified position.
Definition: net_mem.c:413
error_t dhcpClientSendRequest(DhcpClientContext *context)
Send DHCPREQUEST message.
Definition: dhcp_client.c:1103
uint16_t dhcpClientComputeElapsedTime(DhcpClientContext *context)
Compute the appropriate secs field.
Definition: dhcp_client.c:1851
#define DHCP_MIN_MSG_SIZE
Definition: dhcp_common.h:44
#define IPV4_DNS_SERVER_LIST_SIZE
Definition: ipv4.h:70
#define NetRxAncillary
Definition: net_misc.h:40
void dhcpClientLinkChangeEvent(DhcpClientContext *context)
Callback function for link change event.
Definition: dhcp_client.c:361
#define NetInterface
Definition: net.h:36
size_t clientIdLength
Length of the client identifier.
Definition: dhcp_client.h:217
NetInterface * interface
Definition: tcp.h:375
error_t udpAttachRxCallback(NetInterface *interface, uint16_t port, UdpRxCallback callback, void *param)
Register user callback.
Definition: udp.c:840
void netBufferFree(NetBuffer *buffer)
Dispose a multi-part buffer.
Definition: net_mem.c:282
NetInterface * netGetDefaultInterface(void)
Get default network interface.
Definition: net.c:1373
DhcpStateChangeCallback stateChangeEvent
FSM state change event.
Definition: dhcp_client.h:224
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:512
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.
Definition: dhcp_client.c:1364
#define NetTxAncillary
Definition: net_misc.h:36
error_t dhcpClientInit(DhcpClientContext *context, const DhcpClientSettings *settings)
DHCP client initialization.
Definition: dhcp_client.c:114
Definitions common to DHCP client and server.
uint32_t t2
DHCP client settings.
Definition: dhcp_client.h:208
#define TRACE_INFO(...)
Definition: debug.h:95
void dhcpClientStateInit(DhcpClientContext *context)
INIT state.
Definition: dhcp_client.c:426
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
char_t hostname[DHCP_CLIENT_MAX_HOSTNAME_LEN+1]
Host name.
Definition: dhcp_client.h:213
#define DHCP_CLIENT_REQUEST_MAX_RC
Definition: dhcp_client.h:105
#define MIN(a, b)
Definition: os_port.h:62
NetBuffer * udpAllocBuffer(size_t length, size_t *offset)
Allocate a buffer to hold a UDP packet.
Definition: udp.c:773
void dhcpClientStateRequesting(DhcpClientContext *context)
REQUESTING state.
Definition: dhcp_client.c:528
#define DHCP_CLIENT_REQUEST_MAX_RT
Definition: dhcp_client.h:119
void dhcpClientStateProbing(DhcpClientContext *context)
PROBING state.
Definition: dhcp_client.c:725
#define IPV4_BROADCAST_ADDR
Definition: ipv4.h:106
uint32_t netGetRand(void)
Get a random value.
Definition: net.c:1401
systime_t timeout
DHCP configuration timeout.
Definition: dhcp_client.h:221
int32_t netGetRandRange(int32_t min, int32_t max)
Get a random value in the specified range.
Definition: net.c:1432
DhcpState dhcpClientGetState(DhcpClientContext *context)
Retrieve current state.
Definition: dhcp_client.c:258
#define DHCP_CLIENT_REQUEST_INIT_RT
Definition: dhcp_client.h:112
#define TRACE_DEBUG(...)
Definition: debug.h:107
char char_t
Definition: compiler_port.h:43
#define DHCP_CLIENT_INIT_DELAY
Definition: dhcp_client.h:84
void dhcpClientStateInitReboot(DhcpClientContext *context)
INIT-REBOOT state.
Definition: dhcp_client.c:607
uint32_t time
#define ipv4CompAddr(ipAddr1, ipAddr2)
Definition: ipv4.h:146
uint32_t t1
NetInterface * interface
Network interface to configure.
Definition: dhcp_client.h:210
#define HTONS(value)
Definition: cpu_endian.h:410
uint8_t n
DhcpState
DHCP FSM states.
Definition: dhcp_client.h:166
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
Data logging functions for debugging purpose (DHCP)
An address that is not assigned to any interface.
Definition: ipv4.h:189
#define DHCP_SERVER_PORT
Definition: dhcp_common.h:40
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
#define osStrncpy(s1, s2, length)
Definition: os_port.h:188
bool_t manualDnsConfig
Force manual DNS configuration.
Definition: dhcp_client.h:220
#define macCompAddr(macAddr1, macAddr2)
Definition: ethernet.h:121
uint8_t message[]
Definition: chap.h:152
#define DHCP_CLIENT_DISCOVER_MAX_RT
Definition: dhcp_client.h:98
__start_packed struct @20 UdpHeader
UDP header.
void dhcpClientStateRebooting(DhcpClientContext *context)
REBOOTING state.
Definition: dhcp_client.c:647
#define ipv4CopyAddr(destIpAddr, srcIpAddr)
Definition: ipv4.h:142
#define DHCP_CLIENT_PROBE_NUM
Definition: dhcp_client.h:133
error_t dhcpClientSendDiscover(DhcpClientContext *context)
Send DHCPDISCOVER message.
Definition: dhcp_client.c:982
An address assigned to an interface whose use is unrestricted.
Definition: ipv4.h:191
#define MAX_DELAY
Definition: os_port.h:76
#define DHCP_HARDWARE_TYPE_ETH
Definition: dhcp_common.h:49
#define PRIuSIZE
Definition: compiler_port.h:78
unsigned int uint_t
Definition: compiler_port.h:45
#define LOAD16BE(p)
Definition: cpu_endian.h:186
#define osMemset(p, value, length)
Definition: os_port.h:128
TCP/IP stack core.
NetInterface * nicGetLogicalInterface(NetInterface *interface)
Retrieve logical interface.
Definition: nic.c:52
#define DHCP_CLIENT_PORT
Definition: dhcp_common.h:41
void dhcpClientGetDefaultSettings(DhcpClientSettings *settings)
Initialize settings with default values.
Definition: dhcp_client.c:75
char_t * ipv4AddrToString(Ipv4Addr ipAddr, char_t *str)
Convert a binary IPv4 address to dot-decimal notation.
Definition: ipv4.c:1465
#define IPV4_MINIMUM_MTU
Definition: ipv4.h:85
#define osStrcpy(s1, s2)
Definition: os_port.h:182
#define DHCP_CLIENT_DISCOVER_INIT_RT
Definition: dhcp_client.h:91
void dhcpClientTick(DhcpClientContext *context)
DHCP client timer handler.
Definition: dhcp_client.c:284
uint32_t systime_t
Definition: compiler_port.h:46
#define ntohl(value)
Definition: cpu_endian.h:422
error_t mdnsResponderStartProbing(MdnsResponderContext *context)
Restart probing process.
void dhcpClientStateSelecting(DhcpClientContext *context)
SELECTING state.
Definition: dhcp_client.c:466
Success.
Definition: error.h:44
void dhcpAddOption(DhcpMessage *message, uint8_t optionCode, const void *optionValue, size_t optionLen)
Append an option to a DHCP message.
Definition: dhcp_common.c:51
Debugging facilities.
DhcpOption * dhcpGetOption(const DhcpMessage *message, size_t length, uint8_t optionCode)
Find the specified option in a DHCP message.
Definition: dhcp_common.c:108
error_t arpSendProbe(NetInterface *interface, Ipv4Addr targetIpAddr)
Send ARP probe.
Definition: arp.c:814
void dhcpClientParseAck(DhcpClientContext *context, const DhcpMessage *message, size_t length)
Parse DHCPACK message.
Definition: dhcp_client.c:1500
#define IPV4_UNSPECIFIED_ADDR
Definition: ipv4.h:104
mDNS responder (Multicast DNS)
#define DHCP_CLIENT_RAND_FACTOR
Definition: dhcp_client.h:147
systime_t osGetSystemTime(void)
Retrieve system time.
Ipv4Addr destIpAddr
Definition: ipcp.h:78