]> git.sur5r.net Git - freertos/blobdiff - FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_DHCP.c
Update version number in readiness for V10.3.0 release. Sync SVN with reviewed releas...
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-TCP / FreeRTOS_DHCP.c
index 8871d6563990607693bcf2f52932f197ff4f7cdb..930768055483ea21405ab38afbca01fc6aab9168 100644 (file)
-/*\r
- * FreeRTOS+TCP V2.2.0\r
- * Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
- *\r
- * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
- * this software and associated documentation files (the "Software"), to deal in\r
- * the Software without restriction, including without limitation the rights to\r
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
- * the Software, and to permit persons to whom the Software is furnished to do so,\r
- * subject to the following conditions:\r
- *\r
- * The above copyright notice and this permission notice shall be included in all\r
- * copies or substantial portions of the Software.\r
- *\r
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
- *\r
- * http://aws.amazon.com/freertos\r
- * http://www.FreeRTOS.org\r
- */\r
-\r
-/* Standard includes. */\r
-#include <stdint.h>\r
-\r
-/* FreeRTOS includes. */\r
-#include "FreeRTOS.h"\r
-#include "task.h"\r
-#include "semphr.h"\r
-\r
-/* FreeRTOS+TCP includes. */\r
-#include "FreeRTOS_IP.h"\r
-#include "FreeRTOS_Sockets.h"\r
-#include "FreeRTOS_IP_Private.h"\r
-#include "FreeRTOS_UDP_IP.h"\r
-#include "FreeRTOS_TCP_IP.h"\r
-#include "FreeRTOS_DHCP.h"\r
-#include "FreeRTOS_ARP.h"\r
-#include "NetworkInterface.h"\r
-#include "NetworkBufferManagement.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 < 586u )\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\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 */\r
-#ifndef dhcpINITIAL_DHCP_TX_PERIOD\r
-       #define dhcpINITIAL_TIMER_PERIOD                        ( pdMS_TO_TICKS( 250 ) )\r
-       #define dhcpINITIAL_DHCP_TX_PERIOD                      ( pdMS_TO_TICKS( 5000 ) )\r
-#endif\r
-\r
-/* Codes of interest found in the DHCP options field. */\r
-#define dhcpZERO_PAD_OPTION_CODE                               ( 0u )\r
-#define dhcpSUBNET_MASK_OPTION_CODE                            ( 1u )\r
-#define dhcpGATEWAY_OPTION_CODE                                        ( 3u )\r
-#define dhcpDNS_SERVER_OPTIONS_CODE                            ( 6u )\r
-#define dhcpDNS_HOSTNAME_OPTIONS_CODE                  ( 12u )\r
-#define dhcpREQUEST_IP_ADDRESS_OPTION_CODE             ( 50u )\r
-#define dhcpLEASE_TIME_OPTION_CODE                             ( 51u )\r
-#define dhcpMESSAGE_TYPE_OPTION_CODE                   ( 53u )\r
-#define dhcpSERVER_IP_ADDRESS_OPTION_CODE              ( 54u )\r
-#define dhcpPARAMETER_REQUEST_OPTION_CODE              ( 55u )\r
-#define dhcpCLIENT_IDENTIFIER_OPTION_CODE              ( 61u )\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
-/* 48 hours in ticks.  Can not use pdMS_TO_TICKS() as integer overflow can occur. */\r
-#define dhcpDEFAULT_LEASE_TIME                                 ( ( 48UL * 60UL * 60UL ) * configTICK_RATE_HZ )\r
-\r
-/* Don't allow the lease time to be too short. */\r
-#define dhcpMINIMUM_LEASE_TIME                                 ( pdMS_TO_TICKS( 60000UL ) )    /* 60 seconds in ticks. */\r
-\r
-/* Marks the end of the variable length options field in the DHCP packet. */\r
-#define dhcpOPTION_END_BYTE 0xffu\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
-/* Standard DHCP port numbers and magic cookie value. */\r
-#if( ipconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN )\r
-       #define dhcpCLIENT_PORT 0x4400u\r
-       #define dhcpSERVER_PORT 0x4300u\r
-       #define dhcpCOOKIE              0x63538263ul\r
-       #define dhcpBROADCAST   0x0080u\r
-#else\r
-       #define dhcpCLIENT_PORT 0x0044u\r
-       #define dhcpSERVER_PORT 0x0043u\r
-       #define dhcpCOOKIE              0x63825363ul\r
-       #define dhcpBROADCAST   0x8000u\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 DHCPMessage_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
-       #if( ipconfigDHCP_FALL_BACK_AUTO_IP != 0 )\r
-               eGetLinkLayerAddress,           /* When DHCP didn't respond, try to obtain a LinkLayer address 168.254.x.x. */\r
-       #endif\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
-/* Hold information in between steps in the DHCP state machine. */\r
-struct xDHCP_DATA\r
-{\r
-       uint32_t ulTransactionId;\r
-       uint32_t ulOfferedIPAddress;\r
-       uint32_t ulDHCPServerAddress;\r
-       uint32_t ulLeaseTime;\r
-       /* Hold information on the current timer state. */\r
-       TickType_t xDHCPTxTime;\r
-       TickType_t xDHCPTxPeriod;\r
-       /* Try both without and with the broadcast flag */\r
-       BaseType_t xUseBroadcast;\r
-       /* Maintains the DHCP state machine state. */\r
-       eDHCPState_t eDHCPState;\r
-       /* The UDP socket used for all incoming and outgoing DHCP traffic. */\r
-       Socket_t xDHCPSocket;\r
-};\r
-\r
-typedef struct xDHCP_DATA DHCPData_t;\r
-\r
-#if( ipconfigDHCP_FALL_BACK_AUTO_IP != 0 )\r
-       /* Define the Link Layer IP address: 169.254.x.x */\r
-       #define LINK_LAYER_ADDRESS_0    169\r
-       #define LINK_LAYER_ADDRESS_1    254\r
-\r
-       /* Define the netmask used: 255.255.0.0 */\r
-       #define LINK_LAYER_NETMASK_0    255\r
-       #define LINK_LAYER_NETMASK_1    255\r
-       #define LINK_LAYER_NETMASK_2    0\r
-       #define LINK_LAYER_NETMASK_3    0\r
-#endif\r
-\r
-\r
-/*\r
- * Generate a DHCP discover message and send it on the DHCP socket.\r
- */\r
-static void prvSendDHCPDiscover( void );\r
-\r
-/*\r
- * Interpret message received on the DHCP socket.\r
- */\r
-static BaseType_t prvProcessDHCPReplies( BaseType_t xExpectedMessageType );\r
-\r
-/*\r
- * Generate a DHCP request packet, and send it on the DHCP socket.\r
- */\r
-static void prvSendDHCPRequest( void );\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, BaseType_t xOpcode, const uint8_t * const pucOptionsArray, size_t *pxOptionsArraySize );\r
-\r
-/*\r
- * Create the DHCP socket, if it has not been created already.\r
- */\r
-static void prvCreateDHCPSocket( void );\r
-\r
-/*\r
- * After DHCP has failed to answer, prepare everything to start searching\r
- * for (trying-out) LinkLayer IP-addresses, using the random method: Send\r
- * a gratuitous ARP request and wait if another device responds to it.\r
- */\r
-#if( ipconfigDHCP_FALL_BACK_AUTO_IP != 0 )\r
-       static void prvPrepareLinkLayerIPLookUp( void );\r
-#endif\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-/* The next DHCP transaction Id to be used. */\r
-static DHCPData_t xDHCPData;\r
-\r
-/*-----------------------------------------------------------*/\r
-\r
-BaseType_t xIsDHCPSocket( Socket_t xSocket )\r
-{\r
-BaseType_t xReturn;\r
-\r
-       if( xDHCPData.xDHCPSocket == xSocket )\r
-       {\r
-               xReturn = pdTRUE;\r
-       }\r
-       else\r
-       {\r
-               xReturn = pdFALSE;\r
-       }\r
-\r
-       return xReturn;\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-void vDHCPProcess( BaseType_t xReset )\r
-{\r
-BaseType_t xGivingUp = pdFALSE;\r
-#if( ipconfigUSE_DHCP_HOOK != 0 )\r
-       eDHCPCallbackAnswer_t eAnswer;\r
-#endif /* ipconfigUSE_DHCP_HOOK */\r
-\r
-       /* Is DHCP starting over? */\r
-       if( xReset != pdFALSE )\r
-       {\r
-               xDHCPData.eDHCPState = eWaitingSendFirstDiscover;\r
-       }\r
-\r
-       switch( xDHCPData.eDHCPState )\r
-       {\r
-               case eWaitingSendFirstDiscover :\r
-                       /* Ask the user if a DHCP discovery is required. */\r
-               #if( ipconfigUSE_DHCP_HOOK != 0 )\r
-                       eAnswer = xApplicationDHCPHook( eDHCPPhasePreDiscover, xNetworkAddressing.ulDefaultIPAddress );\r
-                       if( eAnswer == eDHCPContinue )\r
-               #endif  /* ipconfigUSE_DHCP_HOOK */\r
-                       {\r
-                               /* Initial state.  Create the DHCP socket, timer, etc. if they\r
-                               have not already been created. */\r
-                               prvInitialiseDHCP();\r
-\r
-                               /* See if prvInitialiseDHCP() has creates a socket. */\r
-                               if( xDHCPData.xDHCPSocket == NULL )\r
-                               {\r
-                                       xGivingUp = pdTRUE;\r
-                                       break;\r
-                               }\r
-\r
-                               *ipLOCAL_IP_ADDRESS_POINTER = 0UL;\r
-\r
-                               /* Send the first discover request. */\r
-                               if( xDHCPData.xDHCPSocket != NULL )\r
-                               {\r
-                                       xDHCPData.xDHCPTxTime = xTaskGetTickCount();\r
-                                       prvSendDHCPDiscover( );\r
-                                       xDHCPData.eDHCPState = eWaitingOffer;\r
-                               }\r
-                       }\r
-               #if( ipconfigUSE_DHCP_HOOK != 0 )\r
-                       else\r
-                       {\r
-                               if( eAnswer == eDHCPUseDefaults )\r
-                               {\r
-                                       memcpy( &xNetworkAddressing, &xDefaultAddressing, sizeof( xNetworkAddressing ) );\r
-                               }\r
-\r
-                               /* The user indicates that the DHCP process does not continue. */\r
-                               xGivingUp = pdTRUE;\r
-                       }\r
-               #endif  /* ipconfigUSE_DHCP_HOOK */\r
-                       break;\r
-\r
-               case eWaitingOffer :\r
-\r
-                       xGivingUp = pdFALSE;\r
-\r
-                       /* Look for offers coming in. */\r
-                       if( prvProcessDHCPReplies( dhcpMESSAGE_TYPE_OFFER ) == pdPASS )\r
-                       {\r
-                       #if( ipconfigUSE_DHCP_HOOK != 0 )\r
-                               /* Ask the user if a DHCP request is required. */\r
-                               eAnswer = xApplicationDHCPHook( eDHCPPhasePreRequest, xDHCPData.ulOfferedIPAddress );\r
-\r
-                               if( eAnswer == eDHCPContinue )\r
-                       #endif  /* ipconfigUSE_DHCP_HOOK */\r
-                               {\r
-                                       /* An offer has been made, the user wants to continue,\r
-                                       generate the request. */\r
-                                       xDHCPData.xDHCPTxTime = xTaskGetTickCount();\r
-                                       xDHCPData.xDHCPTxPeriod = dhcpINITIAL_DHCP_TX_PERIOD;\r
-                                       prvSendDHCPRequest( );\r
-                                       xDHCPData.eDHCPState = eWaitingAcknowledge;\r
-                                       break;\r
-                               }\r
-\r
-                       #if( ipconfigUSE_DHCP_HOOK != 0 )\r
-                               if( eAnswer == eDHCPUseDefaults )\r
-                               {\r
-                                       memcpy( &xNetworkAddressing, &xDefaultAddressing, sizeof( xNetworkAddressing ) );\r
-                               }\r
-\r
-                               /* The user indicates that the DHCP process does not continue. */\r
-                               xGivingUp = pdTRUE;\r
-                       #endif  /* ipconfigUSE_DHCP_HOOK */\r
-                       }\r
-                       else if( ( xTaskGetTickCount() - xDHCPData.xDHCPTxTime ) > xDHCPData.xDHCPTxPeriod )\r
-                       {\r
-                               /* It is time to send another Discover.  Increase the time\r
-                               period, and if it has not got to the point of giving up - send\r
-                               another discovery. */\r
-                               xDHCPData.xDHCPTxPeriod <<= 1;\r
-\r
-                               if( xDHCPData.xDHCPTxPeriod <= ipconfigMAXIMUM_DISCOVER_TX_PERIOD )\r
-                               {\r
-                                       if( xApplicationGetRandomNumber( &( xDHCPData.ulTransactionId ) ) != pdFALSE )\r
-                                       {\r
-                                               xDHCPData.xDHCPTxTime = xTaskGetTickCount( );\r
-                                               xDHCPData.xUseBroadcast = !xDHCPData.xUseBroadcast;\r
-                                               prvSendDHCPDiscover( );\r
-                                               FreeRTOS_debug_printf( ( "vDHCPProcess: timeout %lu ticks\n", xDHCPData.xDHCPTxPeriod ) );\r
-                                       }\r
-                                       else\r
-                                       {\r
-                                               FreeRTOS_debug_printf( ( "vDHCPProcess: failed to generate a random Transaction ID\n" ) );\r
-                                       }\r
-                               }\r
-                               else\r
-                               {\r
-                                       FreeRTOS_debug_printf( ( "vDHCPProcess: giving up %lu > %lu ticks\n", xDHCPData.xDHCPTxPeriod, ipconfigMAXIMUM_DISCOVER_TX_PERIOD ) );\r
-\r
-                                       #if( ipconfigDHCP_FALL_BACK_AUTO_IP != 0 )\r
-                                       {\r
-                                               /* Only use a fake Ack if the default IP address == 0x00\r
-                                               and the link local addressing is used.  Start searching\r
-                                               a free LinkLayer IP-address.  Next state will be\r
-                                               'eGetLinkLayerAddress'. */\r
-                                               prvPrepareLinkLayerIPLookUp();\r
-\r
-                                               /* Setting an IP address manually so set to not using\r
-                                               leased address mode. */\r
-                                               xDHCPData.eDHCPState = eGetLinkLayerAddress;\r
-                                       }\r
-                                       #else\r
-                                       {\r
-                                               xGivingUp = pdTRUE;\r
-                                       }\r
-                                       #endif /* ipconfigDHCP_FALL_BACK_AUTO_IP */\r
-                               }\r
-                       }\r
-                       break;\r
-\r
-               case eWaitingAcknowledge :\r
-\r
-                       /* Look for acks coming in. */\r
-                       if( prvProcessDHCPReplies( dhcpMESSAGE_TYPE_ACK ) == pdPASS )\r
-                       {\r
-                               FreeRTOS_debug_printf( ( "vDHCPProcess: acked %lxip\n", FreeRTOS_ntohl( xDHCPData.ulOfferedIPAddress ) ) );\r
-\r
-                               /* DHCP completed.  The IP address can now be used, and the\r
-                               timer set to the lease timeout time. */\r
-                               *ipLOCAL_IP_ADDRESS_POINTER = xDHCPData.ulOfferedIPAddress;\r
-\r
-                               /* Setting the 'local' broadcast address, something like\r
-                               '192.168.1.255'. */\r
-                               xNetworkAddressing.ulBroadcastAddress = ( xDHCPData.ulOfferedIPAddress & xNetworkAddressing.ulNetMask ) |  ~xNetworkAddressing.ulNetMask;\r
-                               xDHCPData.eDHCPState = eLeasedAddress;\r
-\r
-                               iptraceDHCP_SUCCEDEED( xDHCPData.ulOfferedIPAddress );\r
-\r
-                               /* DHCP failed, the default configured IP-address will be used\r
-                               Now call vIPNetworkUpCalls() to send the network-up event and\r
-                               start the ARP timer. */\r
-                               vIPNetworkUpCalls( );\r
-\r
-                               /* Close socket to ensure packets don't queue on it. */\r
-                               vSocketClose( xDHCPData.xDHCPSocket );\r
-                               xDHCPData.xDHCPSocket = NULL;\r
-\r
-                               if( xDHCPData.ulLeaseTime == 0UL )\r
-                               {\r
-                                       xDHCPData.ulLeaseTime = dhcpDEFAULT_LEASE_TIME;\r
-                               }\r
-                               else if( xDHCPData.ulLeaseTime < dhcpMINIMUM_LEASE_TIME )\r
-                               {\r
-                                       xDHCPData.ulLeaseTime = dhcpMINIMUM_LEASE_TIME;\r
-                               }\r
-                               else\r
-                               {\r
-                                       /* The lease time is already valid. */\r
-                               }\r
-\r
-                               /* Check for clashes. */\r
-                               vARPSendGratuitous();\r
-                               vIPReloadDHCPTimer( xDHCPData.ulLeaseTime );\r
-                       }\r
-                       else\r
-                       {\r
-                               /* Is it time to send another Discover? */\r
-                               if( ( xTaskGetTickCount() - xDHCPData.xDHCPTxTime ) > xDHCPData.xDHCPTxPeriod )\r
-                               {\r
-                                       /* Increase the time period, and if it has not got to the\r
-                                       point of giving up - send another request. */\r
-                                       xDHCPData.xDHCPTxPeriod <<= 1;\r
-\r
-                                       if( xDHCPData.xDHCPTxPeriod <= ipconfigMAXIMUM_DISCOVER_TX_PERIOD )\r
-                                       {\r
-                                               xDHCPData.xDHCPTxTime = xTaskGetTickCount();\r
-                                               prvSendDHCPRequest( );\r
-                                       }\r
-                                       else\r
-                                       {\r
-                                               /* Give up, start again. */\r
-                                               xDHCPData.eDHCPState = eWaitingSendFirstDiscover;\r
-                                       }\r
-                               }\r
-                       }\r
-                       break;\r
-\r
-       #if( ipconfigDHCP_FALL_BACK_AUTO_IP != 0 )\r
-               case eGetLinkLayerAddress:\r
-                       if( ( xTaskGetTickCount() - xDHCPData.xDHCPTxTime ) > xDHCPData.xDHCPTxPeriod )\r
-                       {\r
-                               if( xARPHadIPClash == pdFALSE )\r
-                               {\r
-                                       /* ARP OK. proceed. */\r
-                                       iptraceDHCP_SUCCEDEED( xDHCPData.ulOfferedIPAddress );\r
-\r
-                                       /* Auto-IP succeeded, the default configured IP-address will\r
-                                       be used.  Now call vIPNetworkUpCalls() to send the\r
-                                       network-up event and start the ARP timer. */\r
-                                       vIPNetworkUpCalls( );\r
-                                       xDHCPData.eDHCPState = eNotUsingLeasedAddress;\r
-                               }\r
-                               else\r
-                               {\r
-                                       /* ARP clashed - try another IP address. */\r
-                                       prvPrepareLinkLayerIPLookUp();\r
-\r
-                                       /* Setting an IP address manually so set to not using leased\r
-                                       address mode. */\r
-                                       xDHCPData.eDHCPState = eGetLinkLayerAddress;\r
-                               }\r
-                       }\r
-                       break;\r
-       #endif  /* ipconfigDHCP_FALL_BACK_AUTO_IP */\r
-\r
-               case eLeasedAddress :\r
-\r
-                       /* Resend the request at the appropriate time to renew the lease. */\r
-                       prvCreateDHCPSocket();\r
-\r
-                       if( xDHCPData.xDHCPSocket != NULL )\r
-                       {\r
-                               xDHCPData.xDHCPTxTime = xTaskGetTickCount();\r
-                               xDHCPData.xDHCPTxPeriod = dhcpINITIAL_DHCP_TX_PERIOD;\r
-                               prvSendDHCPRequest( );\r
-                               xDHCPData.eDHCPState = eWaitingAcknowledge;\r
-\r
-                               /* From now on, we should be called more often */\r
-                               vIPReloadDHCPTimer( dhcpINITIAL_TIMER_PERIOD );\r
-                       }\r
-                       break;\r
-\r
-               case eNotUsingLeasedAddress:\r
-\r
-                       vIPSetDHCPTimerEnableState( pdFALSE );\r
-                       break;\r
-\r
-               default:\r
-                       break;\r
-       }\r
-\r
-       if( xGivingUp != pdFALSE )\r
-       {\r
-               /* xGivingUp became true either because of a time-out, or because\r
-               xApplicationDHCPHook() returned another value than 'eDHCPContinue',\r
-               meaning that the conversion is canceled from here. */\r
-\r
-               /* Revert to static IP address. */\r
-               taskENTER_CRITICAL();\r
-               {\r
-                       *ipLOCAL_IP_ADDRESS_POINTER = xNetworkAddressing.ulDefaultIPAddress;\r
-                       iptraceDHCP_REQUESTS_FAILED_USING_DEFAULT_IP_ADDRESS( xNetworkAddressing.ulDefaultIPAddress );\r
-               }\r
-               taskEXIT_CRITICAL();\r
-\r
-               xDHCPData.eDHCPState = eNotUsingLeasedAddress;\r
-               vIPSetDHCPTimerEnableState( pdFALSE );\r
-\r
-               /* DHCP failed, the default configured IP-address will be used.  Now\r
-               call vIPNetworkUpCalls() to send the network-up event and start the ARP\r
-               timer. */\r
-               vIPNetworkUpCalls( );\r
-\r
-               /* Test if socket was indeed created. */\r
-               if( xDHCPData.xDHCPSocket != NULL )\r
-               {\r
-                       /* Close socket to ensure packets don't queue on it. */\r
-                       vSocketClose( xDHCPData.xDHCPSocket );\r
-                       xDHCPData.xDHCPSocket = NULL;\r
-               }\r
-       }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvCreateDHCPSocket( void )\r
-{\r
-struct freertos_sockaddr xAddress;\r
-BaseType_t xReturn;\r
-TickType_t xTimeoutTime = ( TickType_t ) 0;\r
-\r
-       /* Create the socket, if it has not already been created. */\r
-       if( xDHCPData.xDHCPSocket == NULL )\r
-       {\r
-               xDHCPData.xDHCPSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP );\r
-               if( xDHCPData.xDHCPSocket != FREERTOS_INVALID_SOCKET )\r
-               {\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( xDHCPData.xDHCPSocket, 0, FREERTOS_SO_RCVTIMEO, ( void * ) &xTimeoutTime, sizeof( TickType_t ) );\r
-                       FreeRTOS_setsockopt( xDHCPData.xDHCPSocket, 0, FREERTOS_SO_SNDTIMEO, ( void * ) &xTimeoutTime, sizeof( TickType_t ) );\r
-\r
-                       /* Bind to the standard DHCP client port. */\r
-                       xAddress.sin_port = ( uint16_t ) dhcpCLIENT_PORT;\r
-                       xReturn = vSocketBind( xDHCPData.xDHCPSocket, &xAddress, sizeof( xAddress ), pdFALSE );\r
-                       if( xReturn != 0 )\r
-                       {\r
-                               /* Binding failed, close the socket again. */\r
-                               vSocketClose( xDHCPData.xDHCPSocket );\r
-                               xDHCPData.xDHCPSocket = NULL;\r
-                       }\r
-               }\r
-               else\r
-               {\r
-                       /* Change to NULL for easier testing. */\r
-                       xDHCPData.xDHCPSocket = NULL;\r
-               }\r
-       }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static void prvInitialiseDHCP( void )\r
-{\r
-       /* Initialise the parameters that will be set by the DHCP process. Per\r
-       https://www.ietf.org/rfc/rfc2131.txt, Transaction ID should be a random\r
-       value chosen by the client. */\r
-\r
-       /* Check for random number generator API failure. */\r
-       if( xApplicationGetRandomNumber( &( xDHCPData.ulTransactionId ) ) != pdFALSE )\r
-       {\r
-               xDHCPData.xUseBroadcast = 0;\r
-               xDHCPData.ulOfferedIPAddress = 0UL;\r
-               xDHCPData.ulDHCPServerAddress = 0UL;\r
-               xDHCPData.xDHCPTxPeriod = dhcpINITIAL_DHCP_TX_PERIOD;\r
-\r
-               /* Create the DHCP socket if it has not already been created. */\r
-               prvCreateDHCPSocket();\r
-               FreeRTOS_debug_printf( ( "prvInitialiseDHCP: start after %lu ticks\n", dhcpINITIAL_TIMER_PERIOD ) );\r
-               vIPReloadDHCPTimer( dhcpINITIAL_TIMER_PERIOD );\r
-       }\r
-       else\r
-       {\r
-               /* There was a problem with the randomiser. */\r
-       }\r
-}\r
-/*-----------------------------------------------------------*/\r
-\r
-static BaseType_t prvProcessDHCPReplies( BaseType_t xExpectedMessageType )\r
-{\r
-uint8_t *pucUDPPayload, *pucLastByte;\r
-struct freertos_sockaddr xClient;\r
-uint32_t xClientLength = sizeof( xClient );\r
-int32_t lBytes;\r
-DHCPMessage_t *pxDHCPMessage;\r
-uint8_t *pucByte, ucOptionCode, ucLength;\r
-uint32_t ulProcessed, ulParameter;\r
-BaseType_t xReturn = pdFALSE;\r
-const uint32_t ulMandatoryOptions = 2ul; /* DHCP server address, and the correct DHCP message type must be present in the options. */\r
-\r
-       lBytes = FreeRTOS_recvfrom( xDHCPData.xDHCPSocket, ( void * ) &pucUDPPayload, 0ul, FREERTOS_ZERO_COPY, &xClient, &xClientLength );\r
-\r
-       if( lBytes > 0 )\r
-       {\r
-               /* Map a DHCP structure onto the received data. */\r
-               pxDHCPMessage = ( DHCPMessage_t * ) ( pucUDPPayload );\r
-\r
-               /* Sanity check. */\r
-               if( ( lBytes >= sizeof( DHCPMessage_t ) ) &&\r
-                       ( pxDHCPMessage->ulDHCPCookie == ( uint32_t ) dhcpCOOKIE ) &&\r
-                       ( pxDHCPMessage->ucOpcode == ( uint8_t ) dhcpREPLY_OPCODE ) &&\r
-                       ( pxDHCPMessage->ulTransactionID == FreeRTOS_htonl( xDHCPData.ulTransactionId ) ) )\r
-               {\r
-                       if( memcmp( ( void * ) &( pxDHCPMessage->ucClientHardwareAddress ),\r
-                                               ( void * ) ipLOCAL_MAC_ADDRESS,\r
-                                               sizeof( MACAddress_t ) ) == 0 )\r
-                       {\r
-                               /* None of the essential options have been processed yet. */\r
-                               ulProcessed = 0ul;\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
-                /* Maintain a pointer to the last valid byte (i.e. not the first\r
-                invalid byte). */\r
-                               pucLastByte = pucUDPPayload + lBytes - 1;\r
-\r
-                               while( pucByte <= pucLastByte )\r
-                               {\r
-                                       ucOptionCode = pucByte[ 0 ];\r
-                                       if( ucOptionCode == dhcpOPTION_END_BYTE )\r
-                                       {\r
-                                               /* Ready, the last byte has been seen. */\r
-                                               break;\r
-                                       }\r
-                                       if( ucOptionCode == dhcpZERO_PAD_OPTION_CODE )\r
-                                       {\r
-                                               /* The value zero is used as a pad byte,\r
-                                               it is not followed by a length byte. */\r
-                                               pucByte += 1;\r
-                                               continue;\r
-                                       }\r
-\r
-                                       /* Stop if the response is malformed. */\r
-                                       if( pucByte < pucLastByte )\r
-                                       {\r
-                        /* There are at least two bytes left. */\r
-                                               ucLength = pucByte[ 1 ];\r
-                                               pucByte += 2;\r
-\r
-                                               if( pucByte + ucLength > pucLastByte )\r
-                                               {\r
-                                                       break;\r
-                                               }\r
-                                       }\r
-                                       else\r
-                                       {\r
-                                               break;\r
-                                       }\r
-\r
-                                       /* In most cases, a 4-byte network-endian parameter follows,\r
-                                       just get it once here and use later. */\r
-                                       if( ucLength >= sizeof( ulParameter ) )\r
-                                       {\r
-                                               memcpy( ( void * ) &( ulParameter ),\r
-                                                               ( void * ) pucByte,\r
-                                                               ( size_t ) sizeof( ulParameter ) );\r
-                                       }\r
-                                       else\r
-                                       {\r
-                                               ulParameter = 0;\r
-                                       }\r
-\r
-                                       /* Option-specific handling. */\r
-                                       switch( ucOptionCode )\r
-                                       {\r
-                                               case dhcpMESSAGE_TYPE_OPTION_CODE       :\r
-\r
-                                                       if( *pucByte == ( uint8_t ) xExpectedMessageType )\r
-                                                       {\r
-                                                               /* The message type is the message type the\r
-                                                               state machine is expecting. */\r
-                                                               ulProcessed++;\r
-                                                       }\r
-                                                       else if( *pucByte == ( uint8_t ) dhcpMESSAGE_TYPE_NACK )\r
-                                                       {\r
-                                                               if( xExpectedMessageType == ( BaseType_t ) dhcpMESSAGE_TYPE_ACK )\r
-                                                               {\r
-                                                                       /* Start again. */\r
-                                                                       xDHCPData.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
-                                                               xNetworkAddressing.ulNetMask = ulParameter;\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
-                                                               xNetworkAddressing.ulGatewayAddress = ulParameter;\r
-                                                       }\r
-                                                       break;\r
-\r
-                                               case dhcpDNS_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
-                                                       xNetworkAddressing.ulDNSServerAddress = ulParameter;\r
-                                                       break;\r
-\r
-                                               case dhcpSERVER_IP_ADDRESS_OPTION_CODE :\r
-\r
-                                                       if( ucLength == sizeof( uint32_t ) )\r
-                                                       {\r
-                                                               if( xExpectedMessageType == ( BaseType_t ) dhcpMESSAGE_TYPE_OFFER )\r
-                                                               {\r
-                                                                       /* Offers state the replying server. */\r
-                                                                       ulProcessed++;\r
-                                                                       xDHCPData.ulDHCPServerAddress = ulParameter;\r
-                                                               }\r
-                                                               else\r
-                                                               {\r
-                                                                       /* The ack must come from the expected server. */\r
-                                                                       if( xDHCPData.ulDHCPServerAddress == ulParameter )\r
-                                                                       {\r
-                                                                               ulProcessed++;\r
-                                                                       }\r
-                                                               }\r
-                                                       }\r
-                                                       break;\r
-\r
-                                               case dhcpLEASE_TIME_OPTION_CODE :\r
-\r
-                                                       if( ucLength == sizeof( xDHCPData.ulLeaseTime ) )\r
-                                                       {\r
-                                                               /* ulProcessed is not incremented in this case\r
-                                                               because the lease time is not essential. */\r
-                                                               /* The DHCP parameter is in seconds, convert\r
-                                                               to host-endian format. */\r
-                                                               xDHCPData.ulLeaseTime = FreeRTOS_ntohl( ulParameter );\r
-\r
-                                                               /* Divide the lease time by two to ensure a\r
-                                                               renew request is sent before the lease actually\r
-                                                               expires. */\r
-                                                               xDHCPData.ulLeaseTime >>= 1UL;\r
-\r
-                                                               /* Multiply with configTICK_RATE_HZ to get clock\r
-                                                               ticks. */\r
-                                                               xDHCPData.ulLeaseTime = configTICK_RATE_HZ * xDHCPData.ulLeaseTime;\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 == 0u )\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
-                                       /* HT:endian: used to be network order */\r
-                                       xDHCPData.ulOfferedIPAddress = pxDHCPMessage->ulYourIPAddress_yiaddr;\r
-                                       FreeRTOS_printf( ( "vDHCPProcess: offer %lxip\n", FreeRTOS_ntohl( xDHCPData.ulOfferedIPAddress ) ) );\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, BaseType_t xOpcode, const uint8_t * const pucOptionsArray, size_t *pxOptionsArraySize )\r
-{\r
-DHCPMessage_t *pxDHCPMessage;\r
-size_t xRequiredBufferSize = sizeof( DHCPMessage_t ) + *pxOptionsArraySize;\r
-uint8_t *pucUDPPayloadBuffer;\r
-\r
-#if( ipconfigDHCP_REGISTER_HOSTNAME == 1 )\r
-       const char *pucHostName = pcApplicationHostnameHook ();\r
-       size_t xNameLength = strlen( pucHostName );\r
-       uint8_t *pucPtr;\r
-\r
-       xRequiredBufferSize += ( 2 + xNameLength );\r
-#endif\r
-\r
-       /* Get a buffer.  This uses a maximum delay, but the delay will be capped\r
-       to ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS so the return value still needs to\r
-       be test. */\r
-       do\r
-       {\r
-       } while( ( pucUDPPayloadBuffer = ( uint8_t * ) FreeRTOS_GetUDPPayloadBuffer( xRequiredBufferSize, portMAX_DELAY ) ) == NULL );\r
-\r
-       pxDHCPMessage = ( DHCPMessage_t * ) pucUDPPayloadBuffer;\r
-\r
-       /* Most fields need to be zero. */\r
-       memset( ( void * ) pxDHCPMessage, 0x00, sizeof( DHCPMessage_t ) );\r
-\r
-       /* Create the message. */\r
-       pxDHCPMessage->ucOpcode = ( uint8_t ) xOpcode;\r
-       pxDHCPMessage->ucAddressType = ( uint8_t ) dhcpADDRESS_TYPE_ETHERNET;\r
-       pxDHCPMessage->ucAddressLength = ( uint8_t ) dhcpETHERNET_ADDRESS_LENGTH;\r
-       pxDHCPMessage->ulTransactionID = FreeRTOS_htonl( xDHCPData.ulTransactionId );\r
-       pxDHCPMessage->ulDHCPCookie = ( uint32_t ) dhcpCOOKIE;\r
-       if( xDHCPData.xUseBroadcast != pdFALSE )\r
-       {\r
-               pxDHCPMessage->usFlags = ( uint16_t ) dhcpBROADCAST;\r
-       }\r
-       else\r
-       {\r
-               pxDHCPMessage->usFlags = 0u;\r
-       }\r
-\r
-       memcpy( ( void * ) &( pxDHCPMessage->ucClientHardwareAddress[ 0 ] ), ( void * ) ipLOCAL_MAC_ADDRESS, sizeof( MACAddress_t ) );\r
-\r
-       /* Copy in the const part of the options options. */\r
-       memcpy( ( void * ) &( pucUDPPayloadBuffer[ dhcpFIRST_OPTION_BYTE_OFFSET ] ), ( void * ) pucOptionsArray, *pxOptionsArraySize );\r
-\r
-       #if( ipconfigDHCP_REGISTER_HOSTNAME == 1 )\r
-       {\r
-               /* With this option, the hostname can be registered as well which makes\r
-               it easier to lookup a device in a router's list of DHCP clients. */\r
-\r
-               /* Point to where the OPTION_END was stored to add data. */\r
-               pucPtr = &( pucUDPPayloadBuffer[ dhcpFIRST_OPTION_BYTE_OFFSET + ( *pxOptionsArraySize - 1 ) ] );\r
-               pucPtr[ 0 ] = dhcpDNS_HOSTNAME_OPTIONS_CODE;\r
-               pucPtr[ 1 ] = ( uint8_t ) xNameLength;\r
-               memcpy( ( void *) ( pucPtr + 2 ), pucHostName, xNameLength );\r
-               pucPtr[ 2 + xNameLength ] = dhcpOPTION_END_BYTE;\r
-               *pxOptionsArraySize += ( 2 + xNameLength );\r
-       }\r
-       #endif\r
-\r
-       /* Map in the client identifier. */\r
-       memcpy( ( void * ) &( pucUDPPayloadBuffer[ dhcpFIRST_OPTION_BYTE_OFFSET + dhcpCLIENT_IDENTIFIER_OFFSET ] ),\r
-               ( void * ) ipLOCAL_MAC_ADDRESS, sizeof( MACAddress_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( void )\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
-size_t xOptionsLength = sizeof( ucDHCPRequestOptions );\r
-\r
-       pucUDPPayloadBuffer = prvCreatePartDHCPMessage( &xAddress, dhcpREQUEST_OPCODE, ucDHCPRequestOptions, &xOptionsLength );\r
-\r
-       /* Copy in the IP address being requested. */\r
-       memcpy( ( void * ) &( pucUDPPayloadBuffer[ dhcpFIRST_OPTION_BYTE_OFFSET + dhcpREQUESTED_IP_ADDRESS_OFFSET ] ),\r
-               ( void * ) &( xDHCPData.ulOfferedIPAddress ), sizeof( xDHCPData.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 ] ),\r
-               ( void * ) &( xDHCPData.ulDHCPServerAddress ), sizeof( xDHCPData.ulDHCPServerAddress ) );\r
-\r
-       FreeRTOS_debug_printf( ( "vDHCPProcess: reply %lxip\n", FreeRTOS_ntohl( xDHCPData.ulOfferedIPAddress ) ) );\r
-       iptraceSENDING_DHCP_REQUEST();\r
-\r
-       /* 'ucFirstOptionByte' is part of DHCP message struct, so subtract one byte. */\r
-       if( FreeRTOS_sendto( xDHCPData.xDHCPSocket, pucUDPPayloadBuffer, ( sizeof( DHCPMessage_t ) + xOptionsLength - 1 ), 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( void )\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, dhcpDNS_SERVER_OPTIONS_CODE,        /* Parameter request option. */\r
-       dhcpOPTION_END_BYTE\r
-};\r
-size_t xOptionsLength = sizeof( ucDHCPDiscoverOptions );\r
-\r
-       pucUDPPayloadBuffer = prvCreatePartDHCPMessage( &xAddress, dhcpREQUEST_OPCODE, ucDHCPDiscoverOptions, &xOptionsLength );\r
-\r
-       FreeRTOS_debug_printf( ( "vDHCPProcess: discover\n" ) );\r
-       iptraceSENDING_DHCP_DISCOVER();\r
-\r
-       /* 'ucFirstOptionByte' is part of DHCP message struct, so subtract one byte. */\r
-       if( FreeRTOS_sendto( xDHCPData.xDHCPSocket, pucUDPPayloadBuffer, ( sizeof( DHCPMessage_t ) + xOptionsLength - 1 ), 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
-#if( ipconfigDHCP_FALL_BACK_AUTO_IP != 0 )\r
-\r
-       static void prvPrepareLinkLayerIPLookUp( void )\r
-       {\r
-       uint8_t ucLinkLayerIPAddress[ 2 ];\r
-       uint32_t ulNumbers[ 2 ];\r
-\r
-               /* After DHCP has failed to answer, prepare everything to start\r
-               trying-out LinkLayer IP-addresses, using the random method. */\r
-               xDHCPData.xDHCPTxTime = xTaskGetTickCount();\r
-\r
-               xApplicationGetRandomNumber( &( ulNumbers[ 0 ] ) );\r
-               xApplicationGetRandomNumber( &( ulNumbers[ 1 ] ) );\r
-               ucLinkLayerIPAddress[ 0 ] = ( uint8_t )1 + ( uint8_t )( ulNumbers[ 0 ] % 0xFDu );               /* get value 1..254 for IP-address 3rd byte of IP address to try. */\r
-               ucLinkLayerIPAddress[ 1 ] = ( uint8_t )1 + ( uint8_t )( ulNumbers[ 1 ] % 0xFDu );               /* get value 1..254 for IP-address 4th byte of IP address to try. */\r
-\r
-               xNetworkAddressing.ulGatewayAddress = FreeRTOS_htonl( 0xA9FE0203 );\r
-\r
-               /* prepare xDHCPData with data to test. */\r
-               xDHCPData.ulOfferedIPAddress =\r
-                       FreeRTOS_inet_addr_quick( LINK_LAYER_ADDRESS_0, LINK_LAYER_ADDRESS_1, ucLinkLayerIPAddress[ 0 ], ucLinkLayerIPAddress[ 1 ] );\r
-\r
-               xDHCPData.ulLeaseTime = dhcpDEFAULT_LEASE_TIME;  /*  don't care about lease time. just put anything. */\r
-\r
-               xNetworkAddressing.ulNetMask =\r
-                       FreeRTOS_inet_addr_quick( LINK_LAYER_NETMASK_0, LINK_LAYER_NETMASK_1, LINK_LAYER_NETMASK_2, LINK_LAYER_NETMASK_3 );\r
-\r
-               /* DHCP completed.  The IP address can now be used, and the\r
-               timer set to the lease timeout time. */\r
-               *ipLOCAL_IP_ADDRESS_POINTER = xDHCPData.ulOfferedIPAddress;\r
-\r
-               /* Setting the 'local' broadcast address, something like 192.168.1.255' */\r
-               xNetworkAddressing.ulBroadcastAddress = ( xDHCPData.ulOfferedIPAddress & xNetworkAddressing.ulNetMask ) |  ~xNetworkAddressing.ulNetMask;\r
-\r
-               /* Close socket to ensure packets don't queue on it. not needed anymore as DHCP failed. but still need timer for ARP testing. */\r
-               if( xDHCPData.xDHCPSocket != NULL )\r
-               {\r
-                       /* Close socket to ensure packets don't queue on it. */\r
-                       vSocketClose( xDHCPData.xDHCPSocket );\r
-                   xDHCPData.xDHCPSocket = NULL;\r
-               }\r
-\r
-               xApplicationGetRandomNumber( &( ulNumbers[ 0 ] ) );\r
-               xDHCPData.xDHCPTxPeriod = pdMS_TO_TICKS( 3000ul + ( ulNumbers[ 0 ] & 0x3ffuL ) ); /*  do ARP test every (3 + 0-1024mS) seconds. */\r
-\r
-               xARPHadIPClash = pdFALSE;          /* reset flag that shows if have ARP clash. */\r
-               vARPSendGratuitous();\r
-       }\r
-\r
-#endif /* ipconfigDHCP_FALL_BACK_AUTO_IP */\r
-/*-----------------------------------------------------------*/\r
-\r
-#endif /* ipconfigUSE_DHCP != 0 */\r
-\r
-\r
+/*
+ * FreeRTOS+TCP V2.2.0
+ * Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * http://aws.amazon.com/freertos
+ * http://www.FreeRTOS.org
+ */
+
+/* Standard includes. */
+#include <stdint.h>
+
+/* FreeRTOS includes. */
+#include "FreeRTOS.h"
+#include "task.h"
+#include "semphr.h"
+
+/* FreeRTOS+TCP includes. */
+#include "FreeRTOS_IP.h"
+#include "FreeRTOS_Sockets.h"
+#include "FreeRTOS_IP_Private.h"
+#include "FreeRTOS_UDP_IP.h"
+#include "FreeRTOS_TCP_IP.h"
+#include "FreeRTOS_DHCP.h"
+#include "FreeRTOS_ARP.h"
+#include "NetworkInterface.h"
+#include "NetworkBufferManagement.h"
+
+/* Exclude the entire file if DHCP is not enabled. */
+#if( ipconfigUSE_DHCP != 0 )
+
+#if ( ipconfigUSE_DHCP != 0 ) && ( ipconfigNETWORK_MTU < 586u )
+       /* DHCP must be able to receive an options field of 312 bytes, the fixed
+       part of the DHCP packet is 240 bytes, and the IP/UDP headers take 28 bytes. */
+       #error ipconfigNETWORK_MTU needs to be at least 586 to use DHCP
+#endif
+
+/* Parameter widths in the DHCP packet. */
+#define dhcpCLIENT_HARDWARE_ADDRESS_LENGTH             16
+#define dhcpSERVER_HOST_NAME_LENGTH                            64
+#define dhcpBOOT_FILE_NAME_LENGTH                              128
+
+/* Timer parameters */
+#ifndef dhcpINITIAL_DHCP_TX_PERIOD
+       #define dhcpINITIAL_TIMER_PERIOD                        ( pdMS_TO_TICKS( 250 ) )
+       #define dhcpINITIAL_DHCP_TX_PERIOD                      ( pdMS_TO_TICKS( 5000 ) )
+#endif
+
+/* Codes of interest found in the DHCP options field. */
+#define dhcpZERO_PAD_OPTION_CODE                               ( 0u )
+#define dhcpSUBNET_MASK_OPTION_CODE                            ( 1u )
+#define dhcpGATEWAY_OPTION_CODE                                        ( 3u )
+#define dhcpDNS_SERVER_OPTIONS_CODE                            ( 6u )
+#define dhcpDNS_HOSTNAME_OPTIONS_CODE                  ( 12u )
+#define dhcpREQUEST_IP_ADDRESS_OPTION_CODE             ( 50u )
+#define dhcpLEASE_TIME_OPTION_CODE                             ( 51u )
+#define dhcpMESSAGE_TYPE_OPTION_CODE                   ( 53u )
+#define dhcpSERVER_IP_ADDRESS_OPTION_CODE              ( 54u )
+#define dhcpPARAMETER_REQUEST_OPTION_CODE              ( 55u )
+#define dhcpCLIENT_IDENTIFIER_OPTION_CODE              ( 61u )
+
+/* The four DHCP message types of interest. */
+#define dhcpMESSAGE_TYPE_DISCOVER                              ( 1 )
+#define dhcpMESSAGE_TYPE_OFFER                                 ( 2 )
+#define dhcpMESSAGE_TYPE_REQUEST                               ( 3 )
+#define dhcpMESSAGE_TYPE_ACK                                   ( 5 )
+#define dhcpMESSAGE_TYPE_NACK                                  ( 6 )
+
+/* Offsets into the transmitted DHCP options fields at which various parameters
+are located. */
+#define dhcpCLIENT_IDENTIFIER_OFFSET                   ( 5 )
+#define dhcpREQUESTED_IP_ADDRESS_OFFSET                        ( 13 )
+#define dhcpDHCP_SERVER_IP_ADDRESS_OFFSET              ( 19 )
+
+/* Values used in the DHCP packets. */
+#define dhcpREQUEST_OPCODE                                             ( 1 )
+#define dhcpREPLY_OPCODE                                               ( 2 )
+#define dhcpADDRESS_TYPE_ETHERNET                              ( 1 )
+#define dhcpETHERNET_ADDRESS_LENGTH                            ( 6 )
+
+/* If a lease time is not received, use the default of two days. */
+/* 48 hours in ticks.  Can not use pdMS_TO_TICKS() as integer overflow can occur. */
+#define dhcpDEFAULT_LEASE_TIME                                 ( ( 48UL * 60UL * 60UL ) * configTICK_RATE_HZ )
+
+/* Don't allow the lease time to be too short. */
+#define dhcpMINIMUM_LEASE_TIME                                 ( pdMS_TO_TICKS( 60000UL ) )    /* 60 seconds in ticks. */
+
+/* Marks the end of the variable length options field in the DHCP packet. */
+#define dhcpOPTION_END_BYTE 0xffu
+
+/* Offset into a DHCP message at which the first byte of the options is
+located. */
+#define dhcpFIRST_OPTION_BYTE_OFFSET                   ( 0xf0 )
+
+/* Standard DHCP port numbers and magic cookie value. */
+#if( ipconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN )
+       #define dhcpCLIENT_PORT 0x4400u
+       #define dhcpSERVER_PORT 0x4300u
+       #define dhcpCOOKIE              0x63538263ul
+       #define dhcpBROADCAST   0x0080u
+#else
+       #define dhcpCLIENT_PORT 0x0044u
+       #define dhcpSERVER_PORT 0x0043u
+       #define dhcpCOOKIE              0x63825363ul
+       #define dhcpBROADCAST   0x8000u
+#endif /* ipconfigBYTE_ORDER */
+
+#include "pack_struct_start.h"
+struct xDHCPMessage
+{
+       uint8_t ucOpcode;
+       uint8_t ucAddressType;
+       uint8_t ucAddressLength;
+       uint8_t ucHops;
+       uint32_t ulTransactionID;
+       uint16_t usElapsedTime;
+       uint16_t usFlags;
+       uint32_t ulClientIPAddress_ciaddr;
+       uint32_t ulYourIPAddress_yiaddr;
+       uint32_t ulServerIPAddress_siaddr;
+       uint32_t ulRelayAgentIPAddress_giaddr;
+       uint8_t ucClientHardwareAddress[ dhcpCLIENT_HARDWARE_ADDRESS_LENGTH ];
+       uint8_t ucServerHostName[ dhcpSERVER_HOST_NAME_LENGTH ];
+       uint8_t ucBootFileName[ dhcpBOOT_FILE_NAME_LENGTH ];
+       uint32_t ulDHCPCookie;
+       uint8_t ucFirstOptionByte;
+}
+#include "pack_struct_end.h"
+typedef struct xDHCPMessage DHCPMessage_t;
+
+/* DHCP state machine states. */
+typedef enum
+{
+       eWaitingSendFirstDiscover = 0,  /* Initial state.  Send a discover the first time it is called, and reset all timers. */
+       eWaitingOffer,                                  /* Either resend the discover, or, if the offer is forthcoming, send a request. */
+       eWaitingAcknowledge,                    /* Either resend the request. */
+       #if( ipconfigDHCP_FALL_BACK_AUTO_IP != 0 )
+               eGetLinkLayerAddress,           /* When DHCP didn't respond, try to obtain a LinkLayer address 168.254.x.x. */
+       #endif
+       eLeasedAddress,                                 /* Resend the request at the appropriate time to renew the lease. */
+       eNotUsingLeasedAddress                  /* DHCP failed, and a default IP address is being used. */
+} eDHCPState_t;
+
+/* Hold information in between steps in the DHCP state machine. */
+struct xDHCP_DATA
+{
+       uint32_t ulTransactionId;
+       uint32_t ulOfferedIPAddress;
+       uint32_t ulDHCPServerAddress;
+       uint32_t ulLeaseTime;
+       /* Hold information on the current timer state. */
+       TickType_t xDHCPTxTime;
+       TickType_t xDHCPTxPeriod;
+       /* Try both without and with the broadcast flag */
+       BaseType_t xUseBroadcast;
+       /* Maintains the DHCP state machine state. */
+       eDHCPState_t eDHCPState;
+       /* The UDP socket used for all incoming and outgoing DHCP traffic. */
+       Socket_t xDHCPSocket;
+};
+
+typedef struct xDHCP_DATA DHCPData_t;
+
+#if( ipconfigDHCP_FALL_BACK_AUTO_IP != 0 )
+       /* Define the Link Layer IP address: 169.254.x.x */
+       #define LINK_LAYER_ADDRESS_0    169
+       #define LINK_LAYER_ADDRESS_1    254
+
+       /* Define the netmask used: 255.255.0.0 */
+       #define LINK_LAYER_NETMASK_0    255
+       #define LINK_LAYER_NETMASK_1    255
+       #define LINK_LAYER_NETMASK_2    0
+       #define LINK_LAYER_NETMASK_3    0
+#endif
+
+
+/*
+ * Generate a DHCP discover message and send it on the DHCP socket.
+ */
+static void prvSendDHCPDiscover( void );
+
+/*
+ * Interpret message received on the DHCP socket.
+ */
+static BaseType_t prvProcessDHCPReplies( BaseType_t xExpectedMessageType );
+
+/*
+ * Generate a DHCP request packet, and send it on the DHCP socket.
+ */
+static void prvSendDHCPRequest( void );
+
+/*
+ * Prepare to start a DHCP transaction.  This initialises some state variables
+ * and creates the DHCP socket if necessary.
+ */
+static void prvInitialiseDHCP( void );
+
+/*
+ * Creates the part of outgoing DHCP messages that are common to all outgoing
+ * DHCP messages.
+ */
+static uint8_t *prvCreatePartDHCPMessage( struct freertos_sockaddr *pxAddress, BaseType_t xOpcode, const uint8_t * const pucOptionsArray, size_t *pxOptionsArraySize );
+
+/*
+ * Create the DHCP socket, if it has not been created already.
+ */
+static void prvCreateDHCPSocket( void );
+
+/*
+ * After DHCP has failed to answer, prepare everything to start searching
+ * for (trying-out) LinkLayer IP-addresses, using the random method: Send
+ * a gratuitous ARP request and wait if another device responds to it.
+ */
+#if( ipconfigDHCP_FALL_BACK_AUTO_IP != 0 )
+       static void prvPrepareLinkLayerIPLookUp( void );
+#endif
+
+/*-----------------------------------------------------------*/
+
+/* The next DHCP transaction Id to be used. */
+static DHCPData_t xDHCPData;
+
+/*-----------------------------------------------------------*/
+
+BaseType_t xIsDHCPSocket( Socket_t xSocket )
+{
+BaseType_t xReturn;
+
+       if( xDHCPData.xDHCPSocket == xSocket )
+       {
+               xReturn = pdTRUE;
+       }
+       else
+       {
+               xReturn = pdFALSE;
+       }
+
+       return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+void vDHCPProcess( BaseType_t xReset )
+{
+BaseType_t xGivingUp = pdFALSE;
+#if( ipconfigUSE_DHCP_HOOK != 0 )
+       eDHCPCallbackAnswer_t eAnswer;
+#endif /* ipconfigUSE_DHCP_HOOK */
+
+       /* Is DHCP starting over? */
+       if( xReset != pdFALSE )
+       {
+               xDHCPData.eDHCPState = eWaitingSendFirstDiscover;
+       }
+
+       switch( xDHCPData.eDHCPState )
+       {
+               case eWaitingSendFirstDiscover :
+                       /* Ask the user if a DHCP discovery is required. */
+               #if( ipconfigUSE_DHCP_HOOK != 0 )
+                       eAnswer = xApplicationDHCPHook( eDHCPPhasePreDiscover, xNetworkAddressing.ulDefaultIPAddress );
+                       if( eAnswer == eDHCPContinue )
+               #endif  /* ipconfigUSE_DHCP_HOOK */
+                       {
+                               /* Initial state.  Create the DHCP socket, timer, etc. if they
+                               have not already been created. */
+                               prvInitialiseDHCP();
+
+                               /* See if prvInitialiseDHCP() has creates a socket. */
+                               if( xDHCPData.xDHCPSocket == NULL )
+                               {
+                                       xGivingUp = pdTRUE;
+                                       break;
+                               }
+
+                               *ipLOCAL_IP_ADDRESS_POINTER = 0UL;
+
+                               /* Send the first discover request. */
+                               if( xDHCPData.xDHCPSocket != NULL )
+                               {
+                                       xDHCPData.xDHCPTxTime = xTaskGetTickCount();
+                                       prvSendDHCPDiscover( );
+                                       xDHCPData.eDHCPState = eWaitingOffer;
+                               }
+                       }
+               #if( ipconfigUSE_DHCP_HOOK != 0 )
+                       else
+                       {
+                               if( eAnswer == eDHCPUseDefaults )
+                               {
+                                       memcpy( &xNetworkAddressing, &xDefaultAddressing, sizeof( xNetworkAddressing ) );
+                               }
+
+                               /* The user indicates that the DHCP process does not continue. */
+                               xGivingUp = pdTRUE;
+                       }
+               #endif  /* ipconfigUSE_DHCP_HOOK */
+                       break;
+
+               case eWaitingOffer :
+
+                       xGivingUp = pdFALSE;
+
+                       /* Look for offers coming in. */
+                       if( prvProcessDHCPReplies( dhcpMESSAGE_TYPE_OFFER ) == pdPASS )
+                       {
+                       #if( ipconfigUSE_DHCP_HOOK != 0 )
+                               /* Ask the user if a DHCP request is required. */
+                               eAnswer = xApplicationDHCPHook( eDHCPPhasePreRequest, xDHCPData.ulOfferedIPAddress );
+
+                               if( eAnswer == eDHCPContinue )
+                       #endif  /* ipconfigUSE_DHCP_HOOK */
+                               {
+                                       /* An offer has been made, the user wants to continue,
+                                       generate the request. */
+                                       xDHCPData.xDHCPTxTime = xTaskGetTickCount();
+                                       xDHCPData.xDHCPTxPeriod = dhcpINITIAL_DHCP_TX_PERIOD;
+                                       prvSendDHCPRequest( );
+                                       xDHCPData.eDHCPState = eWaitingAcknowledge;
+                                       break;
+                               }
+
+                       #if( ipconfigUSE_DHCP_HOOK != 0 )
+                               if( eAnswer == eDHCPUseDefaults )
+                               {
+                                       memcpy( &xNetworkAddressing, &xDefaultAddressing, sizeof( xNetworkAddressing ) );
+                               }
+
+                               /* The user indicates that the DHCP process does not continue. */
+                               xGivingUp = pdTRUE;
+                       #endif  /* ipconfigUSE_DHCP_HOOK */
+                       }
+                       else if( ( xTaskGetTickCount() - xDHCPData.xDHCPTxTime ) > xDHCPData.xDHCPTxPeriod )
+                       {
+                               /* It is time to send another Discover.  Increase the time
+                               period, and if it has not got to the point of giving up - send
+                               another discovery. */
+                               xDHCPData.xDHCPTxPeriod <<= 1;
+
+                               if( xDHCPData.xDHCPTxPeriod <= ipconfigMAXIMUM_DISCOVER_TX_PERIOD )
+                               {
+                                       if( xApplicationGetRandomNumber( &( xDHCPData.ulTransactionId ) ) != pdFALSE )
+                                       {
+                                               xDHCPData.xDHCPTxTime = xTaskGetTickCount( );
+                                               xDHCPData.xUseBroadcast = !xDHCPData.xUseBroadcast;
+                                               prvSendDHCPDiscover( );
+                                               FreeRTOS_debug_printf( ( "vDHCPProcess: timeout %lu ticks\n", xDHCPData.xDHCPTxPeriod ) );
+                                       }
+                                       else
+                                       {
+                                               FreeRTOS_debug_printf( ( "vDHCPProcess: failed to generate a random Transaction ID\n" ) );
+                                       }
+                               }
+                               else
+                               {
+                                       FreeRTOS_debug_printf( ( "vDHCPProcess: giving up %lu > %lu ticks\n", xDHCPData.xDHCPTxPeriod, ipconfigMAXIMUM_DISCOVER_TX_PERIOD ) );
+
+                                       #if( ipconfigDHCP_FALL_BACK_AUTO_IP != 0 )
+                                       {
+                                               /* Only use a fake Ack if the default IP address == 0x00
+                                               and the link local addressing is used.  Start searching
+                                               a free LinkLayer IP-address.  Next state will be
+                                               'eGetLinkLayerAddress'. */
+                                               prvPrepareLinkLayerIPLookUp();
+
+                                               /* Setting an IP address manually so set to not using
+                                               leased address mode. */
+                                               xDHCPData.eDHCPState = eGetLinkLayerAddress;
+                                       }
+                                       #else
+                                       {
+                                               xGivingUp = pdTRUE;
+                                       }
+                                       #endif /* ipconfigDHCP_FALL_BACK_AUTO_IP */
+                               }
+                       }
+                       break;
+
+               case eWaitingAcknowledge :
+
+                       /* Look for acks coming in. */
+                       if( prvProcessDHCPReplies( dhcpMESSAGE_TYPE_ACK ) == pdPASS )
+                       {
+                               FreeRTOS_debug_printf( ( "vDHCPProcess: acked %lxip\n", FreeRTOS_ntohl( xDHCPData.ulOfferedIPAddress ) ) );
+
+                               /* DHCP completed.  The IP address can now be used, and the
+                               timer set to the lease timeout time. */
+                               *ipLOCAL_IP_ADDRESS_POINTER = xDHCPData.ulOfferedIPAddress;
+
+                               /* Setting the 'local' broadcast address, something like
+                               '192.168.1.255'. */
+                               xNetworkAddressing.ulBroadcastAddress = ( xDHCPData.ulOfferedIPAddress & xNetworkAddressing.ulNetMask ) |  ~xNetworkAddressing.ulNetMask;
+                               xDHCPData.eDHCPState = eLeasedAddress;
+
+                               iptraceDHCP_SUCCEDEED( xDHCPData.ulOfferedIPAddress );
+
+                               /* DHCP failed, the default configured IP-address will be used
+                               Now call vIPNetworkUpCalls() to send the network-up event and
+                               start the ARP timer. */
+                               vIPNetworkUpCalls( );
+
+                               /* Close socket to ensure packets don't queue on it. */
+                               vSocketClose( xDHCPData.xDHCPSocket );
+                               xDHCPData.xDHCPSocket = NULL;
+
+                               if( xDHCPData.ulLeaseTime == 0UL )
+                               {
+                                       xDHCPData.ulLeaseTime = dhcpDEFAULT_LEASE_TIME;
+                               }
+                               else if( xDHCPData.ulLeaseTime < dhcpMINIMUM_LEASE_TIME )
+                               {
+                                       xDHCPData.ulLeaseTime = dhcpMINIMUM_LEASE_TIME;
+                               }
+                               else
+                               {
+                                       /* The lease time is already valid. */
+                               }
+
+                               /* Check for clashes. */
+                               vARPSendGratuitous();
+                               vIPReloadDHCPTimer( xDHCPData.ulLeaseTime );
+                       }
+                       else
+                       {
+                               /* Is it time to send another Discover? */
+                               if( ( xTaskGetTickCount() - xDHCPData.xDHCPTxTime ) > xDHCPData.xDHCPTxPeriod )
+                               {
+                                       /* Increase the time period, and if it has not got to the
+                                       point of giving up - send another request. */
+                                       xDHCPData.xDHCPTxPeriod <<= 1;
+
+                                       if( xDHCPData.xDHCPTxPeriod <= ipconfigMAXIMUM_DISCOVER_TX_PERIOD )
+                                       {
+                                               xDHCPData.xDHCPTxTime = xTaskGetTickCount();
+                                               prvSendDHCPRequest( );
+                                       }
+                                       else
+                                       {
+                                               /* Give up, start again. */
+                                               xDHCPData.eDHCPState = eWaitingSendFirstDiscover;
+                                       }
+                               }
+                       }
+                       break;
+
+       #if( ipconfigDHCP_FALL_BACK_AUTO_IP != 0 )
+               case eGetLinkLayerAddress:
+                       if( ( xTaskGetTickCount() - xDHCPData.xDHCPTxTime ) > xDHCPData.xDHCPTxPeriod )
+                       {
+                               if( xARPHadIPClash == pdFALSE )
+                               {
+                                       /* ARP OK. proceed. */
+                                       iptraceDHCP_SUCCEDEED( xDHCPData.ulOfferedIPAddress );
+
+                                       /* Auto-IP succeeded, the default configured IP-address will
+                                       be used.  Now call vIPNetworkUpCalls() to send the
+                                       network-up event and start the ARP timer. */
+                                       vIPNetworkUpCalls( );
+                                       xDHCPData.eDHCPState = eNotUsingLeasedAddress;
+                               }
+                               else
+                               {
+                                       /* ARP clashed - try another IP address. */
+                                       prvPrepareLinkLayerIPLookUp();
+
+                                       /* Setting an IP address manually so set to not using leased
+                                       address mode. */
+                                       xDHCPData.eDHCPState = eGetLinkLayerAddress;
+                               }
+                       }
+                       break;
+       #endif  /* ipconfigDHCP_FALL_BACK_AUTO_IP */
+
+               case eLeasedAddress :
+
+                       /* Resend the request at the appropriate time to renew the lease. */
+                       prvCreateDHCPSocket();
+
+                       if( xDHCPData.xDHCPSocket != NULL )
+                       {
+                               xDHCPData.xDHCPTxTime = xTaskGetTickCount();
+                               xDHCPData.xDHCPTxPeriod = dhcpINITIAL_DHCP_TX_PERIOD;
+                               prvSendDHCPRequest( );
+                               xDHCPData.eDHCPState = eWaitingAcknowledge;
+
+                               /* From now on, we should be called more often */
+                               vIPReloadDHCPTimer( dhcpINITIAL_TIMER_PERIOD );
+                       }
+                       break;
+
+               case eNotUsingLeasedAddress:
+
+                       vIPSetDHCPTimerEnableState( pdFALSE );
+                       break;
+
+               default:
+                       break;
+       }
+
+       if( xGivingUp != pdFALSE )
+       {
+               /* xGivingUp became true either because of a time-out, or because
+               xApplicationDHCPHook() returned another value than 'eDHCPContinue',
+               meaning that the conversion is canceled from here. */
+
+               /* Revert to static IP address. */
+               taskENTER_CRITICAL();
+               {
+                       *ipLOCAL_IP_ADDRESS_POINTER = xNetworkAddressing.ulDefaultIPAddress;
+                       iptraceDHCP_REQUESTS_FAILED_USING_DEFAULT_IP_ADDRESS( xNetworkAddressing.ulDefaultIPAddress );
+               }
+               taskEXIT_CRITICAL();
+
+               xDHCPData.eDHCPState = eNotUsingLeasedAddress;
+               vIPSetDHCPTimerEnableState( pdFALSE );
+
+               /* DHCP failed, the default configured IP-address will be used.  Now
+               call vIPNetworkUpCalls() to send the network-up event and start the ARP
+               timer. */
+               vIPNetworkUpCalls( );
+
+               /* Test if socket was indeed created. */
+               if( xDHCPData.xDHCPSocket != NULL )
+               {
+                       /* Close socket to ensure packets don't queue on it. */
+                       vSocketClose( xDHCPData.xDHCPSocket );
+                       xDHCPData.xDHCPSocket = NULL;
+               }
+       }
+}
+/*-----------------------------------------------------------*/
+
+static void prvCreateDHCPSocket( void )
+{
+struct freertos_sockaddr xAddress;
+BaseType_t xReturn;
+TickType_t xTimeoutTime = ( TickType_t ) 0;
+
+       /* Create the socket, if it has not already been created. */
+       if( xDHCPData.xDHCPSocket == NULL )
+       {
+               xDHCPData.xDHCPSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP );
+               if( xDHCPData.xDHCPSocket != FREERTOS_INVALID_SOCKET )
+               {
+
+                       /* Ensure the Rx and Tx timeouts are zero as the DHCP executes in the
+                       context of the IP task. */
+                       FreeRTOS_setsockopt( xDHCPData.xDHCPSocket, 0, FREERTOS_SO_RCVTIMEO, ( void * ) &xTimeoutTime, sizeof( TickType_t ) );
+                       FreeRTOS_setsockopt( xDHCPData.xDHCPSocket, 0, FREERTOS_SO_SNDTIMEO, ( void * ) &xTimeoutTime, sizeof( TickType_t ) );
+
+                       /* Bind to the standard DHCP client port. */
+                       xAddress.sin_port = ( uint16_t ) dhcpCLIENT_PORT;
+                       xReturn = vSocketBind( xDHCPData.xDHCPSocket, &xAddress, sizeof( xAddress ), pdFALSE );
+                       if( xReturn != 0 )
+                       {
+                               /* Binding failed, close the socket again. */
+                               vSocketClose( xDHCPData.xDHCPSocket );
+                               xDHCPData.xDHCPSocket = NULL;
+                       }
+               }
+               else
+               {
+                       /* Change to NULL for easier testing. */
+                       xDHCPData.xDHCPSocket = NULL;
+               }
+       }
+}
+/*-----------------------------------------------------------*/
+
+static void prvInitialiseDHCP( void )
+{
+       /* Initialise the parameters that will be set by the DHCP process. Per
+       https://www.ietf.org/rfc/rfc2131.txt, Transaction ID should be a random
+       value chosen by the client. */
+
+       /* Check for random number generator API failure. */
+       if( xApplicationGetRandomNumber( &( xDHCPData.ulTransactionId ) ) != pdFALSE )
+       {
+               xDHCPData.xUseBroadcast = 0;
+               xDHCPData.ulOfferedIPAddress = 0UL;
+               xDHCPData.ulDHCPServerAddress = 0UL;
+               xDHCPData.xDHCPTxPeriod = dhcpINITIAL_DHCP_TX_PERIOD;
+
+               /* Create the DHCP socket if it has not already been created. */
+               prvCreateDHCPSocket();
+               FreeRTOS_debug_printf( ( "prvInitialiseDHCP: start after %lu ticks\n", dhcpINITIAL_TIMER_PERIOD ) );
+               vIPReloadDHCPTimer( dhcpINITIAL_TIMER_PERIOD );
+       }
+       else
+       {
+               /* There was a problem with the randomiser. */
+       }
+}
+/*-----------------------------------------------------------*/
+
+static BaseType_t prvProcessDHCPReplies( BaseType_t xExpectedMessageType )
+{
+uint8_t *pucUDPPayload, *pucLastByte;
+struct freertos_sockaddr xClient;
+uint32_t xClientLength = sizeof( xClient );
+int32_t lBytes;
+DHCPMessage_t *pxDHCPMessage;
+uint8_t *pucByte, ucOptionCode, ucLength;
+uint32_t ulProcessed, ulParameter;
+BaseType_t xReturn = pdFALSE;
+const uint32_t ulMandatoryOptions = 2ul; /* DHCP server address, and the correct DHCP message type must be present in the options. */
+
+       lBytes = FreeRTOS_recvfrom( xDHCPData.xDHCPSocket, ( void * ) &pucUDPPayload, 0ul, FREERTOS_ZERO_COPY, &xClient, &xClientLength );
+
+       if( lBytes > 0 )
+       {
+               /* Map a DHCP structure onto the received data. */
+               pxDHCPMessage = ( DHCPMessage_t * ) ( pucUDPPayload );
+
+               /* Sanity check. */
+               if( ( lBytes >= sizeof( DHCPMessage_t ) ) &&
+                       ( pxDHCPMessage->ulDHCPCookie == ( uint32_t ) dhcpCOOKIE ) &&
+                       ( pxDHCPMessage->ucOpcode == ( uint8_t ) dhcpREPLY_OPCODE ) &&
+                       ( pxDHCPMessage->ulTransactionID == FreeRTOS_htonl( xDHCPData.ulTransactionId ) ) )
+               {
+                       if( memcmp( ( void * ) &( pxDHCPMessage->ucClientHardwareAddress ),
+                                               ( void * ) ipLOCAL_MAC_ADDRESS,
+                                               sizeof( MACAddress_t ) ) == 0 )
+                       {
+                               /* None of the essential options have been processed yet. */
+                               ulProcessed = 0ul;
+
+                               /* Walk through the options until the dhcpOPTION_END_BYTE byte
+                               is found, taking care not to walk off the end of the options. */
+                               pucByte = &( pxDHCPMessage->ucFirstOptionByte );
+                /* Maintain a pointer to the last valid byte (i.e. not the first
+                invalid byte). */
+                               pucLastByte = pucUDPPayload + lBytes - 1;
+
+                               while( pucByte <= pucLastByte )
+                               {
+                                       ucOptionCode = pucByte[ 0 ];
+                                       if( ucOptionCode == dhcpOPTION_END_BYTE )
+                                       {
+                                               /* Ready, the last byte has been seen. */
+                                               break;
+                                       }
+                                       if( ucOptionCode == dhcpZERO_PAD_OPTION_CODE )
+                                       {
+                                               /* The value zero is used as a pad byte,
+                                               it is not followed by a length byte. */
+                                               pucByte += 1;
+                                               continue;
+                                       }
+
+                                       /* Stop if the response is malformed. */
+                                       if( pucByte < pucLastByte )
+                                       {
+                        /* There are at least two bytes left. */
+                                               ucLength = pucByte[ 1 ];
+                                               pucByte += 2;
+
+                                               if( pucByte + ucLength > pucLastByte )
+                                               {
+                                                       break;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               break;
+                                       }
+
+                                       /* In most cases, a 4-byte network-endian parameter follows,
+                                       just get it once here and use later. */
+                                       if( ucLength >= sizeof( ulParameter ) )
+                                       {
+                                               memcpy( ( void * ) &( ulParameter ),
+                                                               ( void * ) pucByte,
+                                                               ( size_t ) sizeof( ulParameter ) );
+                                       }
+                                       else
+                                       {
+                                               ulParameter = 0;
+                                       }
+
+                                       /* Option-specific handling. */
+                                       switch( ucOptionCode )
+                                       {
+                                               case dhcpMESSAGE_TYPE_OPTION_CODE       :
+
+                                                       if( *pucByte == ( uint8_t ) xExpectedMessageType )
+                                                       {
+                                                               /* The message type is the message type the
+                                                               state machine is expecting. */
+                                                               ulProcessed++;
+                                                       }
+                                                       else if( *pucByte == ( uint8_t ) dhcpMESSAGE_TYPE_NACK )
+                                                       {
+                                                               if( xExpectedMessageType == ( BaseType_t ) dhcpMESSAGE_TYPE_ACK )
+                                                               {
+                                                                       /* Start again. */
+                                                                       xDHCPData.eDHCPState = eWaitingSendFirstDiscover;
+                                                               }
+                                                       }
+                                                       else
+                                                       {
+                                                               /* Don't process other message types. */
+                                                       }
+                                                       break;
+
+                                               case dhcpSUBNET_MASK_OPTION_CODE :
+
+                                                       if( ucLength == sizeof( uint32_t ) )
+                                                       {
+                                                               xNetworkAddressing.ulNetMask = ulParameter;
+                                                       }
+                                                       break;
+
+                                               case dhcpGATEWAY_OPTION_CODE :
+
+                                                       if( ucLength == sizeof( uint32_t ) )
+                                                       {
+                                                               /* ulProcessed is not incremented in this case
+                                                               because the gateway is not essential. */
+                                                               xNetworkAddressing.ulGatewayAddress = ulParameter;
+                                                       }
+                                                       break;
+
+                                               case dhcpDNS_SERVER_OPTIONS_CODE :
+
+                                                       /* ulProcessed is not incremented in this case
+                                                       because the DNS server is not essential.  Only the
+                                                       first DNS server address is taken. */
+                                                       xNetworkAddressing.ulDNSServerAddress = ulParameter;
+                                                       break;
+
+                                               case dhcpSERVER_IP_ADDRESS_OPTION_CODE :
+
+                                                       if( ucLength == sizeof( uint32_t ) )
+                                                       {
+                                                               if( xExpectedMessageType == ( BaseType_t ) dhcpMESSAGE_TYPE_OFFER )
+                                                               {
+                                                                       /* Offers state the replying server. */
+                                                                       ulProcessed++;
+                                                                       xDHCPData.ulDHCPServerAddress = ulParameter;
+                                                               }
+                                                               else
+                                                               {
+                                                                       /* The ack must come from the expected server. */
+                                                                       if( xDHCPData.ulDHCPServerAddress == ulParameter )
+                                                                       {
+                                                                               ulProcessed++;
+                                                                       }
+                                                               }
+                                                       }
+                                                       break;
+
+                                               case dhcpLEASE_TIME_OPTION_CODE :
+
+                                                       if( ucLength == sizeof( xDHCPData.ulLeaseTime ) )
+                                                       {
+                                                               /* ulProcessed is not incremented in this case
+                                                               because the lease time is not essential. */
+                                                               /* The DHCP parameter is in seconds, convert
+                                                               to host-endian format. */
+                                                               xDHCPData.ulLeaseTime = FreeRTOS_ntohl( ulParameter );
+
+                                                               /* Divide the lease time by two to ensure a
+                                                               renew request is sent before the lease actually
+                                                               expires. */
+                                                               xDHCPData.ulLeaseTime >>= 1UL;
+
+                                                               /* Multiply with configTICK_RATE_HZ to get clock
+                                                               ticks. */
+                                                               xDHCPData.ulLeaseTime = configTICK_RATE_HZ * xDHCPData.ulLeaseTime;
+                                                       }
+                                                       break;
+
+                                               default :
+
+                                                       /* Not interested in this field. */
+
+                                                       break;
+                                       }
+
+                                       /* Jump over the data to find the next option code. */
+                                       if( ucLength == 0u )
+                                       {
+                                               break;
+                                       }
+                                       else
+                                       {
+                                               pucByte += ucLength;
+                                       }
+                               }
+
+                               /* Were all the mandatory options received? */
+                               if( ulProcessed >= ulMandatoryOptions )
+                               {
+                                       /* HT:endian: used to be network order */
+                                       xDHCPData.ulOfferedIPAddress = pxDHCPMessage->ulYourIPAddress_yiaddr;
+                                       FreeRTOS_printf( ( "vDHCPProcess: offer %lxip\n", FreeRTOS_ntohl( xDHCPData.ulOfferedIPAddress ) ) );
+                                       xReturn = pdPASS;
+                               }
+                       }
+               }
+
+               FreeRTOS_ReleaseUDPPayloadBuffer( ( void * ) pucUDPPayload );
+       }
+
+       return xReturn;
+}
+/*-----------------------------------------------------------*/
+
+static uint8_t *prvCreatePartDHCPMessage( struct freertos_sockaddr *pxAddress, BaseType_t xOpcode, const uint8_t * const pucOptionsArray, size_t *pxOptionsArraySize )
+{
+DHCPMessage_t *pxDHCPMessage;
+size_t xRequiredBufferSize = sizeof( DHCPMessage_t ) + *pxOptionsArraySize;
+uint8_t *pucUDPPayloadBuffer;
+
+#if( ipconfigDHCP_REGISTER_HOSTNAME == 1 )
+       const char *pucHostName = pcApplicationHostnameHook ();
+       size_t xNameLength = strlen( pucHostName );
+       uint8_t *pucPtr;
+
+       xRequiredBufferSize += ( 2 + xNameLength );
+#endif
+
+       /* Get a buffer.  This uses a maximum delay, but the delay will be capped
+       to ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS so the return value still needs to
+       be test. */
+       do
+       {
+       } while( ( pucUDPPayloadBuffer = ( uint8_t * ) FreeRTOS_GetUDPPayloadBuffer( xRequiredBufferSize, portMAX_DELAY ) ) == NULL );
+
+       pxDHCPMessage = ( DHCPMessage_t * ) pucUDPPayloadBuffer;
+
+       /* Most fields need to be zero. */
+       memset( ( void * ) pxDHCPMessage, 0x00, sizeof( DHCPMessage_t ) );
+
+       /* Create the message. */
+       pxDHCPMessage->ucOpcode = ( uint8_t ) xOpcode;
+       pxDHCPMessage->ucAddressType = ( uint8_t ) dhcpADDRESS_TYPE_ETHERNET;
+       pxDHCPMessage->ucAddressLength = ( uint8_t ) dhcpETHERNET_ADDRESS_LENGTH;
+       pxDHCPMessage->ulTransactionID = FreeRTOS_htonl( xDHCPData.ulTransactionId );
+       pxDHCPMessage->ulDHCPCookie = ( uint32_t ) dhcpCOOKIE;
+       if( xDHCPData.xUseBroadcast != pdFALSE )
+       {
+               pxDHCPMessage->usFlags = ( uint16_t ) dhcpBROADCAST;
+       }
+       else
+       {
+               pxDHCPMessage->usFlags = 0u;
+       }
+
+       memcpy( ( void * ) &( pxDHCPMessage->ucClientHardwareAddress[ 0 ] ), ( void * ) ipLOCAL_MAC_ADDRESS, sizeof( MACAddress_t ) );
+
+       /* Copy in the const part of the options options. */
+       memcpy( ( void * ) &( pucUDPPayloadBuffer[ dhcpFIRST_OPTION_BYTE_OFFSET ] ), ( void * ) pucOptionsArray, *pxOptionsArraySize );
+
+       #if( ipconfigDHCP_REGISTER_HOSTNAME == 1 )
+       {
+               /* With this option, the hostname can be registered as well which makes
+               it easier to lookup a device in a router's list of DHCP clients. */
+
+               /* Point to where the OPTION_END was stored to add data. */
+               pucPtr = &( pucUDPPayloadBuffer[ dhcpFIRST_OPTION_BYTE_OFFSET + ( *pxOptionsArraySize - 1 ) ] );
+               pucPtr[ 0 ] = dhcpDNS_HOSTNAME_OPTIONS_CODE;
+               pucPtr[ 1 ] = ( uint8_t ) xNameLength;
+               memcpy( ( void *) ( pucPtr + 2 ), pucHostName, xNameLength );
+               pucPtr[ 2 + xNameLength ] = dhcpOPTION_END_BYTE;
+               *pxOptionsArraySize += ( 2 + xNameLength );
+       }
+       #endif
+
+       /* Map in the client identifier. */
+       memcpy( ( void * ) &( pucUDPPayloadBuffer[ dhcpFIRST_OPTION_BYTE_OFFSET + dhcpCLIENT_IDENTIFIER_OFFSET ] ),
+               ( void * ) ipLOCAL_MAC_ADDRESS, sizeof( MACAddress_t ) );
+
+       /* Set the addressing. */
+       pxAddress->sin_addr = ipBROADCAST_IP_ADDRESS;
+       pxAddress->sin_port = ( uint16_t ) dhcpSERVER_PORT;
+
+       return pucUDPPayloadBuffer;
+}
+/*-----------------------------------------------------------*/
+
+static void prvSendDHCPRequest( void )
+{
+uint8_t *pucUDPPayloadBuffer;
+struct freertos_sockaddr xAddress;
+static const uint8_t ucDHCPRequestOptions[] =
+{
+       /* Do not change the ordering without also changing
+       dhcpCLIENT_IDENTIFIER_OFFSET, dhcpREQUESTED_IP_ADDRESS_OFFSET and
+       dhcpDHCP_SERVER_IP_ADDRESS_OFFSET. */
+       dhcpMESSAGE_TYPE_OPTION_CODE, 1, dhcpMESSAGE_TYPE_REQUEST,              /* Message type option. */
+       dhcpCLIENT_IDENTIFIER_OPTION_CODE, 6, 0, 0, 0, 0, 0, 0,                 /* Client identifier. */
+       dhcpREQUEST_IP_ADDRESS_OPTION_CODE, 4, 0, 0, 0, 0,                              /* The IP address being requested. */
+       dhcpSERVER_IP_ADDRESS_OPTION_CODE, 4, 0, 0, 0, 0,                               /* The IP address of the DHCP server. */
+       dhcpOPTION_END_BYTE
+};
+size_t xOptionsLength = sizeof( ucDHCPRequestOptions );
+
+       pucUDPPayloadBuffer = prvCreatePartDHCPMessage( &xAddress, dhcpREQUEST_OPCODE, ucDHCPRequestOptions, &xOptionsLength );
+
+       /* Copy in the IP address being requested. */
+       memcpy( ( void * ) &( pucUDPPayloadBuffer[ dhcpFIRST_OPTION_BYTE_OFFSET + dhcpREQUESTED_IP_ADDRESS_OFFSET ] ),
+               ( void * ) &( xDHCPData.ulOfferedIPAddress ), sizeof( xDHCPData.ulOfferedIPAddress ) );
+
+       /* Copy in the address of the DHCP server being used. */
+       memcpy( ( void * ) &( pucUDPPayloadBuffer[ dhcpFIRST_OPTION_BYTE_OFFSET + dhcpDHCP_SERVER_IP_ADDRESS_OFFSET ] ),
+               ( void * ) &( xDHCPData.ulDHCPServerAddress ), sizeof( xDHCPData.ulDHCPServerAddress ) );
+
+       FreeRTOS_debug_printf( ( "vDHCPProcess: reply %lxip\n", FreeRTOS_ntohl( xDHCPData.ulOfferedIPAddress ) ) );
+       iptraceSENDING_DHCP_REQUEST();
+
+       /* 'ucFirstOptionByte' is part of DHCP message struct, so subtract one byte. */
+       if( FreeRTOS_sendto( xDHCPData.xDHCPSocket, pucUDPPayloadBuffer, ( sizeof( DHCPMessage_t ) + xOptionsLength - 1 ), FREERTOS_ZERO_COPY, &xAddress, sizeof( xAddress ) ) == 0 )
+       {
+               /* The packet was not successfully queued for sending and must be
+               returned to the stack. */
+               FreeRTOS_ReleaseUDPPayloadBuffer( pucUDPPayloadBuffer );
+       }
+}
+/*-----------------------------------------------------------*/
+
+static void prvSendDHCPDiscover( void )
+{
+uint8_t *pucUDPPayloadBuffer;
+struct freertos_sockaddr xAddress;
+static const uint8_t ucDHCPDiscoverOptions[] =
+{
+       /* Do not change the ordering without also changing dhcpCLIENT_IDENTIFIER_OFFSET. */
+       dhcpMESSAGE_TYPE_OPTION_CODE, 1, dhcpMESSAGE_TYPE_DISCOVER,                                     /* Message type option. */
+       dhcpCLIENT_IDENTIFIER_OPTION_CODE, 6, 0, 0, 0, 0, 0, 0,                                         /* Client identifier. */
+       dhcpPARAMETER_REQUEST_OPTION_CODE, 3, dhcpSUBNET_MASK_OPTION_CODE, dhcpGATEWAY_OPTION_CODE, dhcpDNS_SERVER_OPTIONS_CODE,        /* Parameter request option. */
+       dhcpOPTION_END_BYTE
+};
+size_t xOptionsLength = sizeof( ucDHCPDiscoverOptions );
+
+       pucUDPPayloadBuffer = prvCreatePartDHCPMessage( &xAddress, dhcpREQUEST_OPCODE, ucDHCPDiscoverOptions, &xOptionsLength );
+
+       FreeRTOS_debug_printf( ( "vDHCPProcess: discover\n" ) );
+       iptraceSENDING_DHCP_DISCOVER();
+
+       /* 'ucFirstOptionByte' is part of DHCP message struct, so subtract one byte. */
+       if( FreeRTOS_sendto( xDHCPData.xDHCPSocket, pucUDPPayloadBuffer, ( sizeof( DHCPMessage_t ) + xOptionsLength - 1 ), FREERTOS_ZERO_COPY, &xAddress, sizeof( xAddress ) ) == 0 )
+       {
+               /* The packet was not successfully queued for sending and must be
+               returned to the stack. */
+               FreeRTOS_ReleaseUDPPayloadBuffer( pucUDPPayloadBuffer );
+       }
+}
+/*-----------------------------------------------------------*/
+
+#if( ipconfigDHCP_FALL_BACK_AUTO_IP != 0 )
+
+       static void prvPrepareLinkLayerIPLookUp( void )
+       {
+       uint8_t ucLinkLayerIPAddress[ 2 ];
+       uint32_t ulNumbers[ 2 ];
+
+               /* After DHCP has failed to answer, prepare everything to start
+               trying-out LinkLayer IP-addresses, using the random method. */
+               xDHCPData.xDHCPTxTime = xTaskGetTickCount();
+
+               xApplicationGetRandomNumber( &( ulNumbers[ 0 ] ) );
+               xApplicationGetRandomNumber( &( ulNumbers[ 1 ] ) );
+               ucLinkLayerIPAddress[ 0 ] = ( uint8_t )1 + ( uint8_t )( ulNumbers[ 0 ] % 0xFDu );               /* get value 1..254 for IP-address 3rd byte of IP address to try. */
+               ucLinkLayerIPAddress[ 1 ] = ( uint8_t )1 + ( uint8_t )( ulNumbers[ 1 ] % 0xFDu );               /* get value 1..254 for IP-address 4th byte of IP address to try. */
+
+               xNetworkAddressing.ulGatewayAddress = FreeRTOS_htonl( 0xA9FE0203 );
+
+               /* prepare xDHCPData with data to test. */
+               xDHCPData.ulOfferedIPAddress =
+                       FreeRTOS_inet_addr_quick( LINK_LAYER_ADDRESS_0, LINK_LAYER_ADDRESS_1, ucLinkLayerIPAddress[ 0 ], ucLinkLayerIPAddress[ 1 ] );
+
+               xDHCPData.ulLeaseTime = dhcpDEFAULT_LEASE_TIME;  /*  don't care about lease time. just put anything. */
+
+               xNetworkAddressing.ulNetMask =
+                       FreeRTOS_inet_addr_quick( LINK_LAYER_NETMASK_0, LINK_LAYER_NETMASK_1, LINK_LAYER_NETMASK_2, LINK_LAYER_NETMASK_3 );
+
+               /* DHCP completed.  The IP address can now be used, and the
+               timer set to the lease timeout time. */
+               *ipLOCAL_IP_ADDRESS_POINTER = xDHCPData.ulOfferedIPAddress;
+
+               /* Setting the 'local' broadcast address, something like 192.168.1.255' */
+               xNetworkAddressing.ulBroadcastAddress = ( xDHCPData.ulOfferedIPAddress & xNetworkAddressing.ulNetMask ) |  ~xNetworkAddressing.ulNetMask;
+
+               /* Close socket to ensure packets don't queue on it. not needed anymore as DHCP failed. but still need timer for ARP testing. */
+               if( xDHCPData.xDHCPSocket != NULL )
+               {
+                       /* Close socket to ensure packets don't queue on it. */
+                       vSocketClose( xDHCPData.xDHCPSocket );
+                   xDHCPData.xDHCPSocket = NULL;
+               }
+
+               xApplicationGetRandomNumber( &( ulNumbers[ 0 ] ) );
+               xDHCPData.xDHCPTxPeriod = pdMS_TO_TICKS( 3000ul + ( ulNumbers[ 0 ] & 0x3ffuL ) ); /*  do ARP test every (3 + 0-1024mS) seconds. */
+
+               xARPHadIPClash = pdFALSE;          /* reset flag that shows if have ARP clash. */
+               vARPSendGratuitous();
+       }
+
+#endif /* ipconfigDHCP_FALL_BACK_AUTO_IP */
+/*-----------------------------------------------------------*/
+
+#endif /* ipconfigUSE_DHCP != 0 */
+
+