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