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