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