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