2 * FreeRTOS+UDP V1.0.4 (C) 2014 Real Time Engineers ltd.
\r
3 * All rights reserved
\r
5 * This file is part of the FreeRTOS+UDP distribution. The FreeRTOS+UDP license
\r
6 * terms are different to the FreeRTOS license terms.
\r
8 * FreeRTOS+UDP uses a dual license model that allows the software to be used
\r
9 * under a standard GPL open source license, or a commercial license. The
\r
10 * standard GPL license (unlike the modified GPL license under which FreeRTOS
\r
11 * itself is distributed) requires that all software statically linked with
\r
12 * FreeRTOS+UDP is also distributed under the same GPL V2 license terms.
\r
13 * Details of both license options follow:
\r
15 * - Open source licensing -
\r
16 * FreeRTOS+UDP is a free download and may be used, modified, evaluated and
\r
17 * distributed without charge provided the user adheres to version two of the
\r
18 * GNU General Public License (GPL) and does not remove the copyright notice or
\r
19 * this text. The GPL V2 text is available on the gnu.org web site, and on the
\r
20 * following URL: http://www.FreeRTOS.org/gpl-2.0.txt.
\r
22 * - Commercial licensing -
\r
23 * Businesses and individuals that for commercial or other reasons cannot comply
\r
24 * with the terms of the GPL V2 license must obtain a commercial license before
\r
25 * incorporating FreeRTOS+UDP into proprietary software for distribution in any
\r
26 * form. Commercial licenses can be purchased from http://shop.freertos.org/udp
\r
27 * and do not require any source files to be changed.
\r
29 * FreeRTOS+UDP is distributed in the hope that it will be useful. You cannot
\r
30 * use FreeRTOS+UDP unless you agree that you use the software 'as is'.
\r
31 * FreeRTOS+UDP is provided WITHOUT ANY WARRANTY; without even the implied
\r
32 * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
\r
33 * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they
\r
34 * implied, expressed, or statutory.
\r
36 * 1 tab == 4 spaces!
\r
38 * http://www.FreeRTOS.org
\r
39 * http://www.FreeRTOS.org/udp
\r
43 /* Standard includes. */
\r
46 /* FreeRTOS includes. */
\r
47 #include "FreeRTOS.h"
\r
52 /* FreeRTOS+UDP includes. */
\r
53 #include "FreeRTOS_UDP_IP.h"
\r
54 #include "FreeRTOS_IP_Private.h"
\r
55 #include "FreeRTOS_DHCP.h"
\r
56 #include "FreeRTOS_Sockets.h"
\r
57 #include "NetworkInterface.h"
\r
58 #include "IPTraceMacroDefaults.h"
\r
60 /* Exclude the entire file if DHCP is not enabled. */
\r
61 #if ipconfigUSE_DHCP != 0
\r
63 #if ( ipconfigUSE_DHCP != 0 ) && ( ipconfigNETWORK_MTU < 586 )
\r
64 /* DHCP must be able to receive an options field of 312 bytes, the fixed
\r
65 part of the DHCP packet is 240 bytes, and the IP/UDP headers take 28 bytes. */
\r
66 #error ipconfigNETWORK_MTU needs to be at least 586 to use DHCP (588 if ipconfigCAN_FRAGMENT_OUTGOING_PACKETS is set to 1)
\r
69 /* Parameter widths in the DHCP packet. */
\r
70 #define dhcpCLIENT_HARDWARE_ADDRESS_LENGTH 16
\r
71 #define dhcpSERVER_HOST_NAME_LENGTH 64
\r
72 #define dhcpBOOT_FILE_NAME_LENGTH 128
\r
74 /* Timer parameters. Windows simulator times are much shorter because simulated
\r
75 time is not real time. */
\r
77 #define dhcpINITIAL_DHCP_TX_PERIOD ( 100 / portTICK_RATE_MS )
\r
78 #define dhcpINITIAL_TIMER_PERIOD ( 10 / portTICK_RATE_MS )
\r
79 #define dhcpMAX_TIME_TO_WAIT_FOR_ACK ( 200 / portTICK_RATE_MS )
\r
81 #define dhcpINITIAL_DHCP_TX_PERIOD ( 5000 / portTICK_RATE_MS )
\r
82 #define dhcpINITIAL_TIMER_PERIOD ( 250 / portTICK_RATE_MS )
\r
83 #define dhcpMAX_TIME_TO_WAIT_FOR_ACK ( 5000 / portTICK_RATE_MS )
\r
84 #endif /* _WINDOWS_ */
\r
86 /* Codes of interest found in the DHCP options field. */
\r
87 #define dhcpSUBNET_MASK_OPTION_CODE ( 1 )
\r
88 #define dhcpGATEWAY_OPTION_CODE ( 3 )
\r
89 #define hdcpDNS_SERVER_OPTIONS_CODE ( 6 )
\r
90 #define dhcpMESSAGE_TYPE_OPTION_CODE ( 53 )
\r
91 #define dhcpLEASE_TIME_OPTION_CODE ( 51 )
\r
92 #define dhcpCLIENT_IDENTIFIER_OPTION_CODE ( 61 )
\r
93 #define dhcpPARAMETER_REQUEST_OPTION_CODE ( 55 )
\r
94 #define dhcpREQUEST_IP_ADDRESS_OPTION_CODE ( 50 )
\r
95 #define dhcpSERVER_IP_ADDRESS_OPTION_CODE ( 54 )
\r
97 /* The four DHCP message types of interest. */
\r
98 #define dhcpMESSAGE_TYPE_DISCOVER ( 1 )
\r
99 #define dhcpMESSAGE_TYPE_OFFER ( 2 )
\r
100 #define dhcpMESSAGE_TYPE_REQUEST ( 3 )
\r
101 #define dhcpMESSAGE_TYPE_ACK ( 5 )
\r
102 #define dhcpMESSAGE_TYPE_NACK ( 6 )
\r
104 /* Offsets into the transmitted DHCP options fields at which various parameters
\r
106 #define dhcpCLIENT_IDENTIFIER_OFFSET ( 5 )
\r
107 #define dhcpREQUESTED_IP_ADDRESS_OFFSET ( 13 )
\r
108 #define dhcpDHCP_SERVER_IP_ADDRESS_OFFSET ( 19 )
\r
110 /* Values used in the DHCP packets. */
\r
111 #define dhcpREQUEST_OPCODE ( 1 )
\r
112 #define dhcpREPLY_OPCODE ( 2 )
\r
113 #define dhcpADDRESS_TYPE_ETHERNET ( 1 )
\r
114 #define dhcpETHERNET_ADDRESS_LENGTH ( 6 )
\r
116 /* If a lease time is not received, use the default of two days. */
\r
117 #define dhcpDEFAULT_LEASE_TIME ( ( 48UL * 60UL * 60UL * 1000UL ) / portTICK_RATE_MS ) /* 48 hours in ticks. */
\r
119 /* Don't allow the lease time to be too short. */
\r
120 #define dhcpMINIMUM_LEASE_TIME ( 60000UL / portTICK_RATE_MS ) /* 60 seconds in ticks. */
\r
122 /* Marks the end of the variable length options field in the DHCP packet. */
\r
123 #define dhcpOPTION_END_BYTE 0xff
\r
125 /* Offset into a DHCP message at which the first byte of the options is
\r
127 #define dhcpFIRST_OPTION_BYTE_OFFSET ( 0xf0 )
\r
129 /* When walking the variable length options field, the following value is used
\r
130 to ensure the walk has not gone past the end of the valid options. 2 bytes is
\r
131 made up of the length byte, and minimum one byte value. */
\r
132 #define dhcpMAX_OPTION_LENGTH_OF_INTEREST ( 2L )
\r
134 /* Standard DHCP port numbers and magic cookie value. */
\r
135 #if( ipconfigBYTE_ORDER == FREERTOS_LITTLE_ENDIAN )
\r
136 #define dhcpCLIENT_PORT 0x4400
\r
137 #define dhcpSERVER_PORT 0x4300
\r
138 #define dhcpCOOKIE 0x63538263
\r
139 #define dhcpBROADCAST 0x0080
\r
141 #define dhcpCLIENT_PORT 0x0044
\r
142 #define dhcpSERVER_PORT 0x0043
\r
143 #define dhcpCOOKIE 0x63825363
\r
144 #define dhcpBROADCAST 0x8000
\r
145 #endif /* ipconfigBYTE_ORDER */
\r
147 #include "pack_struct_start.h"
\r
148 struct xDHCPMessage
\r
151 uint8_t ucAddressType;
\r
152 uint8_t ucAddressLength;
\r
154 uint32_t ulTransactionID;
\r
155 uint16_t usElapsedTime;
\r
157 uint32_t ulClientIPAddress_ciaddr;
\r
158 uint32_t ulYourIPAddress_yiaddr;
\r
159 uint32_t ulServerIPAddress_siaddr;
\r
160 uint32_t ulRelayAgentIPAddress_giaddr;
\r
161 uint8_t ucClientHardwareAddress[ dhcpCLIENT_HARDWARE_ADDRESS_LENGTH ];
\r
162 uint8_t ucServerHostName[ dhcpSERVER_HOST_NAME_LENGTH ];
\r
163 uint8_t ucBootFileName[ dhcpBOOT_FILE_NAME_LENGTH ];
\r
164 uint32_t ulDHCPCookie;
\r
165 uint8_t ucFirstOptionByte;
\r
167 #include "pack_struct_end.h"
\r
168 typedef struct xDHCPMessage xDHCPMessage_t;
\r
170 /* DHCP state machine states. */
\r
173 eWaitingSendFirstDiscover = 0, /* Initial state. Send a discover the first time it is called, and reset all timers. */
\r
174 eWaitingOffer, /* Either resend the discover, or, if the offer is forthcoming, send a request. */
\r
175 eWaitingAcknowledge, /* Either resend the request. */
\r
176 eLeasedAddress, /* Resend the request at the appropriate time to renew the lease. */
\r
177 eNotUsingLeasedAddress /* DHCP failed, and a default IP address is being used. */
\r
181 * Generate a DHCP discover message and send it on the DHCP socket.
\r
183 static void prvSendDHCPDiscover( xMACAddress_t *pxMACAddress );
\r
186 * Interpret message received on the DHCP socket.
\r
188 static BaseType_t prvProcessDHCPReplies( uint8_t ucExpectedMessageType, xMACAddress_t *pxMACAddress, xNetworkAddressingParameters_t *pxNetworkAddressing );
\r
191 * Generate a DHCP request packet, and send it on the DHCP socket.
\r
193 static void prvSendDHCPRequest( xMACAddress_t *pxMACAddress );
\r
196 * Prepare to start a DHCP transaction. This initialises some state variables
\r
197 * and creates the DHCP socket if necessary.
\r
199 static void prvInitialiseDHCP( void );
\r
202 * Creates the part of outgoing DHCP messages that are common to all outgoing
\r
205 static uint8_t *prvCreatePartDHCPMessage( struct freertos_sockaddr *pxAddress, xMACAddress_t *pxMACAddress, uint8_t ucOpcode, const uint8_t * const pucOptionsArray, size_t xOptionsArraySize );
\r
208 * Create the DHCP socket, if it has not been created already.
\r
210 static void prvCreateDHCPSocket( void );
\r
212 /*-----------------------------------------------------------*/
\r
214 /* The timer used to drive the DHCP state machine. */
\r
215 static xTimerHandle xDHCPTimer = NULL;
\r
217 /* The UDP socket used for all incoming and outgoing DHCP traffic. */
\r
218 static xSocket_t xDHCPSocket = NULL;
\r
220 /* Hold information in between steps in the DHCP state machine. */
\r
221 static uint32_t ulTransactionId = 0UL, ulOfferedIPAddress = 0UL, ulDHCPServerAddress = 0UL, ulLeaseTime = 0;
\r
223 /* Hold information on the current timer state. */
\r
224 static TickType_t xDHCPTxTime = 0x00, xDHCPTxPeriod = 0x00;
\r
226 /* Maintains the DHCP state machine state. */
\r
227 static eDHCPState_t eDHCPState = eWaitingSendFirstDiscover;
\r
229 /*-----------------------------------------------------------*/
\r
231 void vDHCPProcess( BaseType_t xReset, xMACAddress_t *pxMACAddress, uint32_t *pulIPAddress, xNetworkAddressingParameters_t *pxNetworkAddressing )
\r
233 if( xReset != pdFALSE )
\r
235 eDHCPState = eWaitingSendFirstDiscover;
\r
238 switch( eDHCPState )
\r
240 case eWaitingSendFirstDiscover :
\r
242 /* Initial state. Create the DHCP socket, timer, etc. if they
\r
243 have not already been created. */
\r
244 prvInitialiseDHCP();
\r
245 *pulIPAddress = 0UL;
\r
247 /* Send the first discover request. */
\r
248 if( xDHCPSocket != NULL )
\r
250 xDHCPTxTime = xTaskGetTickCount();
\r
251 prvSendDHCPDiscover( pxMACAddress );
\r
252 eDHCPState = eWaitingOffer;
\r
256 case eWaitingOffer :
\r
258 /* Look for offers coming in. */
\r
259 if( prvProcessDHCPReplies( dhcpMESSAGE_TYPE_OFFER, pxMACAddress, pxNetworkAddressing ) == pdPASS )
\r
261 /* An offer has been made, generate the request. */
\r
262 xDHCPTxTime = xTaskGetTickCount();
\r
263 xDHCPTxPeriod = dhcpINITIAL_DHCP_TX_PERIOD;
\r
264 prvSendDHCPRequest( pxMACAddress );
\r
265 eDHCPState = eWaitingAcknowledge;
\r
269 /* Is it time to send another Discover? */
\r
270 if( ( xTaskGetTickCount() - xDHCPTxTime ) > xDHCPTxPeriod )
\r
272 /* Increase the time period, and if it has not got to the
\r
273 point of giving up - send another discovery. */
\r
274 xDHCPTxPeriod <<= 1;
\r
275 if( xDHCPTxPeriod <= ipconfigMAXIMUM_DISCOVER_TX_PERIOD )
\r
278 xDHCPTxTime = xTaskGetTickCount();
\r
279 prvSendDHCPDiscover( pxMACAddress );
\r
283 /* Revert to static IP address. */
\r
284 taskENTER_CRITICAL();
\r
286 *pulIPAddress = pxNetworkAddressing->ulDefaultIPAddress;
\r
287 iptraceDHCP_REQUESTS_FAILED_USING_DEFAULT_IP_ADDRESS( pxNetworkAddressing->ulDefaultIPAddress );
\r
289 taskEXIT_CRITICAL();
\r
290 eDHCPState = eNotUsingLeasedAddress;
\r
291 xTimerStop( xDHCPTimer, ( TickType_t ) 0 );
\r
293 #if ipconfigUSE_NETWORK_EVENT_HOOK == 1
\r
295 vApplicationIPNetworkEventHook( eNetworkUp );
\r
299 /* Static configuration is being used, so the network is now up. */
\r
300 #if ipconfigFREERTOS_PLUS_NABTO == 1
\r
302 /* Return value is used in configASSERT() inside the
\r
304 ( void ) xStartNabtoTask();
\r
306 #endif /* ipconfigFREERTOS_PLUS_NABTO */
\r
308 /* Close socket to ensure packets don't queue on it. */
\r
309 FreeRTOS_closesocket( xDHCPSocket );
\r
310 xDHCPSocket = NULL;
\r
316 case eWaitingAcknowledge :
\r
318 /* Look for acks coming in. */
\r
319 if( prvProcessDHCPReplies( dhcpMESSAGE_TYPE_ACK, pxMACAddress, pxNetworkAddressing ) == pdPASS )
\r
321 /* DHCP completed. The IP address can now be used, and the
\r
322 timer set to the lease timeout time. */
\r
323 *pulIPAddress = ulOfferedIPAddress;
\r
324 eDHCPState = eLeasedAddress;
\r
326 #if ipconfigUSE_NETWORK_EVENT_HOOK == 1
\r
328 vApplicationIPNetworkEventHook( eNetworkUp );
\r
332 /* Static configuration is being used, so the network is now
\r
334 #if ipconfigFREERTOS_PLUS_NABTO == 1
\r
336 /* Return value is used in configASSERT() inside the
\r
338 ( void ) xStartNabtoTask();
\r
340 #endif /* ipconfigFREERTOS_PLUS_NABTO */
\r
342 /* Close socket to ensure packets don't queue on it. */
\r
343 FreeRTOS_closesocket( xDHCPSocket );
\r
344 xDHCPSocket = NULL;
\r
346 if( ulLeaseTime == 0UL )
\r
348 ulLeaseTime = dhcpDEFAULT_LEASE_TIME;
\r
350 else if( ulLeaseTime < dhcpMINIMUM_LEASE_TIME )
\r
352 ulLeaseTime = dhcpMINIMUM_LEASE_TIME;
\r
356 /* The lease time is already valid. */
\r
359 xTimerChangePeriod( xDHCPTimer, ulLeaseTime, portMAX_DELAY );
\r
363 /* Is it time to send another Discover? */
\r
364 if( ( xTaskGetTickCount() - xDHCPTxTime ) > xDHCPTxPeriod )
\r
366 /* Increase the time period, and if it has not got to the
\r
367 point of giving up - send another request. */
\r
368 xDHCPTxPeriod <<= 1;
\r
369 if( xDHCPTxPeriod <= ipconfigMAXIMUM_DISCOVER_TX_PERIOD )
\r
371 xDHCPTxTime = xTaskGetTickCount();
\r
372 prvSendDHCPRequest( pxMACAddress );
\r
376 /* Give up, start again. */
\r
377 eDHCPState = eWaitingSendFirstDiscover;
\r
383 case eLeasedAddress :
\r
385 /* Resend the request at the appropriate time to renew the lease. */
\r
386 prvCreateDHCPSocket();
\r
387 if( xDHCPSocket != NULL )
\r
389 xDHCPTxTime = xTaskGetTickCount();
\r
390 xDHCPTxPeriod = dhcpINITIAL_DHCP_TX_PERIOD;
\r
391 prvSendDHCPRequest( pxMACAddress );
\r
392 eDHCPState = eWaitingAcknowledge;
\r
394 xTimerChangePeriod( xDHCPTimer, dhcpINITIAL_TIMER_PERIOD, portMAX_DELAY );
\r
397 case eNotUsingLeasedAddress:
\r
398 xTimerStop( xDHCPTimer, ( TickType_t ) 0 );
\r
402 /*-----------------------------------------------------------*/
\r
404 static void prvCreateDHCPSocket( void )
\r
406 struct freertos_sockaddr xAddress;
\r
407 BaseType_t xReturn;
\r
408 TickType_t xTimeoutTime = 0;
\r
410 /* Create the socket, if it has not already been created. */
\r
411 if( xDHCPSocket == NULL )
\r
413 xDHCPSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP );
\r
414 configASSERT( ( xDHCPSocket != FREERTOS_INVALID_SOCKET ) );
\r
416 /* Ensure the Rx and Tx timeouts are zero as the DHCP executes in the
\r
417 context of the IP task. */
\r
418 FreeRTOS_setsockopt( xDHCPSocket, 0, FREERTOS_SO_RCVTIMEO, ( void * ) &xTimeoutTime, sizeof( TickType_t ) );
\r
419 FreeRTOS_setsockopt( xDHCPSocket, 0, FREERTOS_SO_SNDTIMEO, ( void * ) &xTimeoutTime, sizeof( TickType_t ) );
\r
421 /* Bind to the standard DHCP client port. */
\r
422 xAddress.sin_port = dhcpCLIENT_PORT;
\r
423 xReturn = FreeRTOS_bind( xDHCPSocket, &xAddress, sizeof( xAddress ) );
\r
424 configASSERT( xReturn == 0 );
\r
426 /* Remove compiler warnings if configASSERT() is not defined. */
\r
430 /*-----------------------------------------------------------*/
\r
432 static void prvInitialiseDHCP( void )
\r
434 extern void vIPFunctionsTimerCallback( xTimerHandle xTimer );
\r
436 /* Initialise the parameters that will be set by the DHCP process. */
\r
437 if( ulTransactionId == 0 )
\r
439 ulTransactionId = ipconfigRAND32();
\r
445 ulOfferedIPAddress = 0UL;
\r
446 ulDHCPServerAddress = 0UL;
\r
447 xDHCPTxPeriod = dhcpINITIAL_DHCP_TX_PERIOD;
\r
449 /* Create the DHCP socket if it has not already been created. */
\r
450 prvCreateDHCPSocket();
\r
452 if( xDHCPTimer == NULL )
\r
454 xDHCPTimer = xTimerCreate( "DHCP", dhcpINITIAL_TIMER_PERIOD, pdTRUE, ( void * ) eDHCPEvent, vIPFunctionsTimerCallback );
\r
455 configASSERT( xDHCPTimer );
\r
456 xTimerStart( xDHCPTimer, portMAX_DELAY );
\r
460 xTimerChangePeriod( xDHCPTimer, dhcpINITIAL_TIMER_PERIOD, portMAX_DELAY );
\r
463 /*-----------------------------------------------------------*/
\r
465 static BaseType_t prvProcessDHCPReplies( uint8_t ucExpectedMessageType, xMACAddress_t *pxMACAddress, xNetworkAddressingParameters_t *pxNetworkAddressing )
\r
467 uint8_t *pucUDPPayload, *pucLastByte;
\r
468 struct freertos_sockaddr xClient;
\r
469 uint32_t xClientLength = sizeof( xClient );
\r
471 xDHCPMessage_t *pxDHCPMessage;
\r
472 uint8_t *pucByte, ucOptionCode, ucLength;
\r
473 uint32_t ulProcessed;
\r
474 BaseType_t xReturn = pdFALSE;
\r
475 const uint32_t ulMandatoryOptions = 2; /* DHCP server address, and the correct DHCP message type must be present in the options. */
\r
477 lBytes = FreeRTOS_recvfrom( xDHCPSocket, ( void * ) &pucUDPPayload, 0, FREERTOS_ZERO_COPY, &xClient, &xClientLength );
\r
481 /* Map a DHCP structure onto the received data. */
\r
482 pxDHCPMessage = ( xDHCPMessage_t * ) ( pucUDPPayload );
\r
484 /* Sanity check. */
\r
485 if( ( pxDHCPMessage->ulDHCPCookie == dhcpCOOKIE ) && ( pxDHCPMessage->ucOpcode == dhcpREPLY_OPCODE ) && ( pxDHCPMessage->ulTransactionID == ulTransactionId ) )
\r
487 if( memcmp( ( void * ) &( pxDHCPMessage->ucClientHardwareAddress ), ( void * ) pxMACAddress, sizeof( xMACAddress_t ) ) == 0 )
\r
489 /* None of the essential options have been processed yet. */
\r
492 /* Walk through the options until the dhcpOPTION_END_BYTE byte
\r
493 is found, taking care not to walk off the end of the options. */
\r
494 pucByte = &( pxDHCPMessage->ucFirstOptionByte );
\r
495 pucLastByte = &( pucUDPPayload[ lBytes - dhcpMAX_OPTION_LENGTH_OF_INTEREST ] );
\r
496 while( ( *pucByte != dhcpOPTION_END_BYTE ) && ( pucByte < pucLastByte ) )
\r
498 ucOptionCode = *pucByte;
\r
500 ucLength = *pucByte;
\r
503 switch( ucOptionCode )
\r
505 case dhcpMESSAGE_TYPE_OPTION_CODE :
\r
507 if( *pucByte == ucExpectedMessageType )
\r
509 /* The message type is the message type the
\r
510 state machine is expecting. */
\r
513 else if( *pucByte == dhcpMESSAGE_TYPE_NACK )
\r
515 if( ucExpectedMessageType == dhcpMESSAGE_TYPE_ACK )
\r
518 eDHCPState = eWaitingSendFirstDiscover;
\r
523 /* Don't process other message types. */
\r
527 case dhcpSUBNET_MASK_OPTION_CODE :
\r
529 if( ucLength == sizeof( uint32_t ) )
\r
531 memcpy( ( void * ) &( pxNetworkAddressing->ulNetMask ), ( void * ) pucByte, ( size_t ) ucLength );
\r
535 case dhcpGATEWAY_OPTION_CODE :
\r
537 if( ucLength == sizeof( uint32_t ) )
\r
539 /* ulProcessed is not incremented in this case
\r
540 because the gateway is not essential. */
\r
541 memcpy( ( void * ) &( pxNetworkAddressing->ulGatewayAddress ), ( void * ) pucByte, ( size_t ) ucLength );
\r
545 case hdcpDNS_SERVER_OPTIONS_CODE :
\r
547 /* ulProcessed is not incremented in this case
\r
548 because the DNS server is not essential. Only the
\r
549 first DNS server address is taken. */
\r
550 memcpy( ( void * ) &( pxNetworkAddressing->ulDNSServerAddress ), ( void * ) pucByte, sizeof( uint32_t ) );
\r
553 case dhcpSERVER_IP_ADDRESS_OPTION_CODE :
\r
555 if( ucLength == sizeof( uint32_t ) )
\r
557 if( ucExpectedMessageType == dhcpMESSAGE_TYPE_OFFER )
\r
559 /* Offers state the replying server. */
\r
561 memcpy( ( void * ) &ulDHCPServerAddress, ( void * ) pucByte, ( size_t ) ucLength );
\r
565 /* The ack must come from the expected server. */
\r
566 if( memcmp( ( void * ) &ulDHCPServerAddress, ( void * ) pucByte, ( size_t ) ucLength ) == 0 )
\r
574 case dhcpLEASE_TIME_OPTION_CODE :
\r
576 if( ucLength == sizeof( &ulLeaseTime ) )
\r
578 /* ulProcessed is not incremented in this case
\r
579 because the lease time is not essential. */
\r
580 memcpy( ( void * ) &ulLeaseTime, ( void * ) pucByte, ( size_t ) ucLength );
\r
581 ulLeaseTime = FreeRTOS_ntohl( ulLeaseTime );
\r
583 /* Convert the lease time to milliseconds
\r
584 (*1000) then ticks (/portTICK_RATE_MS). */
\r
585 ulLeaseTime *= ( 1000UL / portTICK_RATE_MS );
\r
587 /* Divide the lease time to ensure a renew
\r
588 request is sent before the lease actually
\r
590 ulLeaseTime >>= 1UL;
\r
596 /* Not interested in this field. */
\r
601 /* Jump over the data to find the next option code. */
\r
602 if( ucLength == 0 )
\r
608 pucByte += ucLength;
\r
612 /* Were all the mandatory options received? */
\r
613 if( ulProcessed == ulMandatoryOptions )
\r
615 ulOfferedIPAddress = pxDHCPMessage->ulYourIPAddress_yiaddr;
\r
621 FreeRTOS_ReleaseUDPPayloadBuffer( ( void * ) pucUDPPayload );
\r
626 /*-----------------------------------------------------------*/
\r
628 static uint8_t *prvCreatePartDHCPMessage( struct freertos_sockaddr *pxAddress, xMACAddress_t *pxMACAddress, uint8_t ucOpcode, const uint8_t * const pucOptionsArray, size_t xOptionsArraySize )
\r
630 xDHCPMessage_t *pxDHCPMessage;
\r
631 const size_t xRequiredBufferSize = sizeof( xDHCPMessage_t ) + xOptionsArraySize;
\r
632 uint8_t *pucUDPPayloadBuffer;
\r
633 static uint8_t ucUseBroadcastFlag = pdFALSE;
\r
635 /* Get a buffer. This uses a maximum delay, but the delay will be capped
\r
636 to ipconfigMAX_SEND_BLOCK_TIME_TICKS so the return value still needs to be
\r
640 }while( ( pucUDPPayloadBuffer = ( uint8_t * ) FreeRTOS_GetUDPPayloadBuffer( xRequiredBufferSize, portMAX_DELAY ) ) == NULL );
\r
642 pxDHCPMessage = ( xDHCPMessage_t * ) pucUDPPayloadBuffer;
\r
644 /* Most fields need to be zero. */
\r
645 memset( ( void * ) pxDHCPMessage, 0x00, sizeof( xDHCPMessage_t ) );
\r
647 /* Create the message. */
\r
648 pxDHCPMessage->ucOpcode = ucOpcode;
\r
649 pxDHCPMessage->ucAddressType = dhcpADDRESS_TYPE_ETHERNET;
\r
650 pxDHCPMessage->ucAddressLength = dhcpETHERNET_ADDRESS_LENGTH;
\r
651 pxDHCPMessage->ulTransactionID = ulTransactionId;
\r
652 pxDHCPMessage->ulDHCPCookie = dhcpCOOKIE;
\r
654 /* For maximum possibility of success, alternate between broadcast and non
\r
656 ucUseBroadcastFlag = !ucUseBroadcastFlag;
\r
657 if( ucUseBroadcastFlag == pdTRUE )
\r
659 pxDHCPMessage->usFlags = dhcpBROADCAST;
\r
663 pxDHCPMessage->usFlags = 0;
\r
666 memcpy( ( void * ) &( pxDHCPMessage->ucClientHardwareAddress[ 0 ] ), ( void * ) pxMACAddress, sizeof( xMACAddress_t ) );
\r
668 /* Copy in the const part of the options options. */
\r
669 memcpy( ( void * ) &( pucUDPPayloadBuffer[ dhcpFIRST_OPTION_BYTE_OFFSET ] ), ( void * ) pucOptionsArray, xOptionsArraySize );
\r
671 /* Map in the client identifier. */
\r
672 memcpy( ( void * ) &( pucUDPPayloadBuffer[ dhcpFIRST_OPTION_BYTE_OFFSET + dhcpCLIENT_IDENTIFIER_OFFSET ] ), ( void * ) pxMACAddress, sizeof( xMACAddress_t ) );
\r
674 /* Set the addressing. */
\r
675 pxAddress->sin_addr = ipBROADCAST_IP_ADDRESS;
\r
676 pxAddress->sin_port = ( uint16_t ) dhcpSERVER_PORT;
\r
678 return pucUDPPayloadBuffer;
\r
680 /*-----------------------------------------------------------*/
\r
682 static void prvSendDHCPRequest( xMACAddress_t *pxMACAddress )
\r
684 uint8_t *pucUDPPayloadBuffer;
\r
685 struct freertos_sockaddr xAddress;
\r
686 static const uint8_t ucDHCPRequestOptions[] =
\r
688 /* Do not change the ordering without also changing
\r
689 dhcpCLIENT_IDENTIFIER_OFFSET, dhcpREQUESTED_IP_ADDRESS_OFFSET and
\r
690 dhcpDHCP_SERVER_IP_ADDRESS_OFFSET. */
\r
691 dhcpMESSAGE_TYPE_OPTION_CODE, 1, dhcpMESSAGE_TYPE_REQUEST, /* Message type option. */
\r
692 dhcpCLIENT_IDENTIFIER_OPTION_CODE, 6, 0, 0, 0, 0, 0, 0, /* Client identifier. */
\r
693 dhcpREQUEST_IP_ADDRESS_OPTION_CODE, 4, 0, 0, 0, 0, /* The IP address being requested. */
\r
694 dhcpSERVER_IP_ADDRESS_OPTION_CODE, 4, 0, 0, 0, 0, /* The IP address of the DHCP server. */
\r
695 dhcpOPTION_END_BYTE
\r
698 pucUDPPayloadBuffer = prvCreatePartDHCPMessage( &xAddress, pxMACAddress, dhcpREQUEST_OPCODE, ucDHCPRequestOptions, sizeof( ucDHCPRequestOptions ) );
\r
700 /* Copy in the IP address being requested. */
\r
701 memcpy( ( void * ) &( pucUDPPayloadBuffer[ dhcpFIRST_OPTION_BYTE_OFFSET + dhcpREQUESTED_IP_ADDRESS_OFFSET ] ), ( void * ) &ulOfferedIPAddress, sizeof( ulOfferedIPAddress ) );
\r
703 /* Copy in the address of the DHCP server being used. */
\r
704 memcpy( ( void * ) &( pucUDPPayloadBuffer[ dhcpFIRST_OPTION_BYTE_OFFSET + dhcpDHCP_SERVER_IP_ADDRESS_OFFSET ] ), ( void * ) &ulDHCPServerAddress, sizeof( ulDHCPServerAddress ) );
\r
706 iptraceSENDING_DHCP_REQUEST();
\r
707 if( FreeRTOS_sendto( xDHCPSocket, pucUDPPayloadBuffer, ( sizeof( xDHCPMessage_t ) + sizeof( ucDHCPRequestOptions ) ), FREERTOS_ZERO_COPY, &xAddress, sizeof( xAddress ) ) == 0 )
\r
709 /* The packet was not successfully queued for sending and must be
\r
710 returned to the stack. */
\r
711 FreeRTOS_ReleaseUDPPayloadBuffer( pucUDPPayloadBuffer );
\r
714 /*-----------------------------------------------------------*/
\r
716 static void prvSendDHCPDiscover( xMACAddress_t *pxMACAddress )
\r
718 uint8_t *pucUDPPayloadBuffer;
\r
719 struct freertos_sockaddr xAddress;
\r
720 static const uint8_t ucDHCPDiscoverOptions[] =
\r
722 /* Do not change the ordering without also changing dhcpCLIENT_IDENTIFIER_OFFSET. */
\r
723 dhcpMESSAGE_TYPE_OPTION_CODE, 1, dhcpMESSAGE_TYPE_DISCOVER, /* Message type option. */
\r
724 dhcpCLIENT_IDENTIFIER_OPTION_CODE, 6, 0, 0, 0, 0, 0, 0, /* Client identifier. */
\r
725 dhcpPARAMETER_REQUEST_OPTION_CODE, 3, dhcpSUBNET_MASK_OPTION_CODE, dhcpGATEWAY_OPTION_CODE, hdcpDNS_SERVER_OPTIONS_CODE, /* Parameter request option. */
\r
726 dhcpOPTION_END_BYTE
\r
729 pucUDPPayloadBuffer = prvCreatePartDHCPMessage( &xAddress, pxMACAddress, dhcpREQUEST_OPCODE, ucDHCPDiscoverOptions, sizeof( ucDHCPDiscoverOptions ) );
\r
731 iptraceSENDING_DHCP_DISCOVER();
\r
732 if( FreeRTOS_sendto( xDHCPSocket, pucUDPPayloadBuffer, ( sizeof( xDHCPMessage_t ) + sizeof( ucDHCPDiscoverOptions ) ), FREERTOS_ZERO_COPY, &xAddress, sizeof( xAddress ) ) == 0 )
\r
734 /* The packet was not successfully queued for sending and must be
\r
735 returned to the stack. */
\r
736 FreeRTOS_ReleaseUDPPayloadBuffer( pucUDPPayloadBuffer );
\r
739 /*-----------------------------------------------------------*/
\r
741 #endif /* ipconfigUSE_DHCP != 0 */
\r