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