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-2019 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.6
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  strcpy(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  //A valid pointer to the interface being configured is required
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  memset(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 = strlen(interface->hostname);
145  //Limit the length of the string
147 
148  //Copy host name
149  strncpy(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  //Check parameter
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  //Check parameter
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 #if (DHCP_CLIENT_HOSTNAME_OPTION_SUPPORT == ENABLED)
993  size_t length;
994 #endif
995 
996  //DHCP message type
997  const uint8_t messageType = DHCP_MESSAGE_TYPE_DISCOVER;
998 
999  //Point to the underlying network interface
1000  interface = context->settings.interface;
1001  //Point to the logical interface
1002  logicalInterface = nicGetLogicalInterface(interface);
1003 
1004  //Allocate a memory buffer to hold the DHCP message
1005  buffer = udpAllocBuffer(DHCP_MIN_MSG_SIZE, &offset);
1006  //Failed to allocate buffer?
1007  if(buffer == NULL)
1008  return ERROR_OUT_OF_MEMORY;
1009 
1010  //Point to the beginning of the DHCP message
1011  message = netBufferAt(buffer, offset);
1012  //Clear memory buffer contents
1013  memset(message, 0, DHCP_MIN_MSG_SIZE);
1014 
1015  //Format DHCPDISCOVER message
1018  message->hlen = sizeof(MacAddr);
1019  message->xid = htonl(context->transactionId);
1020  message->secs = dhcpClientComputeElapsedTime(context);
1021  message->flags = HTONS(DHCP_FLAG_BROADCAST);
1022  message->ciaddr = IPV4_UNSPECIFIED_ADDR;
1023  message->chaddr = logicalInterface->macAddr;
1024 
1025  //Write magic cookie before setting any option
1026  message->magicCookie = HTONL(DHCP_MAGIC_COOKIE);
1027  //Properly terminate options field
1028  message->options[0] = DHCP_OPT_END;
1029 
1030  //DHCP Message Type option
1032  &messageType, sizeof(messageType));
1033 
1034 #if (DHCP_CLIENT_HOSTNAME_OPTION_SUPPORT == ENABLED)
1035  //Retrieve the length of the host name
1036  length = strlen(context->settings.hostname);
1037 
1038  //Any host name defined?
1039  if(length > 0)
1040  {
1041  //The Host Name option specifies the name of the client
1043  context->settings.hostname, length);
1044  }
1045 #endif
1046 
1047 #if (DHCP_CLIENT_ID_OPTION_SUPPORT == ENABLED)
1048  //Any client identifier defined?
1049  if(context->settings.clientIdLength > 0)
1050  {
1051  //DHCP servers use this value to index their database of address bindings
1053  context->settings.clientId, context->settings.clientIdLength);
1054  }
1055 #endif
1056 
1057  //Check whether rapid commit is enabled
1058  if(context->settings.rapidCommit)
1059  {
1060  //Include the Rapid Commit option if the client is prepared
1061  //to perform the DHCPDISCOVER-DHCPACK message exchange
1063  }
1064 
1065  //DHCP messages broadcast by a client prior to that client obtaining its
1066  //IP address must have the source address field in the IP header set to 0
1067  //(refer to RFC 2131, section 4.1)
1068  srcIpAddr.length = sizeof(Ipv4Addr);
1069  srcIpAddr.ipv4Addr = IPV4_UNSPECIFIED_ADDR;
1070 
1071  //Set destination IP address
1072  destIpAddr.length = sizeof(Ipv4Addr);
1073  destIpAddr.ipv4Addr = IPV4_BROADCAST_ADDR;
1074 
1075  //Debug message
1076  TRACE_DEBUG("\r\n%s: Sending DHCP message (%" PRIuSIZE " bytes)...\r\n",
1078 
1079  //Dump the contents of the message for debugging purpose
1081 
1082  //Broadcast DHCPDISCOVER message
1083  error = udpSendDatagramEx(interface, &srcIpAddr, DHCP_CLIENT_PORT,
1084  &destIpAddr, DHCP_SERVER_PORT, buffer, offset, IPV4_DEFAULT_TTL);
1085 
1086  //Free previously allocated memory
1087  netBufferFree(buffer);
1088  //Return status code
1089  return error;
1090 }
1091 
1092 
1093 /**
1094  * @brief Send DHCPREQUEST message
1095  * @param[in] context Pointer to the DHCP client context
1096  * @return Error code
1097  **/
1098 
1100 {
1101  uint_t i;
1102  error_t error;
1103  size_t offset;
1104  NetBuffer *buffer;
1105  NetInterface *interface;
1106  NetInterface *logicalInterface;
1108  IpAddr srcIpAddr;
1110 #if (DHCP_CLIENT_HOSTNAME_OPTION_SUPPORT == ENABLED)
1111  size_t length;
1112 #endif
1113 
1114  //DHCP message type
1115  const uint8_t messageType = DHCP_MESSAGE_TYPE_REQUEST;
1116 
1117  //Point to the underlying network interface
1118  interface = context->settings.interface;
1119  //Point to the logical interface
1120  logicalInterface = nicGetLogicalInterface(interface);
1121 
1122  //Index of the IP address in the list of addresses assigned to the interface
1123  i = context->settings.ipAddrIndex;
1124 
1125  //Allocate a memory buffer to hold the DHCP message
1126  buffer = udpAllocBuffer(DHCP_MIN_MSG_SIZE, &offset);
1127  //Failed to allocate buffer?
1128  if(buffer == NULL)
1129  return ERROR_OUT_OF_MEMORY;
1130 
1131  //Point to the beginning of the DHCP message
1132  message = netBufferAt(buffer, offset);
1133  //Clear memory buffer contents
1134  memset(message, 0, DHCP_MIN_MSG_SIZE);
1135 
1136  //Format DHCPREQUEST message
1139  message->hlen = sizeof(MacAddr);
1140  message->xid = htonl(context->transactionId);
1141  message->secs = dhcpClientComputeElapsedTime(context);
1142 
1143  //The client IP address must be included if the client is fully configured
1144  //and can respond to ARP requests
1145  if(context->state == DHCP_STATE_RENEWING ||
1146  context->state == DHCP_STATE_REBINDING)
1147  {
1148  message->flags = 0;
1149  message->ciaddr = interface->ipv4Context.addrList[i].addr;
1150  }
1151  else
1152  {
1153  message->flags = HTONS(DHCP_FLAG_BROADCAST);
1154  message->ciaddr = IPV4_UNSPECIFIED_ADDR;
1155  }
1156 
1157  //Client hardware address
1158  message->chaddr = logicalInterface->macAddr;
1159  //Write magic cookie before setting any option
1160  message->magicCookie = HTONL(DHCP_MAGIC_COOKIE);
1161  //Properly terminate options field
1162  message->options[0] = DHCP_OPT_END;
1163 
1164  //DHCP Message Type option
1166  &messageType, sizeof(messageType));
1167 
1168 #if (DHCP_CLIENT_HOSTNAME_OPTION_SUPPORT == ENABLED)
1169  //Retrieve the length of the host name
1170  length = strlen(context->settings.hostname);
1171 
1172  //Any host name defined?
1173  if(length > 0)
1174  {
1175  //The Host Name option specifies the name of the client
1177  context->settings.hostname, length);
1178  }
1179 #endif
1180 
1181 #if (DHCP_CLIENT_ID_OPTION_SUPPORT == ENABLED)
1182  //Any client identifier defined?
1183  if(context->settings.clientIdLength > 0)
1184  {
1185  //DHCP servers use this value to index their database of address bindings
1187  context->settings.clientId, context->settings.clientIdLength);
1188  }
1189 #endif
1190 
1191  //Server Identifier option
1192  if(context->state == DHCP_STATE_REQUESTING)
1193  {
1195  &context->serverIpAddr, sizeof(Ipv4Addr));
1196  }
1197 
1198  //Requested IP Address option
1199  if(context->state == DHCP_STATE_REQUESTING ||
1200  context->state == DHCP_STATE_REBOOTING)
1201  {
1203  &context->requestedIpAddr, sizeof(Ipv4Addr));
1204  }
1205 
1206  //Parameter Request List option
1208  dhcpOptionList, sizeof(dhcpOptionList));
1209 
1210  //IP address is being renewed?
1211  if(context->state == DHCP_STATE_RENEWING)
1212  {
1213  //Set source IP address
1214  srcIpAddr.length = sizeof(Ipv4Addr);
1215  srcIpAddr.ipv4Addr = interface->ipv4Context.addrList[i].addr;
1216 
1217  //The client transmits the message directly to the server that initially
1218  //granted the lease
1219  destIpAddr.length = sizeof(Ipv4Addr);
1220  destIpAddr.ipv4Addr = context->serverIpAddr;
1221  }
1222  else
1223  {
1224  //DHCP messages broadcast by a client prior to that client obtaining its
1225  //IP address must have the source address field in the IP header set to 0
1226  //(refer to RFC 2131, section 4.1)
1227  srcIpAddr.length = sizeof(Ipv4Addr);
1228  srcIpAddr.ipv4Addr = IPV4_UNSPECIFIED_ADDR;
1229 
1230  //Broadcast the message
1231  destIpAddr.length = sizeof(Ipv4Addr);
1232  destIpAddr.ipv4Addr = IPV4_BROADCAST_ADDR;
1233  }
1234 
1235  //Debug message
1236  TRACE_DEBUG("\r\n%s: Sending DHCP message (%" PRIuSIZE " bytes)...\r\n",
1238 
1239  //Dump the contents of the message for debugging purpose
1241 
1242  //Send DHCPREQUEST message
1243  error = udpSendDatagramEx(interface, &srcIpAddr, DHCP_CLIENT_PORT,
1244  &destIpAddr, DHCP_SERVER_PORT, buffer, offset, IPV4_DEFAULT_TTL);
1245 
1246  //Free previously allocated memory
1247  netBufferFree(buffer);
1248  //Return status code
1249  return error;
1250 }
1251 
1252 
1253 /**
1254  * @brief Send DHCPDECLINE message
1255  * @param[in] context Pointer to the DHCP client context
1256  * @return Error code
1257  **/
1258 
1260 {
1261  error_t error;
1262  size_t offset;
1263  NetBuffer *buffer;
1264  NetInterface *interface;
1265  NetInterface *logicalInterface;
1267  IpAddr srcIpAddr;
1269 
1270  //DHCP message type
1271  const uint8_t messageType = DHCP_MESSAGE_TYPE_DECLINE;
1272 
1273  //Point to the underlying network interface
1274  interface = context->settings.interface;
1275  //Point to the logical interface
1276  logicalInterface = nicGetLogicalInterface(interface);
1277 
1278  //Allocate a memory buffer to hold the DHCP message
1279  buffer = udpAllocBuffer(DHCP_MIN_MSG_SIZE, &offset);
1280  //Failed to allocate buffer?
1281  if(buffer == NULL)
1282  return ERROR_OUT_OF_MEMORY;
1283 
1284  //Point to the beginning of the DHCP message
1285  message = netBufferAt(buffer, offset);
1286  //Clear memory buffer contents
1287  memset(message, 0, DHCP_MIN_MSG_SIZE);
1288 
1289  //Format DHCPDECLINE message
1292  message->hlen = sizeof(MacAddr);
1293  message->xid = htonl(context->transactionId);
1294  message->secs = 0;
1295  message->flags = 0;
1296  message->ciaddr = IPV4_UNSPECIFIED_ADDR;
1297  message->chaddr = logicalInterface->macAddr;
1298 
1299  //Write magic cookie before setting any option
1300  message->magicCookie = HTONL(DHCP_MAGIC_COOKIE);
1301  //Properly terminate options field
1302  message->options[0] = DHCP_OPT_END;
1303 
1304  //DHCP Message Type option
1306  &messageType, sizeof(messageType));
1307  //Server Identifier option
1309  &context->serverIpAddr, sizeof(Ipv4Addr));
1310  //Requested IP Address option
1312  &context->requestedIpAddr, sizeof(Ipv4Addr));
1313 
1314  //Use the unspecified address as source address
1315  srcIpAddr.length = sizeof(Ipv4Addr);
1316  srcIpAddr.ipv4Addr = IPV4_UNSPECIFIED_ADDR;
1317 
1318  //Set destination IP address
1319  destIpAddr.length = sizeof(Ipv4Addr);
1320  destIpAddr.ipv4Addr = IPV4_BROADCAST_ADDR;
1321 
1322  //Debug message
1323  TRACE_DEBUG("\r\n%s: Sending DHCP message (%" PRIuSIZE " bytes)...\r\n",
1325 
1326  //Dump the contents of the message for debugging purpose
1328 
1329  //Broadcast DHCPDECLINE message
1330  error = udpSendDatagramEx(interface, &srcIpAddr, DHCP_CLIENT_PORT,
1331  &destIpAddr, DHCP_SERVER_PORT, buffer, offset, IPV4_DEFAULT_TTL);
1332 
1333  //Free previously allocated memory
1334  netBufferFree(buffer);
1335  //Return status code
1336  return error;
1337 }
1338 
1339 
1340 /**
1341  * @brief Process incoming DHCP message
1342  * @param[in] interface Underlying network interface
1343  * @param[in] pseudoHeader UDP pseudo header
1344  * @param[in] udpHeader UDP header
1345  * @param[in] buffer Multi-part buffer containing the incoming DHCP message
1346  * @param[in] offset Offset to the first byte of the DHCP message
1347  * @param[in] param Pointer to the DHCP client context
1348  **/
1349 
1351  const IpPseudoHeader *pseudoHeader, const UdpHeader *udpHeader,
1352  const NetBuffer *buffer, size_t offset, void *param)
1353 {
1354  size_t length;
1355  DhcpClientContext *context;
1357  DhcpOption *option;
1358 
1359  //Point to the DHCP client context
1360  context = (DhcpClientContext *) param;
1361 
1362  //Retrieve the length of the DHCP message
1363  length = netBufferGetLength(buffer) - offset;
1364 
1365  //Make sure the DHCP message is valid
1366  if(length < sizeof(DhcpMessage))
1367  return;
1369  return;
1370 
1371  //Point to the beginning of the DHCP message
1372  message = netBufferAt(buffer, offset);
1373  //Sanity check
1374  if(message == NULL)
1375  return;
1376 
1377  //Debug message
1378  TRACE_DEBUG("\r\n%s: DHCP message received (%" PRIuSIZE " bytes)...\r\n",
1380 
1381  //Dump the contents of the message for debugging purpose
1383 
1384  //The DHCP server shall respond with a BOOTREPLY opcode
1385  if(message->op != DHCP_OPCODE_BOOTREPLY)
1386  return;
1387  //Enforce hardware type
1388  if(message->htype != DHCP_HARDWARE_TYPE_ETH)
1389  return;
1390  //Check the length of the hardware address
1391  if(message->hlen != sizeof(MacAddr))
1392  return;
1393  //Check magic cookie
1394  if(message->magicCookie != HTONL(DHCP_MAGIC_COOKIE))
1395  return;
1396 
1397  //The DHCP Message Type option must be included in every DHCP message
1399 
1400  //Failed to retrieve the Message Type option?
1401  if(option == NULL || option->length != 1)
1402  return;
1403 
1404  //Check message type
1405  switch(option->value[0])
1406  {
1408  //Parse DHCPOFFER message
1409  dhcpClientParseOffer(context, message, length);
1410  break;
1411  case DHCP_MESSAGE_TYPE_ACK:
1412  //Parse DHCPACK message
1413  dhcpClientParseAck(context, message, length);
1414  break;
1415  case DHCP_MESSAGE_TYPE_NAK:
1416  //Parse DHCPNAK message
1417  dhcpClientParseNak(context, message, length);
1418  break;
1419  default:
1420  //Silently drop incoming message
1421  break;
1422  }
1423 }
1424 
1425 
1426 /**
1427  * @brief Parse DHCPOFFER message
1428  * @param[in] context Pointer to the DHCP client context
1429  * @param[in] message Pointer to the incoming DHCP message
1430  * @param[in] length Length of the incoming message to parse
1431  **/
1432 
1434  const DhcpMessage *message, size_t length)
1435 {
1436  DhcpOption *serverIdOption;
1437  NetInterface *interface;
1438  NetInterface *logicalInterface;
1439 
1440  //Point to the underlying network interface
1441  interface = context->settings.interface;
1442  //Point to the logical interface
1443  logicalInterface = nicGetLogicalInterface(interface);
1444 
1445  //Discard any received packet that does not match the transaction ID
1446  if(ntohl(message->xid) != context->transactionId)
1447  return;
1448  //Make sure the IP address offered to the client is valid
1449  if(message->yiaddr == IPV4_UNSPECIFIED_ADDR)
1450  return;
1451  //Check MAC address
1452  if(!macCompAddr(&message->chaddr, &logicalInterface->macAddr))
1453  return;
1454 
1455  //Make sure that the DHCPOFFER message is received in response to
1456  //a DHCPDISCOVER message
1457  if(context->state != DHCP_STATE_SELECTING)
1458  return;
1459 
1460  //A DHCP server always returns its own address in the Server Identifier option
1462 
1463  //Failed to retrieve the Server Identifier option?
1464  if(serverIdOption == NULL || serverIdOption->length != 4)
1465  return;
1466 
1467  //Record the IP address of the DHCP server
1468  ipv4CopyAddr(&context->serverIpAddr, serverIdOption->value);
1469  //Record the IP address offered to the client
1470  context->requestedIpAddr = message->yiaddr;
1471 
1472  //Switch to the REQUESTING state
1474 }
1475 
1476 
1477 /**
1478  * @brief Parse DHCPACK message
1479  * @param[in] context Pointer to the DHCP client context
1480  * @param[in] message Pointer to the incoming DHCP message
1481  * @param[in] length Length of the incoming message to parse
1482  * @return Error code
1483  **/
1484 
1486  const DhcpMessage *message, size_t length)
1487 {
1488  uint_t i;
1489  uint_t j;
1490  uint_t n;
1491  DhcpOption *option;
1492  DhcpOption *serverIdOption;
1493  NetInterface *interface;
1494  NetInterface *logicalInterface;
1495  NetInterface *physicalInterface;
1496 
1497  //Point to the underlying network interface
1498  interface = context->settings.interface;
1499  //Point to the logical interface
1500  logicalInterface = nicGetLogicalInterface(interface);
1501  //Point to the physical interface
1502  physicalInterface = nicGetPhysicalInterface(interface);
1503 
1504  //Index of the IP address in the list of addresses assigned to the interface
1505  i = context->settings.ipAddrIndex;
1506 
1507  //Discard any received packet that does not match the transaction ID
1508  if(ntohl(message->xid) != context->transactionId)
1509  return;
1510  //Make sure the IP address assigned to the client is valid
1511  if(message->yiaddr == IPV4_UNSPECIFIED_ADDR)
1512  return;
1513  //Check MAC address
1514  if(!macCompAddr(&message->chaddr, &logicalInterface->macAddr))
1515  return;
1516 
1517  //A DHCP server always returns its own address in the Server Identifier option
1519 
1520  //Failed to retrieve the Server Identifier option?
1521  if(serverIdOption == NULL || serverIdOption->length != 4)
1522  return;
1523 
1524  //Check current state
1525  if(context->state == DHCP_STATE_SELECTING)
1526  {
1527  //A DHCPACK message is not acceptable when rapid commit is disallowed
1528  if(!context->settings.rapidCommit)
1529  return;
1530 
1531  //Search for the Rapid Commit option
1533 
1534  //A server must include this option in a DHCPACK message sent
1535  //in a response to a DHCPDISCOVER message when completing the
1536  //DHCPDISCOVER-DHCPACK message exchange
1537  if(option == NULL || option->length != 0)
1538  return;
1539  }
1540  else if(context->state == DHCP_STATE_REQUESTING ||
1541  context->state == DHCP_STATE_RENEWING)
1542  {
1543  //Check the server identifier
1544  if(!ipv4CompAddr(serverIdOption->value, &context->serverIpAddr))
1545  return;
1546  }
1547  else if(context->state == DHCP_STATE_REBOOTING ||
1548  context->state == DHCP_STATE_REBINDING)
1549  {
1550  //Do not check the server identifier
1551  }
1552  else
1553  {
1554  //Silently discard the DHCPACK message
1555  return;
1556  }
1557 
1558  //Retrieve IP Address Lease Time option
1560 
1561  //Failed to retrieve specified option?
1562  if(option == NULL || option->length != 4)
1563  return;
1564 
1565  //Record the lease time
1566  context->leaseTime = LOAD32BE(option->value);
1567 
1568  //Retrieve Renewal Time Value option
1570 
1571  //Specified option found?
1572  if(option != NULL && option->length == 4)
1573  {
1574  //This option specifies the time interval from address assignment
1575  //until the client transitions to the RENEWING state
1576  context->t1 = LOAD32BE(option->value);
1577  }
1578  else if(context->leaseTime != DHCP_INFINITE_TIME)
1579  {
1580  //By default, T1 is set to 50% of the lease time
1581  context->t1 = context->leaseTime / 2;
1582  }
1583  else
1584  {
1585  //Infinite lease
1586  context->t1 = DHCP_INFINITE_TIME;
1587  }
1588 
1589  //Retrieve Rebinding Time value option
1591 
1592  //Specified option found?
1593  if(option != NULL && option->length == 4)
1594  {
1595  //This option specifies the time interval from address assignment
1596  //until the client transitions to the REBINDING state
1597  context->t2 = LOAD32BE(option->value);
1598  }
1599  else if(context->leaseTime != DHCP_INFINITE_TIME)
1600  {
1601  //By default, T2 is set to 87.5% of the lease time
1602  context->t2 = context->leaseTime * 7 / 8;
1603  }
1604  else
1605  {
1606  //Infinite lease
1607  context->t2 = DHCP_INFINITE_TIME;
1608  }
1609 
1610  //Retrieve Subnet Mask option
1612 
1613  //The specified option has been found?
1614  if(option != NULL && option->length == sizeof(Ipv4Addr))
1615  {
1616  //Save subnet mask
1617  ipv4CopyAddr(&interface->ipv4Context.addrList[i].subnetMask,
1618  option->value);
1619  }
1620 
1621  //Retrieve Router option
1623 
1624  //The specified option has been found?
1625  if(option != NULL && !(option->length % sizeof(Ipv4Addr)))
1626  {
1627  //Save default gateway
1628  if(option->length >= sizeof(Ipv4Addr))
1629  {
1630  ipv4CopyAddr(&interface->ipv4Context.addrList[i].defaultGateway,
1631  option->value);
1632  }
1633  }
1634 
1635  //Use the DNS servers provided by the DHCP server?
1636  if(!context->settings.manualDnsConfig)
1637  {
1638  //Retrieve DNS Server option
1640 
1641  //The specified option has been found?
1642  if(option != NULL && !(option->length % sizeof(Ipv4Addr)))
1643  {
1644  //Get the number of addresses provided in the response
1645  n = option->length / sizeof(Ipv4Addr);
1646 
1647  //Loop through the list of addresses
1648  for(j = 0; j < n && j < IPV4_DNS_SERVER_LIST_SIZE; j++)
1649  {
1650  //Save DNS server address
1651  ipv4CopyAddr(&interface->ipv4Context.dnsServerList[j],
1652  option->value + j * sizeof(Ipv4Addr));
1653  }
1654  }
1655  }
1656 
1657  //Retrieve MTU option
1659 
1660  //The specified option has been found?
1661  if(option != NULL && option->length == 2)
1662  {
1663  //This option specifies the MTU to use on this interface
1664  n = LOAD16BE(option->value);
1665 
1666  //Make sure that the option's value is acceptable
1667  if(n >= IPV4_MINIMUM_MTU && n <= physicalInterface->nicDriver->mtu)
1668  {
1669  //Set the MTU to be used on the interface
1670  interface->ipv4Context.linkMtu = n;
1671  }
1672  }
1673 
1674  //Record the IP address of the DHCP server
1675  ipv4CopyAddr(&context->serverIpAddr, serverIdOption->value);
1676  //Record the IP address assigned to the client
1677  context->requestedIpAddr = message->yiaddr;
1678 
1679  //Save the time a which the lease was obtained
1680  context->leaseStartTime = osGetSystemTime();
1681 
1682  //Check current state
1683  if(context->state == DHCP_STATE_REQUESTING ||
1684  context->state == DHCP_STATE_REBOOTING)
1685  {
1686  //Use the IP address as a tentative address
1687  interface->ipv4Context.addrList[i].addr = message->yiaddr;
1688  interface->ipv4Context.addrList[i].state = IPV4_ADDR_STATE_TENTATIVE;
1689 
1690  //Clear conflict flag
1691  interface->ipv4Context.addrList[i].conflict = FALSE;
1692 
1693  //The client should probe the newly received address
1695  }
1696  else
1697  {
1698  //Assign the IP address to the client
1699  interface->ipv4Context.addrList[i].addr = message->yiaddr;
1700  interface->ipv4Context.addrList[i].state = IPV4_ADDR_STATE_VALID;
1701 
1702 #if (MDNS_RESPONDER_SUPPORT == ENABLED)
1703  //Restart mDNS probing process
1704  mdnsResponderStartProbing(interface->mdnsResponderContext);
1705 #endif
1706  //The client transitions to the BOUND state
1708  }
1709 }
1710 
1711 
1712 /**
1713  * @brief Parse DHCPNAK message
1714  * @param[in] context Pointer to the DHCP client context
1715  * @param[in] message Pointer to the incoming DHCP message
1716  * @param[in] length Length of the incoming message to parse
1717  * @return Error code
1718  **/
1719 
1721  const DhcpMessage *message, size_t length)
1722 {
1723  uint_t i;
1724  DhcpOption *serverIdOption;
1725  NetInterface *interface;
1726  NetInterface *logicalInterface;
1727 
1728  //Point to the underlying network interface
1729  interface = context->settings.interface;
1730  //Point to the logical interface
1731  logicalInterface = nicGetLogicalInterface(interface);
1732 
1733  //Index of the IP address in the list of addresses assigned to the interface
1734  i = context->settings.ipAddrIndex;
1735 
1736  //Discard any received packet that does not match the transaction ID
1737  if(ntohl(message->xid) != context->transactionId)
1738  return;
1739  //Check MAC address
1740  if(!macCompAddr(&message->chaddr, &logicalInterface->macAddr))
1741  return;
1742 
1743  //A DHCP server always returns its own address in the Server Identifier option
1745 
1746  //Failed to retrieve the Server Identifier option?
1747  if(serverIdOption == NULL || serverIdOption->length != 4)
1748  return;
1749 
1750  //Check current state
1751  if(context->state == DHCP_STATE_REQUESTING ||
1752  context->state == DHCP_STATE_RENEWING)
1753  {
1754  //Check the server identifier
1755  if(!ipv4CompAddr(serverIdOption->value, &context->serverIpAddr))
1756  return;
1757  }
1758  else if(context->state == DHCP_STATE_REBOOTING ||
1759  context->state == DHCP_STATE_REBINDING)
1760  {
1761  //Do not check the server identifier
1762  }
1763  else
1764  {
1765  //Silently discard the DHCPNAK message
1766  return;
1767  }
1768 
1769  //The host address is no longer appropriate for the link
1770  interface->ipv4Context.addrList[i].addr = IPV4_UNSPECIFIED_ADDR;
1771  interface->ipv4Context.addrList[i].state = IPV4_ADDR_STATE_INVALID;
1772 
1773  //Clear subnet mask
1774  interface->ipv4Context.addrList[i].subnetMask = IPV4_UNSPECIFIED_ADDR;
1775 
1776 #if (MDNS_RESPONDER_SUPPORT == ENABLED)
1777  //Restart mDNS probing process
1778  mdnsResponderStartProbing(interface->mdnsResponderContext);
1779 #endif
1780 
1781  //Restart DHCP configuration
1783 }
1784 
1785 
1786 /**
1787  * @brief Manage DHCP configuration timeout
1788  * @param[in] context Pointer to the DHCP client context
1789  **/
1790 
1792 {
1793  systime_t time;
1794  NetInterface *interface;
1795 
1796  //Point to the underlying network interface
1797  interface = context->settings.interface;
1798 
1799  //Get current time
1800  time = osGetSystemTime();
1801 
1802  //Any registered callback?
1803  if(context->settings.timeoutEvent != NULL)
1804  {
1805  //DHCP configuration timeout?
1806  if(timeCompare(time, context->configStartTime + context->settings.timeout) >= 0)
1807  {
1808  //Ensure the callback function is only called once
1809  if(!context->timeoutEventDone)
1810  {
1811  //Release exclusive access
1813  //Invoke user callback function
1814  context->settings.timeoutEvent(context, interface);
1815  //Get exclusive access
1817 
1818  //Set flag
1819  context->timeoutEventDone = TRUE;
1820  }
1821  }
1822  }
1823 }
1824 
1825 
1826 /**
1827  * @brief Compute the appropriate secs field
1828  *
1829  * Compute the number of seconds elapsed since the client began
1830  * address acquisition or renewal process
1831  *
1832  * @param[in] context Pointer to the DHCP client context
1833  * @return The elapsed time expressed in seconds
1834  **/
1835 
1837 {
1838  systime_t time;
1839 
1840  //Compute the time elapsed since the DHCP configuration process started
1841  time = (osGetSystemTime() - context->configStartTime) / 1000;
1842 
1843  //The value 0xFFFF is used to represent any elapsed time values
1844  //greater than the largest time value that can be represented
1845  time = MIN(time, 0xFFFF);
1846 
1847  //Convert the 16-bit value to network byte order
1848  return htons(time);
1849 }
1850 
1851 
1852 /**
1853  * @brief Update DHCP FSM state
1854  * @param[in] context Pointer to the DHCP client context
1855  * @param[in] newState New DHCP state to switch to
1856  * @param[in] delay Initial delay
1857  **/
1858 
1860  DhcpState newState, systime_t delay)
1861 {
1862  systime_t time;
1863 
1864  //Get current time
1865  time = osGetSystemTime();
1866 
1867 #if (DHCP_TRACE_LEVEL >= TRACE_LEVEL_INFO)
1868  //Sanity check
1869  if(newState <= DHCP_STATE_REBINDING)
1870  {
1871  //DHCP FSM states
1872  static const char_t *stateLabel[] =
1873  {
1874  "INIT",
1875  "SELECTING",
1876  "REQUESTING",
1877  "INIT-REBOOT",
1878  "REBOOTING",
1879  "PROBING",
1880  "BOUND",
1881  "RENEWING",
1882  "REBINDING"
1883  };
1884 
1885  //Debug message
1886  TRACE_INFO("%s: DHCP client %s state\r\n",
1887  formatSystemTime(time, NULL), stateLabel[newState]);
1888  }
1889 #endif
1890 
1891  //Set time stamp
1892  context->timestamp = time;
1893  //Set initial delay
1894  context->timeout = delay;
1895  //Reset retransmission counter
1896  context->retransmitCount = 0;
1897  //Switch to the new state
1898  context->state = newState;
1899 
1900  //Any registered callback?
1901  if(context->settings.stateChangeEvent != NULL)
1902  {
1903  NetInterface *interface;
1904 
1905  //Point to the underlying network interface
1906  interface = context->settings.interface;
1907 
1908  //Release exclusive access
1910  //Invoke user callback function
1911  context->settings.stateChangeEvent(context, interface, newState);
1912  //Get exclusive access
1914  }
1915 }
1916 
1917 
1918 /**
1919  * @brief Dump DHCP configuration for debugging purpose
1920  * @param[in] context Pointer to the DHCP client context
1921  **/
1922 
1924 {
1925 #if (DHCP_TRACE_LEVEL >= TRACE_LEVEL_INFO)
1926  uint_t i;
1927  uint_t j;
1928  NetInterface *interface;
1929  Ipv4Context *ipv4Context;
1930 
1931  //Point to the underlying network interface
1932  interface = context->settings.interface;
1933  //Point to the IPv4 context
1934  ipv4Context = &interface->ipv4Context;
1935 
1936  //Index of the IP address in the list of addresses assigned to the interface
1937  i = context->settings.ipAddrIndex;
1938 
1939  //Debug message
1940  TRACE_INFO("\r\n");
1941  TRACE_INFO("DHCP configuration:\r\n");
1942 
1943  //Lease start time
1944  TRACE_INFO(" Lease Start Time = %s\r\n",
1945  formatSystemTime(context->leaseStartTime, NULL));
1946 
1947  //Lease time
1948  TRACE_INFO(" Lease Time = %" PRIu32 "s\r\n", context->leaseTime);
1949  //Renewal time
1950  TRACE_INFO(" T1 = %" PRIu32 "s\r\n", context->t1);
1951  //Rebinding time
1952  TRACE_INFO(" T2 = %" PRIu32 "s\r\n", context->t2);
1953 
1954  //Host address
1955  TRACE_INFO(" IPv4 Address = %s\r\n",
1956  ipv4AddrToString(ipv4Context->addrList[i].addr, NULL));
1957 
1958  //Subnet mask
1959  TRACE_INFO(" Subnet Mask = %s\r\n",
1960  ipv4AddrToString(ipv4Context->addrList[i].subnetMask, NULL));
1961 
1962  //Default gateway
1963  TRACE_INFO(" Default Gateway = %s\r\n",
1964  ipv4AddrToString(ipv4Context->addrList[i].defaultGateway, NULL));
1965 
1966  //DNS servers
1967  for(j = 0; j < IPV4_DNS_SERVER_LIST_SIZE; j++)
1968  {
1969  TRACE_INFO(" DNS Server %u = %s\r\n", j + 1,
1970  ipv4AddrToString(ipv4Context->dnsServerList[j], NULL));
1971  }
1972 
1973  //Maximum transmit unit
1974  TRACE_INFO(" MTU = %" PRIuSIZE "\r\n", interface->ipv4Context.linkMtu);
1975  TRACE_INFO("\r\n");
1976 #endif
1977 }
1978 
1979 #endif
void dhcpClientStateRebinding(DhcpClientContext *context)
REBINDING state.
Definition: dhcp_client.c:902
error_t udpSendDatagramEx(NetInterface *interface, const IpAddr *srcIpAddr, uint16_t srcPort, const IpAddr *destIpAddr, uint16_t destPort, NetBuffer *buffer, size_t offset, uint_t flags)
Send a UDP datagram (raw interface)
Definition: udp.c:463
#define htons(value)
Definition: cpu_endian.h:392
void dhcpClientChangeState(DhcpClientContext *context, DhcpState newState, systime_t delay)
Update DHCP FSM state.
Definition: dhcp_client.c:1859
void dhcpClientParseOffer(DhcpClientContext *context, const DhcpMessage *message, size_t length)
Parse DHCPOFFER message.
Definition: dhcp_client.c:1433
error_t dhcpDumpMessage(const DhcpMessage *message, size_t length)
Dump DHCP message for debugging purpose.
Definition: dhcp_debug.c:158
uint8_t length
Definition: dtls_misc.h:149
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)
__start_packed struct @124 DhcpOption
DHCP option.
#define LOAD32BE(p)
Definition: cpu_endian.h:194
DhcpLinkChangeCallback linkChangeEvent
Link state change event.
Definition: dhcp_client.h:223
IP network address.
Definition: ip.h:71
@ DHCP_OPT_CLIENT_IDENTIFIER
Definition: dhcp_common.h:167
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
DhcpTimeoutCallback timeoutEvent
DHCP configuration timeout event.
Definition: dhcp_client.h:222
error_t dhcpClientSendDecline(DhcpClientContext *context)
Send DHCPDECLINE message.
Definition: dhcp_client.c:1259
@ DHCP_MESSAGE_TYPE_OFFER
Definition: dhcp_common.h:90
#define DHCP_INFINITE_TIME
Definition: dhcp_common.h:53
@ DHCP_OPT_SERVER_IDENTIFIER
Definition: dhcp_common.h:160
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
@ DHCP_MESSAGE_TYPE_ACK
Definition: dhcp_common.h:93
#define DHCP_CLIENT_REQUEST_MIN_DELAY
Definition: dhcp_client.h:126
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
systime_t dhcpClientTickCounter
Definition: dhcp_client.c:55
#define DHCP_MAGIC_COOKIE
Definition: dhcp_common.h:51
IPv4 context.
Definition: ipv4.h:338
@ DHCP_OPT_ROUTER
Definition: dhcp_common.h:109
#define DhcpClientContext
Definition: dhcp_client.h:154
@ DHCP_MESSAGE_TYPE_REQUEST
Definition: dhcp_common.h:91
error_t dhcpClientStart(DhcpClientContext *context)
Start DHCP client.
Definition: dhcp_client.c:181
__start_packed struct @123 DhcpMessage
DHCP message.
IP pseudo header.
Definition: ip.h:90
@ DHCP_OPT_END
Definition: dhcp_common.h:183
void dhcpClientCheckTimeout(DhcpClientContext *context)
Manage DHCP configuration timeout.
Definition: dhcp_client.c:1791
#define FALSE
Definition: os_port.h:46
@ DHCP_STATE_INIT_REBOOT
Definition: dhcp_client.h:171
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
#define htonl(value)
Definition: cpu_endian.h:393
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:391
error_t
Error codes.
Definition: error.h:42
@ IPV4_ADDR_STATE_TENTATIVE
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:1720
@ DHCP_MESSAGE_TYPE_DISCOVER
Definition: dhcp_common.h:89
void dhcpClientDumpConfig(DhcpClientContext *context)
Dump DHCP configuration for debugging purpose.
Definition: dhcp_client.c:1923
#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:1099
uint16_t dhcpClientComputeElapsedTime(DhcpClientContext *context)
Compute the appropriate secs field.
Definition: dhcp_client.c:1836
#define DHCP_MIN_MSG_SIZE
Definition: dhcp_common.h:44
@ DHCP_OPT_HOST_NAME
Definition: dhcp_common.h:118
#define IPV4_DNS_SERVER_LIST_SIZE
Definition: ipv4.h:70
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:764
void netBufferFree(NetBuffer *buffer)
Dispose a multi-part buffer.
Definition: net_mem.c:282
NetInterface * netGetDefaultInterface(void)
Get default network interface.
Definition: net.c:1782
DhcpStateChangeCallback stateChangeEvent
FSM state change event.
Definition: dhcp_client.h:224
@ DHCP_OPT_IP_ADDRESS_LEASE_TIME
Definition: dhcp_common.h:157
@ DHCP_OPT_DHCP_MESSAGE_TYPE
Definition: dhcp_common.h:159
OsMutex netMutex
Definition: net.c:75
error_t dhcpClientInit(DhcpClientContext *context, const DhcpClientSettings *settings)
DHCP client initialization.
Definition: dhcp_client.c:114
@ DHCP_FLAG_BROADCAST
Definition: dhcp_common.h:79
@ DHCP_STATE_REBOOTING
Definition: dhcp_client.h:172
__start_packed struct @122 UdpHeader
UDP header.
Definitions common to DHCP client and server.
uint32_t t2
DHCP client settings.
Definition: dhcp_client.h:208
#define TRACE_INFO(...)
Definition: debug.h:94
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
@ DHCP_STATE_REBINDING
Definition: dhcp_client.h:176
#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:697
@ DHCP_MESSAGE_TYPE_NAK
Definition: dhcp_common.h:94
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:1810
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:1841
#define IPV4_DEFAULT_TTL
Definition: ipv4.h:56
DhcpState dhcpClientGetState(DhcpClientContext *context)
Retrieve current state.
Definition: dhcp_client.c:258
@ DHCP_STATE_REQUESTING
Definition: dhcp_client.h:170
@ DHCP_OPCODE_BOOTREPLY
Definition: dhcp_common.h:68
#define DHCP_CLIENT_REQUEST_INIT_RT
Definition: dhcp_client.h:112
#define TRACE_DEBUG(...)
Definition: debug.h:106
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
@ DHCP_OPCODE_BOOTREQUEST
Definition: dhcp_common.h:67
@ DHCP_OPT_INTERFACE_MTU
Definition: dhcp_common.h:132
@ DHCP_STATE_BOUND
Definition: dhcp_client.h:174
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
@ DHCP_STATE_SELECTING
Definition: dhcp_client.h:169
@ DHCP_OPT_REBINDING_TIME_VALUE
Definition: dhcp_common.h:165
#define HTONS(value)
Definition: cpu_endian.h:390
uint8_t n
DhcpState
DHCP FSM states.
Definition: dhcp_client.h:166
@ DHCP_STATE_PROBING
Definition: dhcp_client.h:173
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
Data logging functions for debugging purpose (DHCP)
@ DHCP_MESSAGE_TYPE_DECLINE
Definition: dhcp_common.h:92
@ IPV4_ADDR_STATE_INVALID
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.
@ DHCP_OPT_SUBNET_MASK
Definition: dhcp_common.h:107
@ DHCP_OPT_DNS_SERVER
Definition: dhcp_common.h:112
bool_t manualDnsConfig
Force manual DNS configuration.
Definition: dhcp_client.h:220
#define macCompAddr(macAddr1, macAddr2)
Definition: ethernet.h:107
uint8_t message[]
Definition: chap.h:152
#define DHCP_CLIENT_DISCOVER_MAX_RT
Definition: dhcp_client.h:98
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
@ DHCP_STATE_INIT
Definition: dhcp_client.h:168
error_t dhcpClientSendDiscover(DhcpClientContext *context)
Send DHCPDISCOVER message.
Definition: dhcp_client.c:982
@ IPV4_ADDR_STATE_VALID
An address assigned to an interface whose use is unrestricted.
Definition: ipv4.h:191
#define MAX_DELAY
Definition: os_port.h:76
@ DHCP_OPT_PARAM_REQUEST_LIST
Definition: dhcp_common.h:161
#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:170
TCP/IP stack core.
NetInterface * nicGetLogicalInterface(NetInterface *interface)
Retrieve logical interface.
Definition: nic.c:52
#define DHCP_CLIENT_PORT
Definition: dhcp_common.h:41
@ DHCP_OPT_REQUESTED_IP_ADDRESS
Definition: dhcp_common.h:156
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:1466
#define IPV4_MINIMUM_MTU
Definition: ipv4.h:85
@ DHCP_OPT_RENEWAL_TIME_VALUE
Definition: dhcp_common.h:164
#define DHCP_CLIENT_DISCOVER_INIT_RT
Definition: dhcp_client.h:91
void dhcpClientProcessMessage(NetInterface *interface, const IpPseudoHeader *pseudoHeader, const UdpHeader *udpHeader, const NetBuffer *buffer, size_t offset, void *param)
Process incoming DHCP message.
Definition: dhcp_client.c:1350
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:399
error_t mdnsResponderStartProbing(MdnsResponderContext *context)
Restart probing process.
void dhcpClientStateSelecting(DhcpClientContext *context)
SELECTING state.
Definition: dhcp_client.c:466
@ NO_ERROR
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.
@ DHCP_STATE_RENEWING
Definition: dhcp_client.h:175
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:806
@ DHCP_OPT_RAPID_COMMIT
Definition: dhcp_common.h:181
void dhcpClientParseAck(DhcpClientContext *context, const DhcpMessage *message, size_t length)
Parse DHCPACK message.
Definition: dhcp_client.c:1485
#define IPV4_UNSPECIFIED_ADDR
Definition: ipv4.h:104
__start_packed struct @108 MacAddr
MAC address.
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