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