]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_DHCP.c
commit 9f316c246baafa15c542a5aea81a94f26e3d6507
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-TCP / FreeRTOS_DHCP.c
1 /*
2  * FreeRTOS+TCP V2.2.1
3  * Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of
6  * this software and associated documentation files (the "Software"), to deal in
7  * the Software without restriction, including without limitation the rights to
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9  * the Software, and to permit persons to whom the Software is furnished to do so,
10  * subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in all
13  * copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * http://aws.amazon.com/freertos
23  * http://www.FreeRTOS.org
24  */
25
26 /* Standard includes. */
27 #include <stdint.h>
28
29 /* FreeRTOS includes. */
30 #include "FreeRTOS.h"
31 #include "task.h"
32 #include "semphr.h"
33
34 /* FreeRTOS+TCP includes. */
35 #include "FreeRTOS_IP.h"
36 #include "FreeRTOS_Sockets.h"
37 #include "FreeRTOS_IP_Private.h"
38 #include "FreeRTOS_UDP_IP.h"
39 #include "FreeRTOS_TCP_IP.h"
40 #include "FreeRTOS_DHCP.h"
41 #include "FreeRTOS_ARP.h"
42 #include "NetworkInterface.h"
43 #include "NetworkBufferManagement.h"
44
45 /* Exclude the entire file if DHCP is not enabled. */
46 #if( ipconfigUSE_DHCP != 0 )
47
48 #if ( ipconfigUSE_DHCP != 0 ) && ( ipconfigNETWORK_MTU < 586u )
49         /* DHCP must be able to receive an options field of 312 bytes, the fixed
50         part of the DHCP packet is 240 bytes, and the IP/UDP headers take 28 bytes. */
51         #error ipconfigNETWORK_MTU needs to be at least 586 to use DHCP
52 #endif
53
54 /* Parameter widths in the DHCP packet. */
55 #define dhcpCLIENT_HARDWARE_ADDRESS_LENGTH              16
56 #define dhcpSERVER_HOST_NAME_LENGTH                             64
57 #define dhcpBOOT_FILE_NAME_LENGTH                               128
58
59 /* Timer parameters */
60 #ifndef dhcpINITIAL_DHCP_TX_PERIOD
61         #define dhcpINITIAL_TIMER_PERIOD                        ( pdMS_TO_TICKS( 250 ) )
62         #define dhcpINITIAL_DHCP_TX_PERIOD                      ( pdMS_TO_TICKS( 5000 ) )
63 #endif
64
65 /* Codes of interest found in the DHCP options field. */
66 #define dhcpZERO_PAD_OPTION_CODE                                ( 0u )
67 #define dhcpSUBNET_MASK_OPTION_CODE                             ( 1u )
68 #define dhcpGATEWAY_OPTION_CODE                                 ( 3u )
69 #define dhcpDNS_SERVER_OPTIONS_CODE                             ( 6u )
70 #define dhcpDNS_HOSTNAME_OPTIONS_CODE                   ( 12u )
71 #define dhcpREQUEST_IP_ADDRESS_OPTION_CODE              ( 50u )
72 #define dhcpLEASE_TIME_OPTION_CODE                              ( 51u )
73 #define dhcpMESSAGE_TYPE_OPTION_CODE                    ( 53u )
74 #define dhcpSERVER_IP_ADDRESS_OPTION_CODE               ( 54u )
75 #define dhcpPARAMETER_REQUEST_OPTION_CODE               ( 55u )
76 #define dhcpCLIENT_IDENTIFIER_OPTION_CODE               ( 61u )
77
78 /* The four DHCP message types of interest. */
79 #define dhcpMESSAGE_TYPE_DISCOVER                               ( 1 )
80 #define dhcpMESSAGE_TYPE_OFFER                                  ( 2 )
81 #define dhcpMESSAGE_TYPE_REQUEST                                ( 3 )
82 #define dhcpMESSAGE_TYPE_ACK                                    ( 5 )
83 #define dhcpMESSAGE_TYPE_NACK                                   ( 6 )
84
85 /* Offsets into the transmitted DHCP options fields at which various parameters
86 are located. */
87 #define dhcpCLIENT_IDENTIFIER_OFFSET                    ( 6 )
88 #define dhcpREQUESTED_IP_ADDRESS_OFFSET                 ( 14 )
89 #define dhcpDHCP_SERVER_IP_ADDRESS_OFFSET               ( 20 )
90
91 /* Values used in the DHCP packets. */
92 #define dhcpREQUEST_OPCODE                                              ( 1 )
93 #define dhcpREPLY_OPCODE                                                ( 2 )
94 #define dhcpADDRESS_TYPE_ETHERNET                               ( 1 )
95 #define dhcpETHERNET_ADDRESS_LENGTH                             ( 6 )
96
97 /* If a lease time is not received, use the default of two days. */
98 /* 48 hours in ticks.  Can not use pdMS_TO_TICKS() as integer overflow can occur. */
99 #define dhcpDEFAULT_LEASE_TIME                                  ( ( 48UL * 60UL * 60UL ) * configTICK_RATE_HZ )
100
101 /* Don't allow the lease time to be too short. */
102 #define dhcpMINIMUM_LEASE_TIME                                  ( pdMS_TO_TICKS( 60000UL ) )    /* 60 seconds in ticks. */
103
104 /* Marks the end of the variable length options field in the DHCP packet. */
105 #define dhcpOPTION_END_BYTE 0xffu
106
107 /* Offset into a DHCP message at which the first byte of the options is
108 located. */
109 #define dhcpFIRST_OPTION_BYTE_OFFSET                    ( 0xf0 )
110
111 /* Standard DHCP port numbers and magic cookie value. */
112 #if( ipconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN )
113         #define dhcpCLIENT_PORT 0x4400u
114         #define dhcpSERVER_PORT 0x4300u
115         #define dhcpCOOKIE              0x63538263ul
116         #define dhcpBROADCAST   0x0080u
117 #else
118         #define dhcpCLIENT_PORT 0x0044u
119         #define dhcpSERVER_PORT 0x0043u
120         #define dhcpCOOKIE              0x63825363ul
121         #define dhcpBROADCAST   0x8000u
122 #endif /* ipconfigBYTE_ORDER */
123
124 #include "pack_struct_start.h"
125 struct xDHCPMessage
126 {
127         uint8_t ucOpcode;
128         uint8_t ucAddressType;
129         uint8_t ucAddressLength;
130         uint8_t ucHops;
131         uint32_t ulTransactionID;
132         uint16_t usElapsedTime;
133         uint16_t usFlags;
134         uint32_t ulClientIPAddress_ciaddr;
135         uint32_t ulYourIPAddress_yiaddr;
136         uint32_t ulServerIPAddress_siaddr;
137         uint32_t ulRelayAgentIPAddress_giaddr;
138         uint8_t ucClientHardwareAddress[ dhcpCLIENT_HARDWARE_ADDRESS_LENGTH ];
139         uint8_t ucServerHostName[ dhcpSERVER_HOST_NAME_LENGTH ];
140         uint8_t ucBootFileName[ dhcpBOOT_FILE_NAME_LENGTH ];
141         uint32_t ulDHCPCookie;
142         uint8_t ucFirstOptionByte;
143 }
144 #include "pack_struct_end.h"
145 typedef struct xDHCPMessage DHCPMessage_t;
146
147 /* DHCP state machine states. */
148 typedef enum
149 {
150         eWaitingSendFirstDiscover = 0,  /* Initial state.  Send a discover the first time it is called, and reset all timers. */
151         eWaitingOffer,                                  /* Either resend the discover, or, if the offer is forthcoming, send a request. */
152         eWaitingAcknowledge,                    /* Either resend the request. */
153         #if( ipconfigDHCP_FALL_BACK_AUTO_IP != 0 )
154                 eGetLinkLayerAddress,           /* When DHCP didn't respond, try to obtain a LinkLayer address 168.254.x.x. */
155         #endif
156         eLeasedAddress,                                 /* Resend the request at the appropriate time to renew the lease. */
157         eNotUsingLeasedAddress                  /* DHCP failed, and a default IP address is being used. */
158 } eDHCPState_t;
159
160 /* Hold information in between steps in the DHCP state machine. */
161 struct xDHCP_DATA
162 {
163         uint32_t ulTransactionId;
164         uint32_t ulOfferedIPAddress;
165         uint32_t ulDHCPServerAddress;
166         uint32_t ulLeaseTime;
167         /* Hold information on the current timer state. */
168         TickType_t xDHCPTxTime;
169         TickType_t xDHCPTxPeriod;
170         /* Try both without and with the broadcast flag */
171         BaseType_t xUseBroadcast;
172         /* Maintains the DHCP state machine state. */
173         eDHCPState_t eDHCPState;
174         /* The UDP socket used for all incoming and outgoing DHCP traffic. */
175         Socket_t xDHCPSocket;
176 };
177
178 typedef struct xDHCP_DATA DHCPData_t;
179
180 #if( ipconfigDHCP_FALL_BACK_AUTO_IP != 0 )
181         /* Define the Link Layer IP address: 169.254.x.x */
182         #define LINK_LAYER_ADDRESS_0    169
183         #define LINK_LAYER_ADDRESS_1    254
184
185         /* Define the netmask used: 255.255.0.0 */
186         #define LINK_LAYER_NETMASK_0    255
187         #define LINK_LAYER_NETMASK_1    255
188         #define LINK_LAYER_NETMASK_2    0
189         #define LINK_LAYER_NETMASK_3    0
190 #endif
191
192
193 /*
194  * Generate a DHCP discover message and send it on the DHCP socket.
195  */
196 static void prvSendDHCPDiscover( void );
197
198 /*
199  * Interpret message received on the DHCP socket.
200  */
201 static BaseType_t prvProcessDHCPReplies( BaseType_t xExpectedMessageType );
202
203 /*
204  * Generate a DHCP request packet, and send it on the DHCP socket.
205  */
206 static void prvSendDHCPRequest( void );
207
208 /*
209  * Prepare to start a DHCP transaction.  This initialises some state variables
210  * and creates the DHCP socket if necessary.
211  */
212 static void prvInitialiseDHCP( void );
213
214 /*
215  * Creates the part of outgoing DHCP messages that are common to all outgoing
216  * DHCP messages.
217  */
218 static uint8_t *prvCreatePartDHCPMessage( struct freertos_sockaddr *pxAddress, BaseType_t xOpcode, const uint8_t * const pucOptionsArray, size_t *pxOptionsArraySize );
219
220 /*
221  * Create the DHCP socket, if it has not been created already.
222  */
223 static void prvCreateDHCPSocket( void );
224
225 /*
226  * After DHCP has failed to answer, prepare everything to start searching
227  * for (trying-out) LinkLayer IP-addresses, using the random method: Send
228  * a gratuitous ARP request and wait if another device responds to it.
229  */
230 #if( ipconfigDHCP_FALL_BACK_AUTO_IP != 0 )
231         static void prvPrepareLinkLayerIPLookUp( void );
232 #endif
233
234 /*-----------------------------------------------------------*/
235
236 /* The next DHCP transaction Id to be used. */
237 static DHCPData_t xDHCPData;
238
239 /*-----------------------------------------------------------*/
240
241 BaseType_t xIsDHCPSocket( Socket_t xSocket )
242 {
243 BaseType_t xReturn;
244
245         if( xDHCPData.xDHCPSocket == xSocket )
246         {
247                 xReturn = pdTRUE;
248         }
249         else
250         {
251                 xReturn = pdFALSE;
252         }
253
254         return xReturn;
255 }
256 /*-----------------------------------------------------------*/
257
258 void vDHCPProcess( BaseType_t xReset )
259 {
260 BaseType_t xGivingUp = pdFALSE;
261 #if( ipconfigUSE_DHCP_HOOK != 0 )
262         eDHCPCallbackAnswer_t eAnswer;
263 #endif  /* ipconfigUSE_DHCP_HOOK */
264
265         /* Is DHCP starting over? */
266         if( xReset != pdFALSE )
267         {
268                 xDHCPData.eDHCPState = eWaitingSendFirstDiscover;
269         }
270
271         switch( xDHCPData.eDHCPState )
272         {
273                 case eWaitingSendFirstDiscover :
274                         /* Ask the user if a DHCP discovery is required. */
275                 #if( ipconfigUSE_DHCP_HOOK != 0 )
276                         eAnswer = xApplicationDHCPHook( eDHCPPhasePreDiscover, xNetworkAddressing.ulDefaultIPAddress );
277                         if( eAnswer == eDHCPContinue )
278                 #endif  /* ipconfigUSE_DHCP_HOOK */
279                         {
280                                 /* Initial state.  Create the DHCP socket, timer, etc. if they
281                                 have not already been created. */
282                                 prvInitialiseDHCP();
283
284                                 /* See if prvInitialiseDHCP() has creates a socket. */
285                                 if( xDHCPData.xDHCPSocket == NULL )
286                                 {
287                                         xGivingUp = pdTRUE;
288                                         break;
289                                 }
290
291                                 *ipLOCAL_IP_ADDRESS_POINTER = 0UL;
292
293                                 /* Send the first discover request. */
294                                 if( xDHCPData.xDHCPSocket != NULL )
295                                 {
296                                         xDHCPData.xDHCPTxTime = xTaskGetTickCount();
297                                         prvSendDHCPDiscover( );
298                                         xDHCPData.eDHCPState = eWaitingOffer;
299                                 }
300                         }
301                 #if( ipconfigUSE_DHCP_HOOK != 0 )
302                         else
303                         {
304                                 if( eAnswer == eDHCPUseDefaults )
305                                 {
306                                         memcpy( &xNetworkAddressing, &xDefaultAddressing, sizeof( xNetworkAddressing ) );
307                                 }
308
309                                 /* The user indicates that the DHCP process does not continue. */
310                                 xGivingUp = pdTRUE;
311                         }
312                 #endif  /* ipconfigUSE_DHCP_HOOK */
313                         break;
314
315                 case eWaitingOffer :
316
317                         xGivingUp = pdFALSE;
318
319                         /* Look for offers coming in. */
320                         if( prvProcessDHCPReplies( dhcpMESSAGE_TYPE_OFFER ) == pdPASS )
321                         {
322                         #if( ipconfigUSE_DHCP_HOOK != 0 )
323                                 /* Ask the user if a DHCP request is required. */
324                                 eAnswer = xApplicationDHCPHook( eDHCPPhasePreRequest, xDHCPData.ulOfferedIPAddress );
325
326                                 if( eAnswer == eDHCPContinue )
327                         #endif  /* ipconfigUSE_DHCP_HOOK */
328                                 {
329                                         /* An offer has been made, the user wants to continue,
330                                         generate the request. */
331                                         xDHCPData.xDHCPTxTime = xTaskGetTickCount();
332                                         xDHCPData.xDHCPTxPeriod = dhcpINITIAL_DHCP_TX_PERIOD;
333                                         prvSendDHCPRequest( );
334                                         xDHCPData.eDHCPState = eWaitingAcknowledge;
335                                         break;
336                                 }
337
338                         #if( ipconfigUSE_DHCP_HOOK != 0 )
339                                 if( eAnswer == eDHCPUseDefaults )
340                                 {
341                                         memcpy( &xNetworkAddressing, &xDefaultAddressing, sizeof( xNetworkAddressing ) );
342                                 }
343
344                                 /* The user indicates that the DHCP process does not continue. */
345                                 xGivingUp = pdTRUE;
346                         #endif  /* ipconfigUSE_DHCP_HOOK */
347                         }
348                         else if( ( xTaskGetTickCount() - xDHCPData.xDHCPTxTime ) > xDHCPData.xDHCPTxPeriod )
349                         {
350                                 /* It is time to send another Discover.  Increase the time
351                                 period, and if it has not got to the point of giving up - send
352                                 another discovery. */
353                                 xDHCPData.xDHCPTxPeriod <<= 1;
354
355                                 if( xDHCPData.xDHCPTxPeriod <= ipconfigMAXIMUM_DISCOVER_TX_PERIOD )
356                                 {
357                                         if( xApplicationGetRandomNumber( &( xDHCPData.ulTransactionId ) ) != pdFALSE )
358                                         {
359                                                 xDHCPData.xDHCPTxTime = xTaskGetTickCount( );
360                                                 xDHCPData.xUseBroadcast = !xDHCPData.xUseBroadcast;
361                                                 prvSendDHCPDiscover( );
362                                                 FreeRTOS_debug_printf( ( "vDHCPProcess: timeout %lu ticks\n", xDHCPData.xDHCPTxPeriod ) );
363                                         }
364                                         else
365                                         {
366                                                 FreeRTOS_debug_printf( ( "vDHCPProcess: failed to generate a random Transaction ID\n" ) );
367                                         }
368                                 }
369                                 else
370                                 {
371                                         FreeRTOS_debug_printf( ( "vDHCPProcess: giving up %lu > %lu ticks\n", xDHCPData.xDHCPTxPeriod, ipconfigMAXIMUM_DISCOVER_TX_PERIOD ) );
372
373                                         #if( ipconfigDHCP_FALL_BACK_AUTO_IP != 0 )
374                                         {
375                                                 /* Only use a fake Ack if the default IP address == 0x00
376                                                 and the link local addressing is used.  Start searching
377                                                 a free LinkLayer IP-address.  Next state will be
378                                                 'eGetLinkLayerAddress'. */
379                                                 prvPrepareLinkLayerIPLookUp();
380
381                                                 /* Setting an IP address manually so set to not using
382                                                 leased address mode. */
383                                                 xDHCPData.eDHCPState = eGetLinkLayerAddress;
384                                         }
385                                         #else
386                                         {
387                                                 xGivingUp = pdTRUE;
388                                         }
389                                         #endif /* ipconfigDHCP_FALL_BACK_AUTO_IP */
390                                 }
391                         }
392                         break;
393
394                 case eWaitingAcknowledge :
395
396                         /* Look for acks coming in. */
397                         if( prvProcessDHCPReplies( dhcpMESSAGE_TYPE_ACK ) == pdPASS )
398                         {
399                                 FreeRTOS_debug_printf( ( "vDHCPProcess: acked %lxip\n", FreeRTOS_ntohl( xDHCPData.ulOfferedIPAddress ) ) );
400
401                                 /* DHCP completed.  The IP address can now be used, and the
402                                 timer set to the lease timeout time. */
403                                 *ipLOCAL_IP_ADDRESS_POINTER = xDHCPData.ulOfferedIPAddress;
404
405                                 /* Setting the 'local' broadcast address, something like
406                                 '192.168.1.255'. */
407                                 xNetworkAddressing.ulBroadcastAddress = ( xDHCPData.ulOfferedIPAddress & xNetworkAddressing.ulNetMask ) |  ~xNetworkAddressing.ulNetMask;
408                                 xDHCPData.eDHCPState = eLeasedAddress;
409
410                                 iptraceDHCP_SUCCEDEED( xDHCPData.ulOfferedIPAddress );
411
412                                 /* DHCP failed, the default configured IP-address will be used
413                                 Now call vIPNetworkUpCalls() to send the network-up event and
414                                 start the ARP timer. */
415                                 vIPNetworkUpCalls( );
416
417                                 /* Close socket to ensure packets don't queue on it. */
418                                 vSocketClose( xDHCPData.xDHCPSocket );
419                                 xDHCPData.xDHCPSocket = NULL;
420
421                                 if( xDHCPData.ulLeaseTime == 0UL )
422                                 {
423                                         xDHCPData.ulLeaseTime = dhcpDEFAULT_LEASE_TIME;
424                                 }
425                                 else if( xDHCPData.ulLeaseTime < dhcpMINIMUM_LEASE_TIME )
426                                 {
427                                         xDHCPData.ulLeaseTime = dhcpMINIMUM_LEASE_TIME;
428                                 }
429                                 else
430                                 {
431                                         /* The lease time is already valid. */
432                                 }
433
434                                 /* Check for clashes. */
435                                 vARPSendGratuitous();
436                                 vIPReloadDHCPTimer( xDHCPData.ulLeaseTime );
437                         }
438                         else
439                         {
440                                 /* Is it time to send another Discover? */
441                                 if( ( xTaskGetTickCount() - xDHCPData.xDHCPTxTime ) > xDHCPData.xDHCPTxPeriod )
442                                 {
443                                         /* Increase the time period, and if it has not got to the
444                                         point of giving up - send another request. */
445                                         xDHCPData.xDHCPTxPeriod <<= 1;
446
447                                         if( xDHCPData.xDHCPTxPeriod <= ipconfigMAXIMUM_DISCOVER_TX_PERIOD )
448                                         {
449                                                 xDHCPData.xDHCPTxTime = xTaskGetTickCount();
450                                                 prvSendDHCPRequest( );
451                                         }
452                                         else
453                                         {
454                                                 /* Give up, start again. */
455                                                 xDHCPData.eDHCPState = eWaitingSendFirstDiscover;
456                                         }
457                                 }
458                         }
459                         break;
460
461         #if( ipconfigDHCP_FALL_BACK_AUTO_IP != 0 )
462                 case eGetLinkLayerAddress:
463                         if( ( xTaskGetTickCount() - xDHCPData.xDHCPTxTime ) > xDHCPData.xDHCPTxPeriod )
464                         {
465                                 if( xARPHadIPClash == pdFALSE )
466                                 {
467                                         /* ARP OK. proceed. */
468                                         iptraceDHCP_SUCCEDEED( xDHCPData.ulOfferedIPAddress );
469
470                                         /* Auto-IP succeeded, the default configured IP-address will
471                                         be used.  Now call vIPNetworkUpCalls() to send the
472                                         network-up event and start the ARP timer. */
473                                         vIPNetworkUpCalls( );
474                                         xDHCPData.eDHCPState = eNotUsingLeasedAddress;
475                                 }
476                                 else
477                                 {
478                                         /* ARP clashed - try another IP address. */
479                                         prvPrepareLinkLayerIPLookUp();
480
481                                         /* Setting an IP address manually so set to not using leased
482                                         address mode. */
483                                         xDHCPData.eDHCPState = eGetLinkLayerAddress;
484                                 }
485                         }
486                         break;
487         #endif  /* ipconfigDHCP_FALL_BACK_AUTO_IP */
488
489                 case eLeasedAddress :
490
491                         /* Resend the request at the appropriate time to renew the lease. */
492                         prvCreateDHCPSocket();
493
494                         if( xDHCPData.xDHCPSocket != NULL )
495                         {
496                                 xDHCPData.xDHCPTxTime = xTaskGetTickCount();
497                                 xDHCPData.xDHCPTxPeriod = dhcpINITIAL_DHCP_TX_PERIOD;
498                                 prvSendDHCPRequest( );
499                                 xDHCPData.eDHCPState = eWaitingAcknowledge;
500
501                                 /* From now on, we should be called more often */
502                                 vIPReloadDHCPTimer( dhcpINITIAL_TIMER_PERIOD );
503                         }
504                         break;
505
506                 case eNotUsingLeasedAddress:
507
508                         vIPSetDHCPTimerEnableState( pdFALSE );
509                         break;
510
511                 default:
512                         break;
513         }
514
515         if( xGivingUp != pdFALSE )
516         {
517                 /* xGivingUp became true either because of a time-out, or because
518                 xApplicationDHCPHook() returned another value than 'eDHCPContinue',
519                 meaning that the conversion is canceled from here. */
520
521                 /* Revert to static IP address. */
522                 taskENTER_CRITICAL();
523                 {
524                         *ipLOCAL_IP_ADDRESS_POINTER = xNetworkAddressing.ulDefaultIPAddress;
525                         iptraceDHCP_REQUESTS_FAILED_USING_DEFAULT_IP_ADDRESS( xNetworkAddressing.ulDefaultIPAddress );
526                 }
527                 taskEXIT_CRITICAL();
528
529                 xDHCPData.eDHCPState = eNotUsingLeasedAddress;
530                 vIPSetDHCPTimerEnableState( pdFALSE );
531
532                 /* DHCP failed, the default configured IP-address will be used.  Now
533                 call vIPNetworkUpCalls() to send the network-up event and start the ARP
534                 timer. */
535                 vIPNetworkUpCalls( );
536
537                 /* Test if socket was indeed created. */
538                 if( xDHCPData.xDHCPSocket != NULL )
539                 {
540                         /* Close socket to ensure packets don't queue on it. */
541                         vSocketClose( xDHCPData.xDHCPSocket );
542                         xDHCPData.xDHCPSocket = NULL;
543                 }
544         }
545 }
546 /*-----------------------------------------------------------*/
547
548 static void prvCreateDHCPSocket( void )
549 {
550 struct freertos_sockaddr xAddress;
551 BaseType_t xReturn;
552 TickType_t xTimeoutTime = ( TickType_t ) 0;
553
554         /* Create the socket, if it has not already been created. */
555         if( xDHCPData.xDHCPSocket == NULL )
556         {
557                 xDHCPData.xDHCPSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP );
558                 if( xDHCPData.xDHCPSocket != FREERTOS_INVALID_SOCKET )
559                 {
560
561                         /* Ensure the Rx and Tx timeouts are zero as the DHCP executes in the
562                         context of the IP task. */
563                         FreeRTOS_setsockopt( xDHCPData.xDHCPSocket, 0, FREERTOS_SO_RCVTIMEO, ( void * ) &xTimeoutTime, sizeof( TickType_t ) );
564                         FreeRTOS_setsockopt( xDHCPData.xDHCPSocket, 0, FREERTOS_SO_SNDTIMEO, ( void * ) &xTimeoutTime, sizeof( TickType_t ) );
565
566                         /* Bind to the standard DHCP client port. */
567                         xAddress.sin_port = ( uint16_t ) dhcpCLIENT_PORT;
568                         xReturn = vSocketBind( xDHCPData.xDHCPSocket, &xAddress, sizeof( xAddress ), pdFALSE );
569                         if( xReturn != 0 )
570                         {
571                                 /* Binding failed, close the socket again. */
572                                 vSocketClose( xDHCPData.xDHCPSocket );
573                                 xDHCPData.xDHCPSocket = NULL;
574                         }
575                 }
576                 else
577                 {
578                         /* Change to NULL for easier testing. */
579                         xDHCPData.xDHCPSocket = NULL;
580                 }
581         }
582 }
583 /*-----------------------------------------------------------*/
584
585 static void prvInitialiseDHCP( void )
586 {
587         /* Initialise the parameters that will be set by the DHCP process. Per
588         https://www.ietf.org/rfc/rfc2131.txt, Transaction ID should be a random
589         value chosen by the client. */
590
591         /* Check for random number generator API failure. */
592         if( xApplicationGetRandomNumber( &( xDHCPData.ulTransactionId ) ) != pdFALSE )
593         {
594                 xDHCPData.xUseBroadcast = 0;
595                 xDHCPData.ulOfferedIPAddress = 0UL;
596                 xDHCPData.ulDHCPServerAddress = 0UL;
597                 xDHCPData.xDHCPTxPeriod = dhcpINITIAL_DHCP_TX_PERIOD;
598
599                 /* Create the DHCP socket if it has not already been created. */
600                 prvCreateDHCPSocket();
601                 FreeRTOS_debug_printf( ( "prvInitialiseDHCP: start after %lu ticks\n", dhcpINITIAL_TIMER_PERIOD ) );
602                 vIPReloadDHCPTimer( dhcpINITIAL_TIMER_PERIOD );
603         }
604         else
605         {
606                 /* There was a problem with the randomiser. */
607         }
608 }
609 /*-----------------------------------------------------------*/
610
611 static BaseType_t prvProcessDHCPReplies( BaseType_t xExpectedMessageType )
612 {
613 uint8_t *pucUDPPayload, *pucLastByte;
614 struct freertos_sockaddr xClient;
615 uint32_t xClientLength = sizeof( xClient );
616 int32_t lBytes;
617 DHCPMessage_t *pxDHCPMessage;
618 uint8_t *pucByte, ucOptionCode, ucLength;
619 uint32_t ulProcessed, ulParameter;
620 BaseType_t xReturn = pdFALSE;
621 const uint32_t ulMandatoryOptions = 2ul; /* DHCP server address, and the correct DHCP message type must be present in the options. */
622
623         lBytes = FreeRTOS_recvfrom( xDHCPData.xDHCPSocket, ( void * ) &pucUDPPayload, 0ul, FREERTOS_ZERO_COPY, &xClient, &xClientLength );
624
625         if( lBytes > 0 )
626         {
627                 /* Map a DHCP structure onto the received data. */
628                 pxDHCPMessage = ( DHCPMessage_t * ) ( pucUDPPayload );
629
630                 /* Sanity check. */
631                 if( ( lBytes >= sizeof( DHCPMessage_t ) ) &&
632                         ( pxDHCPMessage->ulDHCPCookie == ( uint32_t ) dhcpCOOKIE ) &&
633                         ( pxDHCPMessage->ucOpcode == ( uint8_t ) dhcpREPLY_OPCODE ) &&
634                         ( pxDHCPMessage->ulTransactionID == FreeRTOS_htonl( xDHCPData.ulTransactionId ) ) )
635                 {
636                         if( memcmp( ( void * ) &( pxDHCPMessage->ucClientHardwareAddress ),
637                                                 ( void * ) ipLOCAL_MAC_ADDRESS,
638                                                 sizeof( MACAddress_t ) ) == 0 )
639                         {
640                                 /* None of the essential options have been processed yet. */
641                                 ulProcessed = 0ul;
642
643                                 /* Walk through the options until the dhcpOPTION_END_BYTE byte
644                                 is found, taking care not to walk off the end of the options. */
645                                 pucByte = &( pxDHCPMessage->ucFirstOptionByte );
646                 /* Maintain a pointer to the last valid byte (i.e. not the first
647                 invalid byte). */
648                                 pucLastByte = pucUDPPayload + lBytes - 1;
649
650                                 while( pucByte <= pucLastByte )
651                                 {
652                                         ucOptionCode = pucByte[ 0 ];
653                                         if( ucOptionCode == dhcpOPTION_END_BYTE )
654                                         {
655                                                 /* Ready, the last byte has been seen. */
656                                                 break;
657                                         }
658                                         if( ucOptionCode == dhcpZERO_PAD_OPTION_CODE )
659                                         {
660                                                 /* The value zero is used as a pad byte,
661                                                 it is not followed by a length byte. */
662                                                 pucByte += 1;
663                                                 continue;
664                                         }
665
666                                         /* Stop if the response is malformed. */
667                                         if( pucByte < pucLastByte )
668                                         {
669                         /* There are at least two bytes left. */
670                                                 ucLength = pucByte[ 1 ];
671                                                 pucByte += 2;
672
673                                                 if( pucByte + ucLength > pucLastByte )
674                                                 {
675                                                         break;
676                                                 }
677                                         }
678                                         else
679                                         {
680                                                 break;
681                                         }
682
683                                         /* In most cases, a 4-byte network-endian parameter follows,
684                                         just get it once here and use later. */
685                                         if( ucLength >= sizeof( ulParameter ) )
686                                         {
687                                                 memcpy( ( void * ) &( ulParameter ),
688                                                                 ( void * ) pucByte,
689                                                                 ( size_t ) sizeof( ulParameter ) );
690                                         }
691                                         else
692                                         {
693                                                 ulParameter = 0;
694                                         }
695
696                                         /* Option-specific handling. */
697                                         switch( ucOptionCode )
698                                         {
699                                                 case dhcpMESSAGE_TYPE_OPTION_CODE       :
700
701                                                         if( *pucByte == ( uint8_t ) xExpectedMessageType )
702                                                         {
703                                                                 /* The message type is the message type the
704                                                                 state machine is expecting. */
705                                                                 ulProcessed++;
706                                                         }
707                                                         else if( *pucByte == ( uint8_t ) dhcpMESSAGE_TYPE_NACK )
708                                                         {
709                                                                 if( xExpectedMessageType == ( BaseType_t ) dhcpMESSAGE_TYPE_ACK )
710                                                                 {
711                                                                         /* Start again. */
712                                                                         xDHCPData.eDHCPState = eWaitingSendFirstDiscover;
713                                                                 }
714                                                         }
715                                                         else
716                                                         {
717                                                                 /* Don't process other message types. */
718                                                         }
719                                                         break;
720
721                                                 case dhcpSUBNET_MASK_OPTION_CODE :
722
723                                                         if( ucLength == sizeof( uint32_t ) )
724                                                         {
725                                                                 xNetworkAddressing.ulNetMask = ulParameter;
726                                                         }
727                                                         break;
728
729                                                 case dhcpGATEWAY_OPTION_CODE :
730
731                                                         if( ucLength == sizeof( uint32_t ) )
732                                                         {
733                                                                 /* ulProcessed is not incremented in this case
734                                                                 because the gateway is not essential. */
735                                                                 xNetworkAddressing.ulGatewayAddress = ulParameter;
736                                                         }
737                                                         break;
738
739                                                 case dhcpDNS_SERVER_OPTIONS_CODE :
740
741                                                         /* ulProcessed is not incremented in this case
742                                                         because the DNS server is not essential.  Only the
743                                                         first DNS server address is taken. */
744                                                         xNetworkAddressing.ulDNSServerAddress = ulParameter;
745                                                         break;
746
747                                                 case dhcpSERVER_IP_ADDRESS_OPTION_CODE :
748
749                                                         if( ucLength == sizeof( uint32_t ) )
750                                                         {
751                                                                 if( xExpectedMessageType == ( BaseType_t ) dhcpMESSAGE_TYPE_OFFER )
752                                                                 {
753                                                                         /* Offers state the replying server. */
754                                                                         ulProcessed++;
755                                                                         xDHCPData.ulDHCPServerAddress = ulParameter;
756                                                                 }
757                                                                 else
758                                                                 {
759                                                                         /* The ack must come from the expected server. */
760                                                                         if( xDHCPData.ulDHCPServerAddress == ulParameter )
761                                                                         {
762                                                                                 ulProcessed++;
763                                                                         }
764                                                                 }
765                                                         }
766                                                         break;
767
768                                                 case dhcpLEASE_TIME_OPTION_CODE :
769
770                                                         if( ucLength == sizeof( xDHCPData.ulLeaseTime ) )
771                                                         {
772                                                                 /* ulProcessed is not incremented in this case
773                                                                 because the lease time is not essential. */
774                                                                 /* The DHCP parameter is in seconds, convert
775                                                                 to host-endian format. */
776                                                                 xDHCPData.ulLeaseTime = FreeRTOS_ntohl( ulParameter );
777
778                                                                 /* Divide the lease time by two to ensure a
779                                                                 renew request is sent before the lease actually
780                                                                 expires. */
781                                                                 xDHCPData.ulLeaseTime >>= 1UL;
782
783                                                                 /* Multiply with configTICK_RATE_HZ to get clock
784                                                                 ticks. */
785                                                                 xDHCPData.ulLeaseTime = configTICK_RATE_HZ * xDHCPData.ulLeaseTime;
786                                                         }
787                                                         break;
788
789                                                 default :
790
791                                                         /* Not interested in this field. */
792
793                                                         break;
794                                         }
795
796                                         /* Jump over the data to find the next option code. */
797                                         if( ucLength == 0u )
798                                         {
799                                                 break;
800                                         }
801                                         else
802                                         {
803                                                 pucByte += ucLength;
804                                         }
805                                 }
806
807                                 /* Were all the mandatory options received? */
808                                 if( ulProcessed >= ulMandatoryOptions )
809                                 {
810                                         /* HT:endian: used to be network order */
811                                         xDHCPData.ulOfferedIPAddress = pxDHCPMessage->ulYourIPAddress_yiaddr;
812                                         FreeRTOS_printf( ( "vDHCPProcess: offer %lxip\n", FreeRTOS_ntohl( xDHCPData.ulOfferedIPAddress ) ) );
813                                         xReturn = pdPASS;
814                                 }
815                         }
816                 }
817
818                 FreeRTOS_ReleaseUDPPayloadBuffer( ( void * ) pucUDPPayload );
819         }
820
821         return xReturn;
822 }
823 /*-----------------------------------------------------------*/
824
825 static uint8_t *prvCreatePartDHCPMessage( struct freertos_sockaddr *pxAddress, BaseType_t xOpcode, const uint8_t * const pucOptionsArray, size_t *pxOptionsArraySize )
826 {
827 DHCPMessage_t *pxDHCPMessage;
828 size_t xRequiredBufferSize = sizeof( DHCPMessage_t ) + *pxOptionsArraySize;
829 uint8_t *pucUDPPayloadBuffer;
830
831 #if( ipconfigDHCP_REGISTER_HOSTNAME == 1 )
832         const char *pucHostName = pcApplicationHostnameHook ();
833         size_t xNameLength = strlen( pucHostName );
834         uint8_t *pucPtr;
835
836         xRequiredBufferSize += ( 2 + xNameLength );
837 #endif
838
839         /* Get a buffer.  This uses a maximum delay, but the delay will be capped
840         to ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS so the return value still needs to
841         be test. */
842         do
843         {
844         } while( ( pucUDPPayloadBuffer = ( uint8_t * ) FreeRTOS_GetUDPPayloadBuffer( xRequiredBufferSize, portMAX_DELAY ) ) == NULL );
845
846         pxDHCPMessage = ( DHCPMessage_t * ) pucUDPPayloadBuffer;
847
848         /* Most fields need to be zero. */
849         memset( ( void * ) pxDHCPMessage, 0x00, sizeof( DHCPMessage_t ) );
850
851         /* Create the message. */
852         pxDHCPMessage->ucOpcode = ( uint8_t ) xOpcode;
853         pxDHCPMessage->ucAddressType = ( uint8_t ) dhcpADDRESS_TYPE_ETHERNET;
854         pxDHCPMessage->ucAddressLength = ( uint8_t ) dhcpETHERNET_ADDRESS_LENGTH;
855         pxDHCPMessage->ulTransactionID = FreeRTOS_htonl( xDHCPData.ulTransactionId );
856         pxDHCPMessage->ulDHCPCookie = ( uint32_t ) dhcpCOOKIE;
857         if( xDHCPData.xUseBroadcast != pdFALSE )
858         {
859                 pxDHCPMessage->usFlags = ( uint16_t ) dhcpBROADCAST;
860         }
861         else
862         {
863                 pxDHCPMessage->usFlags = 0u;
864         }
865
866         memcpy( ( void * ) &( pxDHCPMessage->ucClientHardwareAddress[ 0 ] ), ( void * ) ipLOCAL_MAC_ADDRESS, sizeof( MACAddress_t ) );
867
868         /* Copy in the const part of the options options. */
869         memcpy( ( void * ) &( pucUDPPayloadBuffer[ dhcpFIRST_OPTION_BYTE_OFFSET ] ), ( void * ) pucOptionsArray, *pxOptionsArraySize );
870
871         #if( ipconfigDHCP_REGISTER_HOSTNAME == 1 )
872         {
873                 /* With this option, the hostname can be registered as well which makes
874                 it easier to lookup a device in a router's list of DHCP clients. */
875
876                 /* Point to where the OPTION_END was stored to add data. */
877                 pucPtr = &( pucUDPPayloadBuffer[ dhcpFIRST_OPTION_BYTE_OFFSET + ( *pxOptionsArraySize - 1 ) ] );
878                 pucPtr[ 0 ] = dhcpDNS_HOSTNAME_OPTIONS_CODE;
879                 pucPtr[ 1 ] = ( uint8_t ) xNameLength;
880                 memcpy( ( void *) ( pucPtr + 2 ), pucHostName, xNameLength );
881                 pucPtr[ 2 + xNameLength ] = dhcpOPTION_END_BYTE;
882                 *pxOptionsArraySize += ( 2 + xNameLength );
883         }
884         #endif
885
886         /* Map in the client identifier. */
887         memcpy( ( void * ) &( pucUDPPayloadBuffer[ dhcpFIRST_OPTION_BYTE_OFFSET + dhcpCLIENT_IDENTIFIER_OFFSET ] ),
888                 ( void * ) ipLOCAL_MAC_ADDRESS, sizeof( MACAddress_t ) );
889
890         /* Set the addressing. */
891         pxAddress->sin_addr = ipBROADCAST_IP_ADDRESS;
892         pxAddress->sin_port = ( uint16_t ) dhcpSERVER_PORT;
893
894         return pucUDPPayloadBuffer;
895 }
896 /*-----------------------------------------------------------*/
897
898 static void prvSendDHCPRequest( void )
899 {
900 uint8_t *pucUDPPayloadBuffer;
901 struct freertos_sockaddr xAddress;
902 static const uint8_t ucDHCPRequestOptions[] =
903 {
904         /* Do not change the ordering without also changing
905         dhcpCLIENT_IDENTIFIER_OFFSET, dhcpREQUESTED_IP_ADDRESS_OFFSET and
906         dhcpDHCP_SERVER_IP_ADDRESS_OFFSET. */
907         dhcpMESSAGE_TYPE_OPTION_CODE, 1, dhcpMESSAGE_TYPE_REQUEST,              /* Message type option. */
908         dhcpCLIENT_IDENTIFIER_OPTION_CODE, 7, 1, 0, 0, 0, 0, 0, 0,                      /* Client identifier. */
909         dhcpREQUEST_IP_ADDRESS_OPTION_CODE, 4, 0, 0, 0, 0,                              /* The IP address being requested. */
910         dhcpSERVER_IP_ADDRESS_OPTION_CODE, 4, 0, 0, 0, 0,                               /* The IP address of the DHCP server. */
911         dhcpOPTION_END_BYTE
912 };
913 size_t xOptionsLength = sizeof( ucDHCPRequestOptions );
914
915         pucUDPPayloadBuffer = prvCreatePartDHCPMessage( &xAddress, dhcpREQUEST_OPCODE, ucDHCPRequestOptions, &xOptionsLength );
916
917         /* Copy in the IP address being requested. */
918         memcpy( ( void * ) &( pucUDPPayloadBuffer[ dhcpFIRST_OPTION_BYTE_OFFSET + dhcpREQUESTED_IP_ADDRESS_OFFSET ] ),
919                 ( void * ) &( xDHCPData.ulOfferedIPAddress ), sizeof( xDHCPData.ulOfferedIPAddress ) );
920
921         /* Copy in the address of the DHCP server being used. */
922         memcpy( ( void * ) &( pucUDPPayloadBuffer[ dhcpFIRST_OPTION_BYTE_OFFSET + dhcpDHCP_SERVER_IP_ADDRESS_OFFSET ] ),
923                 ( void * ) &( xDHCPData.ulDHCPServerAddress ), sizeof( xDHCPData.ulDHCPServerAddress ) );
924
925         FreeRTOS_debug_printf( ( "vDHCPProcess: reply %lxip\n", FreeRTOS_ntohl( xDHCPData.ulOfferedIPAddress ) ) );
926         iptraceSENDING_DHCP_REQUEST();
927
928         /* 'ucFirstOptionByte' is part of DHCP message struct, so subtract one byte. */
929         if( FreeRTOS_sendto( xDHCPData.xDHCPSocket, pucUDPPayloadBuffer, ( sizeof( DHCPMessage_t ) + xOptionsLength - 1 ), FREERTOS_ZERO_COPY, &xAddress, sizeof( xAddress ) ) == 0 )
930         {
931                 /* The packet was not successfully queued for sending and must be
932                 returned to the stack. */
933                 FreeRTOS_ReleaseUDPPayloadBuffer( pucUDPPayloadBuffer );
934         }
935 }
936 /*-----------------------------------------------------------*/
937
938 static void prvSendDHCPDiscover( void )
939 {
940 uint8_t *pucUDPPayloadBuffer;
941 struct freertos_sockaddr xAddress;
942 static const uint8_t ucDHCPDiscoverOptions[] =
943 {
944         /* Do not change the ordering without also changing dhcpCLIENT_IDENTIFIER_OFFSET. */
945         dhcpMESSAGE_TYPE_OPTION_CODE, 1, dhcpMESSAGE_TYPE_DISCOVER,                                     /* Message type option. */
946         dhcpCLIENT_IDENTIFIER_OPTION_CODE, 7, 1, 0, 0, 0, 0, 0, 0,                                              /* Client identifier. */
947         dhcpPARAMETER_REQUEST_OPTION_CODE, 3, dhcpSUBNET_MASK_OPTION_CODE, dhcpGATEWAY_OPTION_CODE, dhcpDNS_SERVER_OPTIONS_CODE,        /* Parameter request option. */
948         dhcpOPTION_END_BYTE
949 };
950 size_t xOptionsLength = sizeof( ucDHCPDiscoverOptions );
951
952         pucUDPPayloadBuffer = prvCreatePartDHCPMessage( &xAddress, dhcpREQUEST_OPCODE, ucDHCPDiscoverOptions, &xOptionsLength );
953
954         FreeRTOS_debug_printf( ( "vDHCPProcess: discover\n" ) );
955         iptraceSENDING_DHCP_DISCOVER();
956
957         /* 'ucFirstOptionByte' is part of DHCP message struct, so subtract one byte. */
958         if( FreeRTOS_sendto( xDHCPData.xDHCPSocket, pucUDPPayloadBuffer, ( sizeof( DHCPMessage_t ) + xOptionsLength - 1 ), FREERTOS_ZERO_COPY, &xAddress, sizeof( xAddress ) ) == 0 )
959         {
960                 /* The packet was not successfully queued for sending and must be
961                 returned to the stack. */
962                 FreeRTOS_ReleaseUDPPayloadBuffer( pucUDPPayloadBuffer );
963         }
964 }
965 /*-----------------------------------------------------------*/
966
967 #if( ipconfigDHCP_FALL_BACK_AUTO_IP != 0 )
968
969         static void prvPrepareLinkLayerIPLookUp( void )
970         {
971         uint8_t ucLinkLayerIPAddress[ 2 ];
972         uint32_t ulNumbers[ 2 ];
973
974                 /* After DHCP has failed to answer, prepare everything to start
975                 trying-out LinkLayer IP-addresses, using the random method. */
976                 xDHCPData.xDHCPTxTime = xTaskGetTickCount();
977
978                 xApplicationGetRandomNumber( &( ulNumbers[ 0 ] ) );
979                 xApplicationGetRandomNumber( &( ulNumbers[ 1 ] ) );
980                 ucLinkLayerIPAddress[ 0 ] = ( uint8_t )1 + ( uint8_t )( ulNumbers[ 0 ] % 0xFDu );               /* get value 1..254 for IP-address 3rd byte of IP address to try. */
981                 ucLinkLayerIPAddress[ 1 ] = ( uint8_t )1 + ( uint8_t )( ulNumbers[ 1 ] % 0xFDu );               /* get value 1..254 for IP-address 4th byte of IP address to try. */
982
983                 xNetworkAddressing.ulGatewayAddress = FreeRTOS_htonl( 0xA9FE0203 );
984
985                 /* prepare xDHCPData with data to test. */
986                 xDHCPData.ulOfferedIPAddress =
987                         FreeRTOS_inet_addr_quick( LINK_LAYER_ADDRESS_0, LINK_LAYER_ADDRESS_1, ucLinkLayerIPAddress[ 0 ], ucLinkLayerIPAddress[ 1 ] );
988
989                 xDHCPData.ulLeaseTime = dhcpDEFAULT_LEASE_TIME;  /*  don't care about lease time. just put anything. */
990
991                 xNetworkAddressing.ulNetMask =
992                         FreeRTOS_inet_addr_quick( LINK_LAYER_NETMASK_0, LINK_LAYER_NETMASK_1, LINK_LAYER_NETMASK_2, LINK_LAYER_NETMASK_3 );
993
994                 /* DHCP completed.  The IP address can now be used, and the
995                 timer set to the lease timeout time. */
996                 *ipLOCAL_IP_ADDRESS_POINTER = xDHCPData.ulOfferedIPAddress;
997
998                 /* Setting the 'local' broadcast address, something like 192.168.1.255' */
999                 xNetworkAddressing.ulBroadcastAddress = ( xDHCPData.ulOfferedIPAddress & xNetworkAddressing.ulNetMask ) |  ~xNetworkAddressing.ulNetMask;
1000
1001                 /* Close socket to ensure packets don't queue on it. not needed anymore as DHCP failed. but still need timer for ARP testing. */
1002                 if( xDHCPData.xDHCPSocket != NULL )
1003                 {
1004                         /* Close socket to ensure packets don't queue on it. */
1005                         vSocketClose( xDHCPData.xDHCPSocket );
1006                     xDHCPData.xDHCPSocket = NULL;
1007                 }
1008
1009                 xApplicationGetRandomNumber( &( ulNumbers[ 0 ] ) );
1010                 xDHCPData.xDHCPTxPeriod = pdMS_TO_TICKS( 3000ul + ( ulNumbers[ 0 ] & 0x3ffuL ) ); /*  do ARP test every (3 + 0-1024mS) seconds. */
1011
1012                 xARPHadIPClash = pdFALSE;          /* reset flag that shows if have ARP clash. */
1013                 vARPSendGratuitous();
1014         }
1015
1016 #endif /* ipconfigDHCP_FALL_BACK_AUTO_IP */
1017 /*-----------------------------------------------------------*/
1018
1019 #endif /* ipconfigUSE_DHCP != 0 */
1020
1021