--- /dev/null
+/*\r
+ * FreeRTOS+UDP V1.0.0 (C) 2013 Real Time Engineers ltd.\r
+ *\r
+ * FreeRTOS+UDP is an add-on component to FreeRTOS. It is not, in itself, part\r
+ * of the FreeRTOS kernel. FreeRTOS+UDP is licensed separately from FreeRTOS,\r
+ * and uses a different license to FreeRTOS. FreeRTOS+UDP uses a dual license\r
+ * model, information on which is provided below:\r
+ *\r
+ * - Open source licensing -\r
+ * FreeRTOS+UDP is a free download and may be used, modified and distributed\r
+ * without charge provided the user adheres to version two of the GNU General\r
+ * Public license (GPL) and does not remove the copyright notice or this text.\r
+ * The GPL V2 text is available on the gnu.org web site, and on the following\r
+ * URL: http://www.FreeRTOS.org/gpl-2.0.txt\r
+ *\r
+ * - Commercial licensing -\r
+ * Businesses and individuals who wish to incorporate FreeRTOS+UDP into\r
+ * proprietary software for redistribution in any form must first obtain a\r
+ * (very) low cost commercial license - and in-so-doing support the maintenance,\r
+ * support and further development of the FreeRTOS+UDP product. Commercial\r
+ * licenses can be obtained from http://shop.freertos.org and do not require any\r
+ * source files to be changed.\r
+ *\r
+ * FreeRTOS+UDP is distributed in the hope that it will be useful. You cannot\r
+ * use FreeRTOS+UDP unless you agree that you use the software 'as is'.\r
+ * FreeRTOS+UDP is provided WITHOUT ANY WARRANTY; without even the implied\r
+ * warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR\r
+ * PURPOSE. Real Time Engineers Ltd. disclaims all conditions and terms, be they\r
+ * implied, expressed, or statutory.\r
+ *\r
+ * 1 tab == 4 spaces!\r
+ *\r
+ * http://www.FreeRTOS.org\r
+ * http://www.FreeRTOS.org/udp\r
+ *\r
+ */\r
+\r
+/* Standard includes. */\r
+#include <stdint.h>\r
+\r
+/* FreeRTOS includes. */\r
+#include "FreeRTOS.h"\r
+#include "task.h"\r
+#include "queue.h"\r
+#include "timers.h"\r
+\r
+/* FreeRTOS+UDP includes. */\r
+#include "FreeRTOS_UDP_IP.h"\r
+#include "FreeRTOS_IP_Private.h"\r
+#include "FreeRTOS_DHCP.h"\r
+#include "FreeRTOS_Sockets.h"\r
+#include "NetworkInterface.h"\r
+#include "IPTraceMacroDefaults.h"\r
+\r
+/* Exclude the entire file if DHCP is not enabled. */\r
+#if ipconfigUSE_DHCP != 0\r
+\r
+#if ( ipconfigUSE_DHCP != 0 ) && ( ipconfigNETWORK_MTU < 586 )\r
+ /* DHCP must be able to receive an options field of 312 bytes, the fixed\r
+ part of the DHCP packet is 240 bytes, and the IP/UDP headers take 28 bytes. */\r
+ #error ipconfigNETWORK_MTU needs to be at least 586 to use DHCP (588 if ipconfigCAN_FRAGMENT_OUTGOING_PACKETS is set to 1)\r
+#endif\r
+\r
+/* Parameter widths in the DHCP packet. */\r
+#define dhcpCLIENT_HARDWARE_ADDRESS_LENGTH 16\r
+#define dhcpSERVER_HOST_NAME_LENGTH 64\r
+#define dhcpBOOT_FILE_NAME_LENGTH 128\r
+\r
+/* Timer parameters. Windows simulator times are much shorter because simulated\r
+time is not real time. */\r
+#ifdef _WINDOWS_\r
+ #define dhcpINITIAL_DHCP_TX_PERIOD ( 100 / portTICK_RATE_MS )\r
+ #define dhcpINITIAL_TIMER_PERIOD ( 10 / portTICK_RATE_MS )\r
+ #define dhcpMAX_TIME_TO_WAIT_FOR_ACK ( 200 / portTICK_RATE_MS )\r
+#else\r
+ #define dhcpINITIAL_DHCP_TX_PERIOD ( 5000 / portTICK_RATE_MS )\r
+ #define dhcpINITIAL_TIMER_PERIOD ( 250 / portTICK_RATE_MS )\r
+ #define dhcpMAX_TIME_TO_WAIT_FOR_ACK ( 5000 / portTICK_RATE_MS )\r
+#endif /* _WINDOWS_ */\r
+\r
+/* Codes of interest found in the DHCP options field. */\r
+#define dhcpSUBNET_MASK_OPTION_CODE ( 1 )\r
+#define dhcpGATEWAY_OPTION_CODE ( 3 )\r
+#define hdcpDNS_SERVER_OPTIONS_CODE ( 6 )\r
+#define dhcpMESSAGE_TYPE_OPTION_CODE ( 53 )\r
+#define dhcpLEASE_TIME_OPTION_CODE ( 51 )\r
+#define dhcpCLIENT_IDENTIFIER_OPTION_CODE ( 61 )\r
+#define dhcpPARAMETER_REQUEST_OPTION_CODE ( 55 )\r
+#define dhcpREQUEST_IP_ADDRESS_OPTION_CODE ( 50 )\r
+#define dhcpSERVER_IP_ADDRESS_OPTION_CODE ( 54 )\r
+\r
+/* The four DHCP message types of interest. */\r
+#define dhcpMESSAGE_TYPE_DISCOVER ( 1 )\r
+#define dhcpMESSAGE_TYPE_OFFER ( 2 )\r
+#define dhcpMESSAGE_TYPE_REQUEST ( 3 )\r
+#define dhcpMESSAGE_TYPE_ACK ( 5 )\r
+#define dhcpMESSAGE_TYPE_NACK ( 6 )\r
+\r
+/* Offsets into the transmitted DHCP options fields at which various parameters\r
+are located. */\r
+#define dhcpCLIENT_IDENTIFIER_OFFSET ( 5 )\r
+#define dhcpREQUESTED_IP_ADDRESS_OFFSET ( 13 )\r
+#define dhcpDHCP_SERVER_IP_ADDRESS_OFFSET ( 19 )\r
+\r
+/* Values used in the DHCP packets. */\r
+#define dhcpREQUEST_OPCODE ( 1 )\r
+#define dhcpREPLY_OPCODE ( 2 )\r
+#define dhcpADDRESS_TYPE_ETHERNET ( 1 )\r
+#define dhcpETHERNET_ADDRESS_LENGTH ( 6 )\r
+\r
+/* If a lease time is not received, use the default of two days. */\r
+#define dhcpDEFAULT_LEASE_TIME ( ( 48UL * 60UL * 60UL * 1000UL ) / portTICK_RATE_MS ) /* 48 hours in ticks. */\r
+\r
+/* Don't allow the lease time to be too short. */\r
+#define dhcpMINIMUM_LEASE_TIME ( 60000UL / portTICK_RATE_MS ) /* 60 seconds in ticks. */\r
+\r
+/* Marks the end of the variable length options field in the DHCP packet. */\r
+#define dhcpOPTION_END_BYTE 0xff\r
+\r
+/* Offset into a DHCP message at which the first byte of the options is\r
+located. */\r
+#define dhcpFIRST_OPTION_BYTE_OFFSET ( 0xf0 )\r
+\r
+/* When walking the variable length options field, the following value is used\r
+to ensure the walk has not gone past the end of the valid options. 2 bytes is\r
+made up of the length byte, and minimum one byte value. */\r
+#define dhcpMAX_OPTION_LENGTH_OF_INTEREST ( 2L )\r
+\r
+/* Standard DHCP port numbers and magic cookie value. */\r
+#if( ipconfigBYTE_ORDER == FREERTOS_LITTLE_ENDIAN )\r
+ #define dhcpCLIENT_PORT 0x4400\r
+ #define dhcpSERVER_PORT 0x4300\r
+ #define dhcpCOOKIE 0x63538263\r
+#else\r
+ #define dhcpCLIENT_PORT 0x0044\r
+ #define dhcpSERVER_PORT 0x0043\r
+ #define dhcpCOOKIE 0x63825363\r
+#endif /* ipconfigBYTE_ORDER */\r
+\r
+#include "pack_struct_start.h"\r
+struct xDHCPMessage\r
+{\r
+ uint8_t ucOpcode;\r
+ uint8_t ucAddressType;\r
+ uint8_t ucAddressLength;\r
+ uint8_t ucHops;\r
+ uint32_t ulTransactionID;\r
+ uint16_t usElapsedTime;\r
+ uint16_t usFlags;\r
+ uint32_t ulClientIPAddress_ciaddr;\r
+ uint32_t ulYourIPAddress_yiaddr;\r
+ uint32_t ulServerIPAddress_siaddr;\r
+ uint32_t ulRelayAgentIPAddress_giaddr;\r
+ uint8_t ucClientHardwareAddress[ dhcpCLIENT_HARDWARE_ADDRESS_LENGTH ];\r
+ uint8_t ucServerHostName[ dhcpSERVER_HOST_NAME_LENGTH ];\r
+ uint8_t ucBootFileName[ dhcpBOOT_FILE_NAME_LENGTH ];\r
+ uint32_t ulDHCPCookie;\r
+ uint8_t ucFirstOptionByte;\r
+}\r
+#include "pack_struct_end.h"\r
+typedef struct xDHCPMessage xDHCPMessage_t;\r
+\r
+/* DHCP state machine states. */\r
+typedef enum\r
+{\r
+ eWaitingSendFirstDiscover = 0, /* Initial state. Send a discover the first time it is called, and reset all timers. */\r
+ eWaitingOffer, /* Either resend the discover, or, if the offer is forthcoming, send a request. */\r
+ eWaitingAcknowledge, /* Either resend the request. */\r
+ eLeasedAddress, /* Resend the request at the appropriate time to renew the lease. */\r
+ eNotUsingLeasedAddress /* DHCP failed, and a default IP address is being used. */\r
+} eDHCPState_t;\r
+\r
+/*\r
+ * Generate a DHCP discover message and send it on the DHCP socket.\r
+ */\r
+static void prvSendDHCPDiscover( xMACAddress_t *pxMACAddress );\r
+\r
+/*\r
+ * Interpret message received on the DHCP socket.\r
+ */\r
+static portBASE_TYPE prvProcessDHCPReplies( uint8_t ucExpectedMessageType, xMACAddress_t *pxMACAddress, xNetworkAddressingParameters_t *pxNetworkAddressing );\r
+\r
+/*\r
+ * Generate a DHCP request packet, and send it on the DHCP socket.\r
+ */\r
+static void prvSendDHCPRequest( xMACAddress_t *pxMACAddress );\r
+\r
+/*\r
+ * Prepare to start a DHCP transaction. This initialises some state variables\r
+ * and creates the DHCP socket if necessary.\r
+ */\r
+static void prvInitialiseDHCP( void );\r
+\r
+/*\r
+ * Creates the part of outgoing DHCP messages that are common to all outgoing\r
+ * DHCP messages.\r
+ */\r
+static uint8_t *prvCreatePartDHCPMessage( struct freertos_sockaddr *pxAddress, xMACAddress_t *pxMACAddress, uint8_t ucOpcode, const uint8_t * const pucOptionsArray, size_t xOptionsArraySize );\r
+\r
+/*\r
+ * Create the DHCP socket, if it has not been created already.\r
+ */\r
+static void prvCreateDHCPSocket( void );\r
+\r
+/*-----------------------------------------------------------*/\r
+\r
+/* The timer used to drive the DHCP state machine. */\r
+static xTimerHandle xDHCPTimer = NULL;\r
+\r
+/* The UDP socket used for all incoming and outgoing DHCP traffic. */\r
+static xSocket_t xDHCPSocket = NULL;\r
+\r
+/* Hold information in between steps in the DHCP state machine. */\r
+static uint32_t ulTransactionId = 0UL, ulOfferedIPAddress = 0UL, ulDHCPServerAddress = 0UL, ulLeaseTime = 0;\r
+\r
+/* Hold information on the current timer state. */\r
+static portTickType xDHCPTxTime = 0x00, xDHCPTxPeriod = 0x00;\r
+\r
+/* Maintains the DHCP state machine state. */\r
+static eDHCPState_t eDHCPState = eWaitingSendFirstDiscover;\r
+\r
+/*-----------------------------------------------------------*/\r
+\r
+void vDHCPProcess( portBASE_TYPE xReset, xMACAddress_t *pxMACAddress, uint32_t *pulIPAddress, xNetworkAddressingParameters_t *pxNetworkAddressing )\r
+{\r
+ if( xReset != pdFALSE )\r
+ {\r
+ eDHCPState = eWaitingSendFirstDiscover;\r
+ }\r
+\r
+ switch( eDHCPState )\r
+ {\r
+ case eWaitingSendFirstDiscover :\r
+\r
+ /* Initial state. Create the DHCP socket, timer, etc. if they\r
+ have not already been created. */\r
+ prvInitialiseDHCP();\r
+ *pulIPAddress = 0UL;\r
+\r
+ /* Send the first discover request. */\r
+ if( xDHCPSocket != NULL )\r
+ {\r
+ xDHCPTxTime = xTaskGetTickCount();\r
+ prvSendDHCPDiscover( pxMACAddress );\r
+ eDHCPState = eWaitingOffer;\r
+ }\r
+ break;\r
+\r
+ case eWaitingOffer :\r
+\r
+ /* Look for offers coming in. */\r
+ if( prvProcessDHCPReplies( dhcpMESSAGE_TYPE_OFFER, pxMACAddress, pxNetworkAddressing ) == pdPASS )\r
+ {\r
+ /* An offer has been made, generate the request. */\r
+ xDHCPTxTime = xTaskGetTickCount();\r
+ xDHCPTxPeriod = dhcpINITIAL_DHCP_TX_PERIOD;\r
+ prvSendDHCPRequest( pxMACAddress );\r
+ eDHCPState = eWaitingAcknowledge;\r
+ }\r
+ else\r
+ {\r
+ /* Is it time to send another Discover? */\r
+ if( ( xTaskGetTickCount() - xDHCPTxTime ) > xDHCPTxPeriod )\r
+ {\r
+ /* Increase the time period, and if it has not got to the\r
+ point of giving up - send another discovery. */\r
+ xDHCPTxPeriod <<= 1;\r
+ if( xDHCPTxPeriod <= ipconfigMAXIMUM_DISCOVER_TX_PERIOD )\r
+ {\r
+ ulTransactionId++;\r
+ xDHCPTxTime = xTaskGetTickCount();\r
+ prvSendDHCPDiscover( pxMACAddress );\r
+ }\r
+ else\r
+ {\r
+ /* Revert to static IP address. */\r
+ taskENTER_CRITICAL();\r
+ {\r
+ *pulIPAddress = pxNetworkAddressing->ulDefaultIPAddress;\r
+ iptraceDHCP_REQUESTS_FAILED_USING_DEFAULT_IP_ADDRESS( pxNetworkAddressing->ulDefaultIPAddress );\r
+ }\r
+ taskEXIT_CRITICAL();\r
+ eDHCPState = eNotUsingLeasedAddress;\r
+ xTimerStop( xDHCPTimer, ( portTickType ) 0 );\r
+\r
+ #if ipconfigFREERTOS_PLUS_NABTO == 1\r
+ {\r
+ vStartNabtoTask();\r
+ }\r
+ #endif /* ipconfigFREERTOS_PLUS_NABTO */\r
+\r
+ #if ipconfigUSE_NETWORK_EVENT_HOOK == 1\r
+ {\r
+ vApplicationIPNetworkEventHook( eNetworkUp );\r
+ }\r
+ #endif\r
+\r
+ /* Close socket to ensure packets don't queue on it. */\r
+ FreeRTOS_closesocket( xDHCPSocket );\r
+ xDHCPSocket = NULL;\r
+ }\r
+ }\r
+ }\r
+ break;\r
+\r
+ case eWaitingAcknowledge :\r
+\r
+ /* Look for acks coming in. */\r
+ if( prvProcessDHCPReplies( dhcpMESSAGE_TYPE_ACK, pxMACAddress, pxNetworkAddressing ) == pdPASS )\r
+ {\r
+ /* DHCP completed. The IP address can now be used, and the\r
+ timer set to the lease timeout time. */\r
+ *pulIPAddress = ulOfferedIPAddress;\r
+ eDHCPState = eLeasedAddress;\r
+\r
+ #if ipconfigFREERTOS_PLUS_NABTO == 1\r
+ {\r
+ vStartNabtoTask();\r
+ }\r
+ #endif /* ipconfigFREERTOS_PLUS_NABTO */\r
+\r
+ #if ipconfigUSE_NETWORK_EVENT_HOOK == 1\r
+ {\r
+ vApplicationIPNetworkEventHook( eNetworkUp );\r
+ }\r
+ #endif\r
+\r
+ /* Close socket to ensure packets don't queue on it. */\r
+ FreeRTOS_closesocket( xDHCPSocket );\r
+ xDHCPSocket = NULL;\r
+\r
+ if( ulLeaseTime == 0UL )\r
+ {\r
+ ulLeaseTime = dhcpDEFAULT_LEASE_TIME;\r
+ }\r
+ else if( ulLeaseTime < dhcpMINIMUM_LEASE_TIME )\r
+ {\r
+ ulLeaseTime = dhcpMINIMUM_LEASE_TIME;\r
+ }\r
+ else\r
+ {\r
+ /* The lease time is already valid. */\r
+ }\r
+\r
+ xTimerChangePeriod( xDHCPTimer, ulLeaseTime, portMAX_DELAY );\r
+ }\r
+ else\r
+ {\r
+ /* Is it time to send another Discover? */\r
+ if( ( xTaskGetTickCount() - xDHCPTxTime ) > xDHCPTxPeriod )\r
+ {\r
+ /* Increase the time period, and if it has not got to the\r
+ point of giving up - send another request. */\r
+ xDHCPTxPeriod <<= 1;\r
+ if( xDHCPTxPeriod <= ipconfigMAXIMUM_DISCOVER_TX_PERIOD )\r
+ {\r
+ xDHCPTxTime = xTaskGetTickCount();\r
+ prvSendDHCPRequest( pxMACAddress );\r
+ }\r
+ else\r
+ {\r
+ /* Give up, start again. */\r
+ eDHCPState = eWaitingSendFirstDiscover;\r
+ }\r
+ }\r
+ }\r
+ break;\r
+\r
+ case eLeasedAddress :\r
+\r
+ /* Resend the request at the appropriate time to renew the lease. */\r
+ prvCreateDHCPSocket();\r
+ if( xDHCPSocket != NULL )\r
+ {\r
+ xDHCPTxTime = xTaskGetTickCount();\r
+ xDHCPTxPeriod = dhcpINITIAL_DHCP_TX_PERIOD;\r
+ prvSendDHCPRequest( pxMACAddress );\r
+ eDHCPState = eWaitingAcknowledge;\r
+ }\r
+ xTimerChangePeriod( xDHCPTimer, dhcpINITIAL_TIMER_PERIOD, portMAX_DELAY );\r
+ break;\r
+\r
+ case eNotUsingLeasedAddress:\r
+ xTimerStop( xDHCPTimer, ( portTickType ) 0 );\r
+ break;\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvCreateDHCPSocket( void )\r
+{\r
+struct freertos_sockaddr xAddress;\r
+portBASE_TYPE xReturn;\r
+portTickType xTimeoutTime = 0;\r
+\r
+ /* Create the socket, if it has not already been created. */\r
+ if( xDHCPSocket == NULL )\r
+ {\r
+ xDHCPSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP );\r
+ configASSERT( ( xDHCPSocket != FREERTOS_INVALID_SOCKET ) );\r
+\r
+ /* Ensure the Rx and Tx timeouts are zero as the DHCP executes in the\r
+ context of the IP task. */\r
+ FreeRTOS_setsockopt( xDHCPSocket, 0, FREERTOS_SO_RCVTIMEO, ( void * ) &xTimeoutTime, sizeof( portTickType ) );\r
+ FreeRTOS_setsockopt( xDHCPSocket, 0, FREERTOS_SO_SNDTIMEO, ( void * ) &xTimeoutTime, sizeof( portTickType ) );\r
+\r
+ /* Bind to the standard DHCP client port. */\r
+ xAddress.sin_port = dhcpCLIENT_PORT;\r
+ xReturn = FreeRTOS_bind( xDHCPSocket, &xAddress, sizeof( xAddress ) );\r
+ configASSERT( xReturn == 0 );\r
+\r
+ /* Remove compiler warnings if configASSERT() is not defined. */\r
+ ( void ) xReturn;\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvInitialiseDHCP( void )\r
+{\r
+extern void vIPFunctionsTimerCallback( xTimerHandle xTimer );\r
+\r
+ /* Initialise the parameters that will be set by the DHCP process. */\r
+ if( ulTransactionId == 0 )\r
+ {\r
+ ulTransactionId = ipconfigRAND32();\r
+ }\r
+ else\r
+ {\r
+ ulTransactionId++;\r
+ }\r
+ ulOfferedIPAddress = 0UL;\r
+ ulDHCPServerAddress = 0UL;\r
+ xDHCPTxPeriod = dhcpINITIAL_DHCP_TX_PERIOD;\r
+\r
+ /* Create the DHCP socket if it has not already been created. */\r
+ prvCreateDHCPSocket();\r
+\r
+ if( xDHCPTimer == NULL )\r
+ {\r
+ xDHCPTimer = xTimerCreate( ( const signed char * const ) "DHCP", dhcpINITIAL_TIMER_PERIOD, pdTRUE, ( void * ) eDHCPEvent, vIPFunctionsTimerCallback );\r
+ configASSERT( xDHCPTimer );\r
+ xTimerStart( xDHCPTimer, portMAX_DELAY );\r
+ }\r
+ else\r
+ {\r
+ xTimerChangePeriod( xDHCPTimer, dhcpINITIAL_TIMER_PERIOD, portMAX_DELAY );\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static portBASE_TYPE prvProcessDHCPReplies( uint8_t ucExpectedMessageType, xMACAddress_t *pxMACAddress, xNetworkAddressingParameters_t *pxNetworkAddressing )\r
+{\r
+uint8_t *pucUDPPayload, *pucLastByte;\r
+struct freertos_sockaddr xClient;\r
+uint32_t xClientLength = sizeof( xClient );\r
+int32_t lBytes;\r
+xDHCPMessage_t *pxDHCPMessage;\r
+uint8_t *pucByte, ucOptionCode, ucLength;\r
+uint32_t ulProcessed;\r
+portBASE_TYPE xReturn = pdFALSE;\r
+const uint32_t ulMandatoryOptions = 2; /* DHCP server address, and the correct DHCP message type must be present in the options. */\r
+\r
+ lBytes = FreeRTOS_recvfrom( xDHCPSocket, ( void * ) &pucUDPPayload, 0, FREERTOS_ZERO_COPY, &xClient, &xClientLength );\r
+\r
+ if( lBytes > 0 )\r
+ {\r
+ /* Map a DHCP structure onto the received data. */\r
+ pxDHCPMessage = ( xDHCPMessage_t * ) ( pucUDPPayload );\r
+\r
+ /* Sanity check. */\r
+ if( ( pxDHCPMessage->ulDHCPCookie == dhcpCOOKIE ) && ( pxDHCPMessage->ucOpcode == dhcpREPLY_OPCODE ) && ( pxDHCPMessage->ulTransactionID == ulTransactionId ) )\r
+ {\r
+ if( memcmp( ( void * ) &( pxDHCPMessage->ucClientHardwareAddress ), ( void * ) pxMACAddress, sizeof( xMACAddress_t ) ) == 0 )\r
+ {\r
+ /* None of the essential options have been processed yet. */\r
+ ulProcessed = 0;\r
+\r
+ /* Walk through the options until the dhcpOPTION_END_BYTE byte\r
+ is found, taking care not to walk off the end of the options. */\r
+ pucByte = &( pxDHCPMessage->ucFirstOptionByte );\r
+ pucLastByte = &( pucUDPPayload[ lBytes - dhcpMAX_OPTION_LENGTH_OF_INTEREST ] );\r
+ while( ( *pucByte != dhcpOPTION_END_BYTE ) && ( pucByte < pucLastByte ) )\r
+ {\r
+ ucOptionCode = *pucByte;\r
+ pucByte++;\r
+ ucLength = *pucByte;\r
+ pucByte++;\r
+\r
+ switch( ucOptionCode )\r
+ {\r
+ case dhcpMESSAGE_TYPE_OPTION_CODE :\r
+\r
+ if( *pucByte == ucExpectedMessageType )\r
+ {\r
+ /* The message type is the message type the\r
+ state machine is expecting. */\r
+ ulProcessed++;\r
+ }\r
+ else if( *pucByte == dhcpMESSAGE_TYPE_NACK )\r
+ {\r
+ if( ucExpectedMessageType == dhcpMESSAGE_TYPE_ACK )\r
+ {\r
+ /* Start again. */\r
+ eDHCPState = eWaitingSendFirstDiscover;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ /* Don't process other message types. */\r
+ }\r
+ break;\r
+\r
+ case dhcpSUBNET_MASK_OPTION_CODE :\r
+\r
+ if( ucLength == sizeof( uint32_t ) )\r
+ {\r
+ memcpy( ( void * ) &( pxNetworkAddressing->ulNetMask ), ( void * ) pucByte, ( size_t ) ucLength );\r
+ }\r
+ break;\r
+\r
+ case dhcpGATEWAY_OPTION_CODE :\r
+\r
+ if( ucLength == sizeof( uint32_t ) )\r
+ {\r
+ /* ulProcessed is not incremented in this case\r
+ because the gateway is not essential. */\r
+ memcpy( ( void * ) &( pxNetworkAddressing->ulGatewayAddress ), ( void * ) pucByte, ( size_t ) ucLength );\r
+ }\r
+ break;\r
+\r
+ case hdcpDNS_SERVER_OPTIONS_CODE :\r
+\r
+ /* ulProcessed is not incremented in this case\r
+ because the DNS server is not essential. Only the\r
+ first DNS server address is taken. */\r
+ memcpy( ( void * ) &( pxNetworkAddressing->ulDNSServerAddress ), ( void * ) pucByte, sizeof( uint32_t ) );\r
+ break;\r
+\r
+ case dhcpSERVER_IP_ADDRESS_OPTION_CODE :\r
+\r
+ if( ucLength == sizeof( uint32_t ) )\r
+ {\r
+ if( ucExpectedMessageType == dhcpMESSAGE_TYPE_OFFER )\r
+ {\r
+ /* Offers state the replying server. */\r
+ ulProcessed++;\r
+ memcpy( ( void * ) &ulDHCPServerAddress, ( void * ) pucByte, ( size_t ) ucLength );\r
+ }\r
+ else\r
+ {\r
+ /* The ack must come from the expected server. */\r
+ if( memcmp( ( void * ) &ulDHCPServerAddress, ( void * ) pucByte, ( size_t ) ucLength ) == 0 )\r
+ {\r
+ ulProcessed++;\r
+ }\r
+ }\r
+ }\r
+ break;\r
+\r
+ case dhcpLEASE_TIME_OPTION_CODE :\r
+\r
+ if( ucLength == sizeof( &ulLeaseTime ) )\r
+ {\r
+ /* ulProcessed is not incremented in this case\r
+ because the lease time is not essential. */\r
+ memcpy( ( void * ) &ulLeaseTime, ( void * ) pucByte, ( size_t ) ucLength );\r
+ ulLeaseTime = FreeRTOS_ntohl( ulLeaseTime );\r
+\r
+ /* Convert the lease time to milliseconds\r
+ (*1000) then ticks (/portTICK_RATE_MS). */\r
+ ulLeaseTime *= ( 1000UL / portTICK_RATE_MS );\r
+\r
+ /* Divide the lease time to ensure a renew \r
+ request is sent before the lease actually\r
+ expires. */\r
+ ulLeaseTime >>= 1UL;\r
+ }\r
+ break;\r
+\r
+ default :\r
+\r
+ /* Not interested in this field. */\r
+\r
+ break;\r
+ }\r
+\r
+ /* Jump over the data to find the next option code. */\r
+ if( ucLength == 0 )\r
+ {\r
+ break;\r
+ }\r
+ else\r
+ {\r
+ pucByte += ucLength;\r
+ }\r
+ }\r
+\r
+ /* Were all the mandatory options received? */\r
+ if( ulProcessed == ulMandatoryOptions )\r
+ {\r
+ ulOfferedIPAddress = pxDHCPMessage->ulYourIPAddress_yiaddr;\r
+ xReturn = pdPASS;\r
+ }\r
+ }\r
+ }\r
+\r
+ FreeRTOS_ReleaseUDPPayloadBuffer( ( void * ) pucUDPPayload );\r
+ }\r
+\r
+ return xReturn;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static uint8_t *prvCreatePartDHCPMessage( struct freertos_sockaddr *pxAddress, xMACAddress_t *pxMACAddress, uint8_t ucOpcode, const uint8_t * const pucOptionsArray, size_t xOptionsArraySize )\r
+{\r
+xDHCPMessage_t *pxDHCPMessage;\r
+const size_t xRequiredBufferSize = sizeof( xDHCPMessage_t ) + xOptionsArraySize;\r
+uint8_t *pucUDPPayloadBuffer;\r
+\r
+ /* Get a buffer. This uses a maximum delay, but the delay will be capped\r
+ to ipconfigMAX_SEND_BLOCK_TIME_TICKS so the return value still needs to be\r
+ test. */\r
+ do\r
+ {\r
+ }while( ( pucUDPPayloadBuffer = ( uint8_t * ) FreeRTOS_GetUDPPayloadBuffer( xRequiredBufferSize, portMAX_DELAY ) ) == NULL );\r
+\r
+ pxDHCPMessage = ( xDHCPMessage_t * ) pucUDPPayloadBuffer;\r
+\r
+ /* Most fields need to be zero. */\r
+ memset( ( void * ) pxDHCPMessage, 0x00, sizeof( xDHCPMessage_t ) );\r
+\r
+ /* Create the message. */\r
+ pxDHCPMessage->ucOpcode = ucOpcode;\r
+ pxDHCPMessage->ucAddressType = dhcpADDRESS_TYPE_ETHERNET;\r
+ pxDHCPMessage->ucAddressLength = dhcpETHERNET_ADDRESS_LENGTH;\r
+ pxDHCPMessage->ulTransactionID = ulTransactionId;\r
+ pxDHCPMessage->ulYourIPAddress_yiaddr = ulOfferedIPAddress;\r
+ pxDHCPMessage->ulDHCPCookie = dhcpCOOKIE;\r
+ memcpy( ( void * ) &( pxDHCPMessage->ucClientHardwareAddress[ 0 ] ), ( void * ) pxMACAddress, sizeof( xMACAddress_t ) );\r
+\r
+ /* Copy in the const part of the options options. */\r
+ memcpy( ( void * ) &( pucUDPPayloadBuffer[ dhcpFIRST_OPTION_BYTE_OFFSET ] ), ( void * ) pucOptionsArray, xOptionsArraySize );\r
+\r
+ /* Map in the client identifier. */\r
+ memcpy( ( void * ) &( pucUDPPayloadBuffer[ dhcpFIRST_OPTION_BYTE_OFFSET + dhcpCLIENT_IDENTIFIER_OFFSET ] ), ( void * ) pxMACAddress, sizeof( xMACAddress_t ) );\r
+\r
+ /* Set the addressing. */\r
+ pxAddress->sin_addr = ipBROADCAST_IP_ADDRESS;\r
+ pxAddress->sin_port = ( uint16_t ) dhcpSERVER_PORT;\r
+\r
+ return pucUDPPayloadBuffer;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvSendDHCPRequest( xMACAddress_t *pxMACAddress )\r
+{\r
+uint8_t *pucUDPPayloadBuffer;\r
+struct freertos_sockaddr xAddress;\r
+static const uint8_t ucDHCPRequestOptions[] =\r
+{\r
+ /* Do not change the ordering without also changing\r
+ dhcpCLIENT_IDENTIFIER_OFFSET, dhcpREQUESTED_IP_ADDRESS_OFFSET and\r
+ dhcpDHCP_SERVER_IP_ADDRESS_OFFSET. */\r
+ dhcpMESSAGE_TYPE_OPTION_CODE, 1, dhcpMESSAGE_TYPE_REQUEST, /* Message type option. */\r
+ dhcpCLIENT_IDENTIFIER_OPTION_CODE, 6, 0, 0, 0, 0, 0, 0, /* Client identifier. */\r
+ dhcpREQUEST_IP_ADDRESS_OPTION_CODE, 4, 0, 0, 0, 0, /* The IP address being requested. */\r
+ dhcpSERVER_IP_ADDRESS_OPTION_CODE, 4, 0, 0, 0, 0, /* The IP address of the DHCP server. */\r
+ dhcpOPTION_END_BYTE\r
+};\r
+\r
+ pucUDPPayloadBuffer = prvCreatePartDHCPMessage( &xAddress, pxMACAddress, dhcpREQUEST_OPCODE, ucDHCPRequestOptions, sizeof( ucDHCPRequestOptions ) );\r
+\r
+ /* Copy in the IP address being requested. */\r
+ memcpy( ( void * ) &( pucUDPPayloadBuffer[ dhcpFIRST_OPTION_BYTE_OFFSET + dhcpREQUESTED_IP_ADDRESS_OFFSET ] ), ( void * ) &ulOfferedIPAddress, sizeof( ulOfferedIPAddress ) );\r
+\r
+ /* Copy in the address of the DHCP server being used. */\r
+ memcpy( ( void * ) &( pucUDPPayloadBuffer[ dhcpFIRST_OPTION_BYTE_OFFSET + dhcpDHCP_SERVER_IP_ADDRESS_OFFSET ] ), ( void * ) &ulDHCPServerAddress, sizeof( ulDHCPServerAddress ) );\r
+\r
+ iptraceSENDING_DHCP_REQUEST();\r
+ if( FreeRTOS_sendto( xDHCPSocket, pucUDPPayloadBuffer, ( sizeof( xDHCPMessage_t ) + sizeof( ucDHCPRequestOptions ) ), FREERTOS_ZERO_COPY, &xAddress, sizeof( xAddress ) ) == 0 )\r
+ {\r
+ /* The packet was not successfully queued for sending and must be\r
+ returned to the stack. */\r
+ FreeRTOS_ReleaseUDPPayloadBuffer( pucUDPPayloadBuffer );\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+static void prvSendDHCPDiscover( xMACAddress_t *pxMACAddress )\r
+{\r
+uint8_t *pucUDPPayloadBuffer;\r
+struct freertos_sockaddr xAddress;\r
+static const uint8_t ucDHCPDiscoverOptions[] =\r
+{\r
+ /* Do not change the ordering without also changing dhcpCLIENT_IDENTIFIER_OFFSET. */\r
+ dhcpMESSAGE_TYPE_OPTION_CODE, 1, dhcpMESSAGE_TYPE_DISCOVER, /* Message type option. */\r
+ dhcpCLIENT_IDENTIFIER_OPTION_CODE, 6, 0, 0, 0, 0, 0, 0, /* Client identifier. */\r
+ dhcpPARAMETER_REQUEST_OPTION_CODE, 3, dhcpSUBNET_MASK_OPTION_CODE, dhcpGATEWAY_OPTION_CODE, hdcpDNS_SERVER_OPTIONS_CODE, /* Parameter request option. */\r
+ dhcpOPTION_END_BYTE\r
+};\r
+\r
+ pucUDPPayloadBuffer = prvCreatePartDHCPMessage( &xAddress, pxMACAddress, dhcpREQUEST_OPCODE, ucDHCPDiscoverOptions, sizeof( ucDHCPDiscoverOptions ) );\r
+\r
+ iptraceSENDING_DHCP_DISCOVER();\r
+ if( FreeRTOS_sendto( xDHCPSocket, pucUDPPayloadBuffer, ( sizeof( xDHCPMessage_t ) + sizeof( ucDHCPDiscoverOptions ) ), FREERTOS_ZERO_COPY, &xAddress, sizeof( xAddress ) ) == 0 )\r
+ {\r
+ /* The packet was not successfully queued for sending and must be\r
+ returned to the stack. */\r
+ FreeRTOS_ReleaseUDPPayloadBuffer( pucUDPPayloadBuffer );\r
+ }\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+#endif /* ipconfigUSE_DHCP != 0 */\r
+\r
+\r