FreeRTOS_DHCP.c 61 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335
  1. /*
  2. * FreeRTOS+TCP V2.3.2 LTS Patch 1
  3. * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
  4. *
  5. * Permission is hereby granted, free of charge, to any person obtaining a copy of
  6. * this software and associated documentation files (the "Software"), to deal in
  7. * the Software without restriction, including without limitation the rights to
  8. * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  9. * the Software, and to permit persons to whom the Software is furnished to do so,
  10. * subject to the following conditions:
  11. *
  12. * The above copyright notice and this permission notice shall be included in all
  13. * copies or substantial portions of the Software.
  14. *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  17. * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  18. * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  19. * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  20. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  21. *
  22. * http://aws.amazon.com/freertos
  23. * http://www.FreeRTOS.org
  24. */
  25. /**
  26. * @file FreeRTOS_DHCP.c
  27. * @brief Implements the Dynamic Host Configuration Protocol for the FreeRTOS+TCP network stack.
  28. */
  29. /* Standard includes. */
  30. #include <stdint.h>
  31. /* FreeRTOS includes. */
  32. #include "FreeRTOS.h"
  33. #include "task.h"
  34. #include "semphr.h"
  35. /* FreeRTOS+TCP includes. */
  36. #include "FreeRTOS_IP.h"
  37. #include "FreeRTOS_Sockets.h"
  38. #include "FreeRTOS_IP_Private.h"
  39. #include "FreeRTOS_UDP_IP.h"
  40. #include "FreeRTOS_DHCP.h"
  41. #include "FreeRTOS_ARP.h"
  42. /* Exclude the entire file if DHCP is not enabled. */
  43. #if ( ipconfigUSE_DHCP != 0 )
  44. #include "NetworkInterface.h"
  45. #include "NetworkBufferManagement.h"
  46. #if ( ipconfigUSE_DHCP != 0 ) && ( ipconfigNETWORK_MTU < 586U )
  47. /* DHCP must be able to receive an options field of 312 bytes, the fixed
  48. * part of the DHCP packet is 240 bytes, and the IP/UDP headers take 28 bytes. */
  49. #error ipconfigNETWORK_MTU needs to be at least 586 to use DHCP
  50. #endif
  51. /* Parameter widths in the DHCP packet. */
  52. #define dhcpCLIENT_HARDWARE_ADDRESS_LENGTH 16 /**< Client hardware address length.*/
  53. #define dhcpSERVER_HOST_NAME_LENGTH 64 /**< Server host name length. */
  54. #define dhcpBOOT_FILE_NAME_LENGTH 128 /**< Boot file name length. */
  55. /* Timer parameters */
  56. #ifndef dhcpINITIAL_TIMER_PERIOD
  57. /** @brief The interval at which the DHCP state handler is called. */
  58. #define dhcpINITIAL_TIMER_PERIOD ( pdMS_TO_TICKS( 250U ) )
  59. #endif
  60. #ifndef dhcpINITIAL_DHCP_TX_PERIOD
  61. /** @brief The initial amount of time to wait for a DHCP reply. When repeating an
  62. * unanswered request, this time-out shall be multiplied by 2. */
  63. #define dhcpINITIAL_DHCP_TX_PERIOD ( pdMS_TO_TICKS( 5000U ) )
  64. #endif
  65. /* Codes of interest found in the DHCP options field. */
  66. #define dhcpIPv4_ZERO_PAD_OPTION_CODE ( 0U ) /**< Used to pad other options to make them aligned. See RFC 2132. */
  67. #define dhcpIPv4_SUBNET_MASK_OPTION_CODE ( 1U ) /**< Subnet mask. See RFC 2132. */
  68. #define dhcpIPv4_GATEWAY_OPTION_CODE ( 3U ) /**< Available routers. See RFC 2132. */
  69. #define dhcpIPv4_DNS_SERVER_OPTIONS_CODE ( 6U ) /**< Domain name server. See RFC 2132. */
  70. #define dhcpIPv4_DNS_HOSTNAME_OPTIONS_CODE ( 12U ) /**< Host name. See RFC 2132. */
  71. #define dhcpIPv4_REQUEST_IP_ADDRESS_OPTION_CODE ( 50U ) /**< Requested IP-address. See RFC 2132. */
  72. #define dhcpIPv4_LEASE_TIME_OPTION_CODE ( 51U ) /**< IP-address lease time. See RFC 2132. */
  73. #define dhcpIPv4_MESSAGE_TYPE_OPTION_CODE ( 53U ) /**< DHCP message type. See RFC 2132. */
  74. #define dhcpIPv4_SERVER_IP_ADDRESS_OPTION_CODE ( 54U ) /**< Server Identifier. See RFC 2132. */
  75. #define dhcpIPv4_PARAMETER_REQUEST_OPTION_CODE ( 55U ) /**< Parameter Request list. See RFC 2132. */
  76. #define dhcpIPv4_CLIENT_IDENTIFIER_OPTION_CODE ( 61U ) /**< Client Identifier. See RFC 2132. */
  77. /* The four DHCP message types of interest. */
  78. #define dhcpMESSAGE_TYPE_DISCOVER ( 1 ) /**< DHCP discover message. */
  79. #define dhcpMESSAGE_TYPE_OFFER ( 2 ) /**< DHCP offer message. */
  80. #define dhcpMESSAGE_TYPE_REQUEST ( 3 ) /**< DHCP request message. */
  81. #define dhcpMESSAGE_TYPE_ACK ( 5 ) /**< DHCP acknowledgement. */
  82. #define dhcpMESSAGE_TYPE_NACK ( 6 ) /**< DHCP NACK. (Negative acknowledgement) */
  83. /* Offsets into the transmitted DHCP options fields at which various parameters
  84. * are located. */
  85. #define dhcpCLIENT_IDENTIFIER_OFFSET ( 6U ) /**< Offset for the client ID option. */
  86. #define dhcpREQUESTED_IP_ADDRESS_OFFSET ( 14U ) /**< Offset for the requested IP-address option. */
  87. #define dhcpDHCP_SERVER_IP_ADDRESS_OFFSET ( 20U ) /**< Offset for the server IP-address option. */
  88. /* Values used in the DHCP packets. */
  89. #define dhcpREQUEST_OPCODE ( 1U ) /**< DHCP request opcode. */
  90. #define dhcpREPLY_OPCODE ( 2U ) /**< DHCP reply opcode. */
  91. #define dhcpADDRESS_TYPE_ETHERNET ( 1U ) /**< Address type: ethernet opcode. */
  92. #define dhcpETHERNET_ADDRESS_LENGTH ( 6U ) /**< Ethernet address length opcode. */
  93. /* The following define is temporary and serves to make the /single source
  94. * code more similar to the /multi version. */
  95. #define EP_DHCPData xDHCPData /**< Temporary define to make /single source similar to /multi version. */
  96. #define EP_IPv4_SETTINGS xNetworkAddressing /**< Temporary define to make /single source similar to /multi version. */
  97. /** @brief If a lease time is not received, use the default of two days (48 hours in ticks).
  98. * Can not use pdMS_TO_TICKS() as integer overflow can occur. */
  99. #define dhcpDEFAULT_LEASE_TIME ( ( 48UL * 60UL * 60UL ) * configTICK_RATE_HZ )
  100. /** @brief Don't allow the lease time to be too short. */
  101. #define dhcpMINIMUM_LEASE_TIME ( pdMS_TO_TICKS( 60000UL ) ) /* 60 seconds in ticks. */
  102. /** @brief Marks the end of the variable length options field in the DHCP packet. */
  103. #define dhcpOPTION_END_BYTE 0xffu
  104. /** @brief Offset into a DHCP message at which the first byte of the options is
  105. * located. */
  106. #define dhcpFIRST_OPTION_BYTE_OFFSET ( 0xf0U )
  107. /* Standard DHCP port numbers and magic cookie value.
  108. * DHCPv4 uses UDP port number 68 for clients and port number 67 for servers.
  109. */
  110. #if ( ipconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN )
  111. #define dhcpCLIENT_PORT_IPv4 0x4400U /**< Little endian representation of port 68. */
  112. #define dhcpSERVER_PORT_IPv4 0x4300U /**< Little endian representation of port 67. */
  113. #define dhcpCOOKIE 0x63538263UL /**< Little endian representation of magic cookie. */
  114. #define dhcpBROADCAST 0x0080U /**< Little endian representation of broadcast flag. */
  115. #else
  116. #define dhcpCLIENT_PORT_IPv4 0x0044U /**< Big endian representation of port 68. */
  117. #define dhcpSERVER_PORT_IPv4 0x0043U /**< Big endian representation of port 68. */
  118. #define dhcpCOOKIE 0x63825363UL /**< Big endian representation of magic cookie. */
  119. #define dhcpBROADCAST 0x8000U /**< Big endian representation of broadcast flag. */
  120. #endif /* ( ipconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN ) */
  121. #include "pack_struct_start.h"
  122. struct xDHCPMessage_IPv4
  123. {
  124. uint8_t ucOpcode; /**< Operation Code: Specifies the general type of message. */
  125. uint8_t ucAddressType; /**< Hardware type used on the local network. */
  126. uint8_t ucAddressLength; /**< Hardware Address Length: Specifies how long hardware
  127. * addresses are in this message. */
  128. uint8_t ucHops; /**< Hops. */
  129. uint32_t ulTransactionID; /**< A 32-bit identification field generated by the client,
  130. * to allow it to match up the request with replies received
  131. * from DHCP servers. */
  132. uint16_t usElapsedTime; /**< Number of seconds elapsed since a client began an attempt to acquire or renew a lease. */
  133. uint16_t usFlags; /**< Just one bit used to indicate broadcast. */
  134. uint32_t ulClientIPAddress_ciaddr; /**< Client's IP address if it has one or 0 is put in this field. */
  135. uint32_t ulYourIPAddress_yiaddr; /**< The IP address that the server is assigning to the client. */
  136. uint32_t ulServerIPAddress_siaddr; /**< The DHCP server address that the client should use. */
  137. uint32_t ulRelayAgentIPAddress_giaddr; /**< Gateway IP address in case the server client are on different subnets. */
  138. uint8_t ucClientHardwareAddress[ dhcpCLIENT_HARDWARE_ADDRESS_LENGTH ]; /**< The client hardware address. */
  139. uint8_t ucServerHostName[ dhcpSERVER_HOST_NAME_LENGTH ]; /**< Server's hostname. */
  140. uint8_t ucBootFileName[ dhcpBOOT_FILE_NAME_LENGTH ]; /**< Boot file full directory path. */
  141. uint32_t ulDHCPCookie; /**< Magic cookie option. */
  142. /* Option bytes from here on. */
  143. };
  144. #include "pack_struct_end.h"
  145. typedef struct xDHCPMessage_IPv4 DHCPMessage_IPv4_t;
  146. /**
  147. * @brief Function to cast pointers to DHCPMessage_IPv4_t.
  148. */
  149. static portINLINE ipDECL_CAST_PTR_FUNC_FOR_TYPE( DHCPMessage_IPv4_t )
  150. {
  151. return ( DHCPMessage_IPv4_t * ) pvArgument;
  152. }
  153. /**
  154. * @brief Function to cast const pointers to DHCPMessage_IPv4_t.
  155. */
  156. static portINLINE ipDECL_CAST_CONST_PTR_FUNC_FOR_TYPE( DHCPMessage_IPv4_t )
  157. {
  158. return ( const DHCPMessage_IPv4_t * ) pvArgument;
  159. }
  160. /** @brief The UDP socket used for all incoming and outgoing DHCP traffic. */
  161. _static Socket_t xDHCPSocket;
  162. #if ( ipconfigDHCP_FALL_BACK_AUTO_IP != 0 )
  163. /* Define the Link Layer IP address: 169.254.x.x */
  164. #define LINK_LAYER_ADDRESS_0 169
  165. #define LINK_LAYER_ADDRESS_1 254
  166. /* Define the netmask used: 255.255.0.0 */
  167. #define LINK_LAYER_NETMASK_0 255
  168. #define LINK_LAYER_NETMASK_1 255
  169. #define LINK_LAYER_NETMASK_2 0
  170. #define LINK_LAYER_NETMASK_3 0
  171. #endif
  172. /*
  173. * Generate a DHCP discover message and send it on the DHCP socket.
  174. */
  175. static BaseType_t prvSendDHCPDiscover( void );
  176. /*
  177. * Interpret message received on the DHCP socket.
  178. */
  179. _static BaseType_t prvProcessDHCPReplies( BaseType_t xExpectedMessageType );
  180. /*
  181. * Generate a DHCP request packet, and send it on the DHCP socket.
  182. */
  183. static BaseType_t prvSendDHCPRequest( void );
  184. /*
  185. * Prepare to start a DHCP transaction. This initialises some state variables
  186. * and creates the DHCP socket if necessary.
  187. */
  188. static void prvInitialiseDHCP( void );
  189. /*
  190. * Creates the part of outgoing DHCP messages that are common to all outgoing
  191. * DHCP messages.
  192. */
  193. static uint8_t * prvCreatePartDHCPMessage( struct freertos_sockaddr * pxAddress,
  194. BaseType_t xOpcode,
  195. const uint8_t * const pucOptionsArray,
  196. size_t * pxOptionsArraySize );
  197. /*
  198. * Create the DHCP socket, if it has not been created already.
  199. */
  200. _static void prvCreateDHCPSocket( void );
  201. /*
  202. * Close the DHCP socket.
  203. */
  204. static void prvCloseDHCPSocket( void );
  205. /*
  206. * After DHCP has failed to answer, prepare everything to start searching
  207. * for (trying-out) LinkLayer IP-addresses, using the random method: Send
  208. * a gratuitous ARP request and wait if another device responds to it.
  209. */
  210. #if ( ipconfigDHCP_FALL_BACK_AUTO_IP != 0 )
  211. static void prvPrepareLinkLayerIPLookUp( void );
  212. #endif
  213. /*-----------------------------------------------------------*/
  214. /** @brief Hold information in between steps in the DHCP state machine. */
  215. _static DHCPData_t xDHCPData;
  216. int gUseDhcpClient = 0;
  217. void setDhcpClientState(BaseType_t on)
  218. {
  219. gUseDhcpClient = (int)on;
  220. }
  221. int getDhcpClientState()
  222. {
  223. return gUseDhcpClient;
  224. }
  225. /*-----------------------------------------------------------*/
  226. /**
  227. * @brief Check whether a given socket is the DHCP socket or not.
  228. *
  229. * @param[in] xSocket: The socket to be checked.
  230. *
  231. * @return If the socket given as parameter is the DHCP socket - return
  232. * pdTRUE, else pdFALSE.
  233. */
  234. BaseType_t xIsDHCPSocket( Socket_t xSocket )
  235. {
  236. BaseType_t xReturn;
  237. if( xDHCPSocket == xSocket )
  238. {
  239. xReturn = pdTRUE;
  240. }
  241. else
  242. {
  243. xReturn = pdFALSE;
  244. }
  245. return xReturn;
  246. }
  247. /*-----------------------------------------------------------*/
  248. /**
  249. * @brief Returns the current state of a DHCP process.
  250. *
  251. * @return The current state ( eDHCPState_t ) of the DHCP process.
  252. */
  253. eDHCPState_t eGetDHCPState( void )
  254. {
  255. return EP_DHCPData.eDHCPState;
  256. }
  257. /**
  258. * @brief Process the DHCP state machine based on current state.
  259. *
  260. * @param[in] xReset: Is the DHCP state machine starting over? pdTRUE/pdFALSE.
  261. * @param[in] eExpectedState: The function will only run if the state is expected.
  262. */
  263. void vDHCPProcess( BaseType_t xReset,
  264. eDHCPState_t eExpectedState )
  265. {
  266. BaseType_t xGivingUp = pdFALSE;
  267. #if ( ipconfigUSE_DHCP_HOOK != 0 )
  268. eDHCPCallbackAnswer_t eAnswer;
  269. #endif /* ipconfigUSE_DHCP_HOOK */
  270. /* Is DHCP starting over? */
  271. if( xReset != pdFALSE )
  272. {
  273. EP_DHCPData.eDHCPState = eInitialWait;
  274. }
  275. if( ( EP_DHCPData.eDHCPState != eExpectedState ) && ( xReset == pdFALSE ) )
  276. {
  277. /* When the DHCP event was generated, the DHCP client was
  278. * in a different state. Therefore, ignore this event. */
  279. FreeRTOS_debug_printf( ( "DHCP wrong state: expect: %d got: %d : ignore\n",
  280. eExpectedState, EP_DHCPData.eDHCPState ) );
  281. }
  282. else
  283. {
  284. switch( EP_DHCPData.eDHCPState )
  285. {
  286. case eInitialWait:
  287. /* Initial state. Create the DHCP socket, timer, etc. if they
  288. * have not already been created. */
  289. prvInitialiseDHCP();
  290. EP_DHCPData.eDHCPState = eWaitingSendFirstDiscover;
  291. break;
  292. case eWaitingSendFirstDiscover:
  293. /* Ask the user if a DHCP discovery is required. */
  294. #if ( ipconfigUSE_DHCP_HOOK != 0 )
  295. eAnswer = xApplicationDHCPHook( eDHCPPhasePreDiscover, xNetworkAddressing.ulDefaultIPAddress );
  296. if( eAnswer == eDHCPContinue )
  297. #endif /* ipconfigUSE_DHCP_HOOK */
  298. {
  299. /* See if prvInitialiseDHCP() has creates a socket. */
  300. if( xDHCPSocket == NULL )
  301. {
  302. xGivingUp = pdTRUE;
  303. }
  304. else
  305. {
  306. *ipLOCAL_IP_ADDRESS_POINTER = 0UL;
  307. /* Send the first discover request. */
  308. EP_DHCPData.xDHCPTxTime = xTaskGetTickCount();
  309. if( prvSendDHCPDiscover() == pdPASS )
  310. {
  311. EP_DHCPData.eDHCPState = eWaitingOffer;
  312. }
  313. else
  314. {
  315. /* Either the creation of a message buffer failed, or sendto().
  316. * Try again in the next cycle. */
  317. FreeRTOS_debug_printf( ( "Send failed during eWaitingSendFirstDiscover\n" ) );
  318. }
  319. }
  320. }
  321. #if ( ipconfigUSE_DHCP_HOOK != 0 )
  322. else
  323. {
  324. if( eAnswer == eDHCPUseDefaults )
  325. {
  326. ( void ) memcpy( &( xNetworkAddressing ), &( xDefaultAddressing ), sizeof( xNetworkAddressing ) );
  327. }
  328. /* The user indicates that the DHCP process does not continue. */
  329. xGivingUp = pdTRUE;
  330. }
  331. #endif /* ipconfigUSE_DHCP_HOOK */
  332. break;
  333. case eSendDHCPRequest:
  334. if( prvSendDHCPRequest() == pdPASS )
  335. {
  336. /* Send succeeded, go to state 'eWaitingAcknowledge'. */
  337. EP_DHCPData.xDHCPTxTime = xTaskGetTickCount();
  338. EP_DHCPData.xDHCPTxPeriod = dhcpINITIAL_DHCP_TX_PERIOD;
  339. EP_DHCPData.eDHCPState = eWaitingAcknowledge;
  340. }
  341. else
  342. {
  343. /* Either the creation of a message buffer failed, or sendto().
  344. * Try again in the next cycle. */
  345. FreeRTOS_debug_printf( ( "Send failed during eSendDHCPRequest.\n" ) );
  346. }
  347. break;
  348. case eWaitingOffer:
  349. xGivingUp = pdFALSE;
  350. /* Look for offers coming in. */
  351. if( prvProcessDHCPReplies( dhcpMESSAGE_TYPE_OFFER ) == pdPASS )
  352. {
  353. #if ( ipconfigUSE_DHCP_HOOK != 0 )
  354. /* Ask the user if a DHCP request is required. */
  355. eAnswer = xApplicationDHCPHook( eDHCPPhasePreRequest, EP_DHCPData.ulOfferedIPAddress );
  356. if( eAnswer == eDHCPContinue )
  357. #endif /* ipconfigUSE_DHCP_HOOK */
  358. {
  359. /* An offer has been made, the user wants to continue,
  360. * generate the request. */
  361. if( prvSendDHCPRequest() == pdPASS )
  362. {
  363. EP_DHCPData.xDHCPTxTime = xTaskGetTickCount();
  364. EP_DHCPData.xDHCPTxPeriod = dhcpINITIAL_DHCP_TX_PERIOD;
  365. EP_DHCPData.eDHCPState = eWaitingAcknowledge;
  366. }
  367. else
  368. {
  369. /* Either the creation of a message buffer failed, or sendto().
  370. * Try again in the next cycle. */
  371. FreeRTOS_debug_printf( ( "Send failed during eWaitingOffer/1.\n" ) );
  372. EP_DHCPData.eDHCPState = eSendDHCPRequest;
  373. }
  374. break;
  375. }
  376. #if ( ipconfigUSE_DHCP_HOOK != 0 )
  377. if( eAnswer == eDHCPUseDefaults )
  378. {
  379. ( void ) memcpy( &( xNetworkAddressing ), &( xDefaultAddressing ), sizeof( xNetworkAddressing ) );
  380. }
  381. /* The user indicates that the DHCP process does not continue. */
  382. xGivingUp = pdTRUE;
  383. #endif /* ipconfigUSE_DHCP_HOOK */
  384. }
  385. /* Is it time to send another Discover? */
  386. else if( ( xTaskGetTickCount() - EP_DHCPData.xDHCPTxTime ) > EP_DHCPData.xDHCPTxPeriod )
  387. {
  388. /* It is time to send another Discover. Increase the time
  389. * period, and if it has not got to the point of giving up - send
  390. * another discovery. */
  391. EP_DHCPData.xDHCPTxPeriod <<= 1;
  392. if( EP_DHCPData.xDHCPTxPeriod <= ( TickType_t ) ipconfigMAXIMUM_DISCOVER_TX_PERIOD )
  393. {
  394. if( xApplicationGetRandomNumber( &( EP_DHCPData.ulTransactionId ) ) != pdFALSE )
  395. {
  396. EP_DHCPData.xDHCPTxTime = xTaskGetTickCount();
  397. if( EP_DHCPData.xUseBroadcast != pdFALSE )
  398. {
  399. EP_DHCPData.xUseBroadcast = pdFALSE;
  400. }
  401. else
  402. {
  403. EP_DHCPData.xUseBroadcast = pdTRUE;
  404. }
  405. if( prvSendDHCPDiscover() == pdPASS )
  406. {
  407. FreeRTOS_debug_printf( ( "vDHCPProcess: timeout %lu ticks\n", EP_DHCPData.xDHCPTxPeriod ) );
  408. }
  409. else
  410. {
  411. /* Either the creation of a message buffer failed, or sendto().
  412. * Try again in the next cycle. */
  413. FreeRTOS_debug_printf( ( "Send failed during eWaitingOffer/2.\n" ) );
  414. EP_DHCPData.eDHCPState = eInitialWait;
  415. }
  416. }
  417. else
  418. {
  419. FreeRTOS_debug_printf( ( "vDHCPProcess: failed to generate a random Transaction ID\n" ) );
  420. }
  421. }
  422. else
  423. {
  424. FreeRTOS_debug_printf( ( "vDHCPProcess: giving up %lu > %lu ticks\n", EP_DHCPData.xDHCPTxPeriod, ipconfigMAXIMUM_DISCOVER_TX_PERIOD ) );
  425. #if ( ipconfigDHCP_FALL_BACK_AUTO_IP != 0 )
  426. {
  427. /* Only use a fake Ack if the default IP address == 0x00
  428. * and the link local addressing is used. Start searching
  429. * a free LinkLayer IP-address. Next state will be
  430. * 'eGetLinkLayerAddress'. */
  431. prvPrepareLinkLayerIPLookUp();
  432. /* Setting an IP address manually so set to not using
  433. * leased address mode. */
  434. EP_DHCPData.eDHCPState = eGetLinkLayerAddress;
  435. }
  436. #else
  437. {
  438. xGivingUp = pdTRUE;
  439. }
  440. #endif /* ipconfigDHCP_FALL_BACK_AUTO_IP */
  441. }
  442. }
  443. else
  444. {
  445. /* There was no DHCP reply, there was no time-out, just keep on waiting. */
  446. }
  447. break;
  448. case eWaitingAcknowledge:
  449. /* Look for acks coming in. */
  450. if( prvProcessDHCPReplies( dhcpMESSAGE_TYPE_ACK ) == pdPASS )
  451. {
  452. FreeRTOS_debug_printf( ( "vDHCPProcess: acked %lxip\n", FreeRTOS_ntohl( EP_DHCPData.ulOfferedIPAddress ) ) );
  453. /* DHCP completed. The IP address can now be used, and the
  454. * timer set to the lease timeout time. */
  455. *ipLOCAL_IP_ADDRESS_POINTER = EP_DHCPData.ulOfferedIPAddress;
  456. #if ( ipconfigUSE_DHCP_HOOK != 0 )
  457. xApplicationDHCPHook(eDHCPPhaseFinished, EP_DHCPData.ulOfferedIPAddress);
  458. #endif
  459. /* Setting the 'local' broadcast address, something like
  460. * '192.168.1.255'. */
  461. EP_IPv4_SETTINGS.ulBroadcastAddress = ( EP_DHCPData.ulOfferedIPAddress & xNetworkAddressing.ulNetMask ) | ~xNetworkAddressing.ulNetMask;
  462. EP_DHCPData.eDHCPState = eLeasedAddress;
  463. iptraceDHCP_SUCCEDEED( EP_DHCPData.ulOfferedIPAddress );
  464. /* DHCP failed, the default configured IP-address will be used
  465. * Now call vIPNetworkUpCalls() to send the network-up event and
  466. * start the ARP timer. */
  467. vIPNetworkUpCalls();
  468. /* Close socket to ensure packets don't queue on it. */
  469. prvCloseDHCPSocket();
  470. if( EP_DHCPData.ulLeaseTime == 0UL )
  471. {
  472. EP_DHCPData.ulLeaseTime = ( uint32_t ) dhcpDEFAULT_LEASE_TIME;
  473. }
  474. else if( EP_DHCPData.ulLeaseTime < dhcpMINIMUM_LEASE_TIME )
  475. {
  476. EP_DHCPData.ulLeaseTime = dhcpMINIMUM_LEASE_TIME;
  477. }
  478. else
  479. {
  480. /* The lease time is already valid. */
  481. }
  482. /* Check for clashes. */
  483. vARPSendGratuitous();
  484. vIPReloadDHCPTimer( EP_DHCPData.ulLeaseTime );
  485. }
  486. else
  487. {
  488. /* Is it time to send another Discover? */
  489. if( ( xTaskGetTickCount() - EP_DHCPData.xDHCPTxTime ) > EP_DHCPData.xDHCPTxPeriod )
  490. {
  491. /* Increase the time period, and if it has not got to the
  492. * point of giving up - send another request. */
  493. EP_DHCPData.xDHCPTxPeriod <<= 1;
  494. if( EP_DHCPData.xDHCPTxPeriod <= ( TickType_t ) ipconfigMAXIMUM_DISCOVER_TX_PERIOD )
  495. {
  496. EP_DHCPData.xDHCPTxTime = xTaskGetTickCount();
  497. if( prvSendDHCPRequest() == pdPASS )
  498. {
  499. /* The message is sent. Stay in state 'eWaitingAcknowledge'. */
  500. }
  501. else
  502. {
  503. /* Either the creation of a message buffer failed, or sendto().
  504. * Try again in the next cycle. */
  505. FreeRTOS_debug_printf( ( "Send failed during eWaitingAcknowledge.\n" ) );
  506. EP_DHCPData.eDHCPState = eSendDHCPRequest;
  507. }
  508. }
  509. else
  510. {
  511. /* Give up, start again. */
  512. EP_DHCPData.eDHCPState = eInitialWait;
  513. }
  514. }
  515. }
  516. break;
  517. #if ( ipconfigDHCP_FALL_BACK_AUTO_IP != 0 )
  518. case eGetLinkLayerAddress:
  519. if( ( xTaskGetTickCount() - EP_DHCPData.xDHCPTxTime ) > EP_DHCPData.xDHCPTxPeriod )
  520. {
  521. if( xARPHadIPClash == pdFALSE )
  522. {
  523. /* ARP OK. proceed. */
  524. iptraceDHCP_SUCCEDEED( EP_DHCPData.ulOfferedIPAddress );
  525. /* Auto-IP succeeded, the default configured IP-address will
  526. * be used. Now call vIPNetworkUpCalls() to send the
  527. * network-up event and start the ARP timer. */
  528. vIPNetworkUpCalls();
  529. EP_DHCPData.eDHCPState = eNotUsingLeasedAddress;
  530. }
  531. else
  532. {
  533. /* ARP clashed - try another IP address. */
  534. prvPrepareLinkLayerIPLookUp();
  535. /* Setting an IP address manually so set to not using leased
  536. * address mode. */
  537. EP_DHCPData.eDHCPState = eGetLinkLayerAddress;
  538. }
  539. }
  540. break;
  541. #endif /* ipconfigDHCP_FALL_BACK_AUTO_IP */
  542. case eLeasedAddress:
  543. if( FreeRTOS_IsNetworkUp() != 0 )
  544. {
  545. /* Resend the request at the appropriate time to renew the lease. */
  546. prvCreateDHCPSocket();
  547. if( xDHCPSocket != NULL )
  548. {
  549. uint32_t ulID;
  550. if( xApplicationGetRandomNumber( &( ulID ) ) != pdFALSE )
  551. {
  552. EP_DHCPData.ulTransactionId = ulID;
  553. }
  554. EP_DHCPData.xDHCPTxTime = xTaskGetTickCount();
  555. EP_DHCPData.xDHCPTxPeriod = dhcpINITIAL_DHCP_TX_PERIOD;
  556. if( prvSendDHCPRequest() == pdPASS )
  557. {
  558. /* The packet was sent successfully, wait for an acknowledgement. */
  559. EP_DHCPData.eDHCPState = eWaitingAcknowledge;
  560. }
  561. else
  562. {
  563. /* The packet was not sent, try sending it later. */
  564. EP_DHCPData.eDHCPState = eSendDHCPRequest;
  565. FreeRTOS_debug_printf( ( "Send failed eLeasedAddress.\n" ) );
  566. }
  567. /* From now on, we should be called more often */
  568. vIPReloadDHCPTimer( dhcpINITIAL_TIMER_PERIOD );
  569. }
  570. }
  571. else
  572. {
  573. /* See PR #53 on github/freertos/freertos */
  574. FreeRTOS_printf( ( "DHCP: lease time finished but network is down\n" ) );
  575. vIPReloadDHCPTimer( pdMS_TO_TICKS( 5000U ) );
  576. }
  577. break;
  578. case eNotUsingLeasedAddress:
  579. vIPSetDHCPTimerEnableState( pdFALSE );
  580. break;
  581. default:
  582. /* Lint: all options are included. */
  583. break;
  584. }
  585. if( xGivingUp != pdFALSE )
  586. {
  587. /* xGivingUp became true either because of a time-out, or because
  588. * xApplicationDHCPHook() returned another value than 'eDHCPContinue',
  589. * meaning that the conversion is cancelled from here. */
  590. /* Revert to static IP address. */
  591. taskENTER_CRITICAL();
  592. {
  593. *ipLOCAL_IP_ADDRESS_POINTER = xNetworkAddressing.ulDefaultIPAddress;
  594. iptraceDHCP_REQUESTS_FAILED_USING_DEFAULT_IP_ADDRESS( xNetworkAddressing.ulDefaultIPAddress );
  595. }
  596. taskEXIT_CRITICAL();
  597. EP_DHCPData.eDHCPState = eNotUsingLeasedAddress;
  598. vIPSetDHCPTimerEnableState( pdFALSE );
  599. /* DHCP failed, the default configured IP-address will be used. Now
  600. * call vIPNetworkUpCalls() to send the network-up event and start the ARP
  601. * timer. */
  602. vIPNetworkUpCalls();
  603. /* Close socket to ensure packets don't queue on it. */
  604. prvCloseDHCPSocket();
  605. }
  606. }
  607. }
  608. /*-----------------------------------------------------------*/
  609. /**
  610. * @brief Close the DHCP socket.
  611. */
  612. static void prvCloseDHCPSocket( void )
  613. {
  614. if( xDHCPSocket != NULL )
  615. {
  616. /* This modules runs from the IP-task. Use the internal
  617. * function 'vSocketClose()` to close the socket. */
  618. ( void ) vSocketClose( xDHCPSocket );
  619. xDHCPSocket = NULL;
  620. }
  621. }
  622. /*-----------------------------------------------------------*/
  623. /**
  624. * @brief Create a DHCP socket with the defined timeouts.
  625. */
  626. _static void prvCreateDHCPSocket( void )
  627. {
  628. struct freertos_sockaddr xAddress;
  629. BaseType_t xReturn;
  630. TickType_t xTimeoutTime = ( TickType_t ) 0;
  631. /* Create the socket, if it has not already been created. */
  632. if( xDHCPSocket == NULL )
  633. {
  634. xDHCPSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP );
  635. if( xDHCPSocket != FREERTOS_INVALID_SOCKET )
  636. {
  637. /* Ensure the Rx and Tx timeouts are zero as the DHCP executes in the
  638. * context of the IP task. */
  639. ( void ) FreeRTOS_setsockopt( xDHCPSocket, 0, FREERTOS_SO_RCVTIMEO, &( xTimeoutTime ), sizeof( TickType_t ) );
  640. ( void ) FreeRTOS_setsockopt( xDHCPSocket, 0, FREERTOS_SO_SNDTIMEO, &( xTimeoutTime ), sizeof( TickType_t ) );
  641. /* Bind to the standard DHCP client port. */
  642. xAddress.sin_port = ( uint16_t ) dhcpCLIENT_PORT_IPv4;
  643. xReturn = vSocketBind( xDHCPSocket, &xAddress, sizeof( xAddress ), pdFALSE );
  644. if( xReturn != 0 )
  645. {
  646. /* Binding failed, close the socket again. */
  647. prvCloseDHCPSocket();
  648. }
  649. }
  650. else
  651. {
  652. /* Change to NULL for easier testing. */
  653. xDHCPSocket = NULL;
  654. }
  655. }
  656. }
  657. /*-----------------------------------------------------------*/
  658. /**
  659. * @brief Initialise the DHCP state machine by creating DHCP socket and
  660. * begin the transaction.
  661. */
  662. static void prvInitialiseDHCP( void )
  663. {
  664. /* Initialise the parameters that will be set by the DHCP process. Per
  665. * https://www.ietf.org/rfc/rfc2131.txt, Transaction ID should be a random
  666. * value chosen by the client. */
  667. /* Check for random number generator API failure. */
  668. if( xApplicationGetRandomNumber( &( EP_DHCPData.ulTransactionId ) ) != pdFALSE )
  669. {
  670. EP_DHCPData.xUseBroadcast = 0;
  671. EP_DHCPData.ulOfferedIPAddress = 0UL;
  672. EP_DHCPData.ulDHCPServerAddress = 0UL;
  673. EP_DHCPData.xDHCPTxPeriod = dhcpINITIAL_DHCP_TX_PERIOD;
  674. /* Create the DHCP socket if it has not already been created. */
  675. prvCreateDHCPSocket();
  676. FreeRTOS_debug_printf( ( "prvInitialiseDHCP: start after %lu ticks\n", dhcpINITIAL_TIMER_PERIOD ) );
  677. vIPReloadDHCPTimer( dhcpINITIAL_TIMER_PERIOD );
  678. }
  679. else
  680. {
  681. /* There was a problem with the randomiser. */
  682. }
  683. }
  684. /*-----------------------------------------------------------*/
  685. /**
  686. * @brief Process the DHCP replies.
  687. *
  688. * @param[in] xExpectedMessageType: The type of the message the DHCP state machine is expecting.
  689. * Messages of different type will be dropped.
  690. *
  691. * @return pdPASS: if DHCP options are received correctly; pdFAIL: Otherwise.
  692. */
  693. _static BaseType_t prvProcessDHCPReplies( BaseType_t xExpectedMessageType )
  694. {
  695. uint8_t * pucUDPPayload;
  696. int32_t lBytes;
  697. const DHCPMessage_IPv4_t * pxDHCPMessage;
  698. const uint8_t * pucByte;
  699. uint8_t ucOptionCode;
  700. uint32_t ulProcessed, ulParameter;
  701. BaseType_t xReturn = pdFALSE;
  702. const uint32_t ulMandatoryOptions = 2UL; /* DHCP server address, and the correct DHCP message type must be present in the options. */
  703. /* memcpy() helper variables for MISRA Rule 21.15 compliance*/
  704. const void * pvCopySource;
  705. void * pvCopyDest;
  706. /* Passing the address of a pointer (pucUDPPayload) because FREERTOS_ZERO_COPY is used. */
  707. lBytes = FreeRTOS_recvfrom( xDHCPSocket, &pucUDPPayload, 0UL, FREERTOS_ZERO_COPY, NULL, NULL );
  708. if( lBytes > 0 )
  709. {
  710. /* Map a DHCP structure onto the received data. */
  711. pxDHCPMessage = ipCAST_CONST_PTR_TO_CONST_TYPE_PTR( DHCPMessage_IPv4_t, pucUDPPayload );
  712. /* Sanity check. */
  713. if( lBytes < ( int32_t ) sizeof( DHCPMessage_IPv4_t ) )
  714. {
  715. /* Not enough bytes. */
  716. }
  717. else if( ( pxDHCPMessage->ulDHCPCookie != ( uint32_t ) dhcpCOOKIE ) ||
  718. ( pxDHCPMessage->ucOpcode != ( uint8_t ) dhcpREPLY_OPCODE ) )
  719. {
  720. /* Invalid cookie or unexpected opcode. */
  721. }
  722. else if( ( pxDHCPMessage->ulTransactionID != FreeRTOS_htonl( EP_DHCPData.ulTransactionId ) ) )
  723. {
  724. /* Transaction ID does not match. */
  725. }
  726. else /* Looks like a valid DHCP response, with the same transaction ID. */
  727. {
  728. if( memcmp( pxDHCPMessage->ucClientHardwareAddress,
  729. ipLOCAL_MAC_ADDRESS,
  730. sizeof( MACAddress_t ) ) != 0 )
  731. {
  732. /* Target MAC address doesn't match. */
  733. }
  734. else
  735. {
  736. size_t uxIndex, uxPayloadDataLength, uxLength;
  737. /* None of the essential options have been processed yet. */
  738. ulProcessed = 0UL;
  739. /* Walk through the options until the dhcpOPTION_END_BYTE byte
  740. * is found, taking care not to walk off the end of the options. */
  741. pucByte = &( pucUDPPayload[ sizeof( DHCPMessage_IPv4_t ) ] );
  742. uxIndex = 0;
  743. uxPayloadDataLength = ( ( size_t ) lBytes ) - sizeof( DHCPMessage_IPv4_t );
  744. while( uxIndex < uxPayloadDataLength )
  745. {
  746. ucOptionCode = pucByte[ uxIndex ];
  747. if( ucOptionCode == ( uint8_t ) dhcpOPTION_END_BYTE )
  748. {
  749. /* Ready, the last byte has been seen. */
  750. /* coverity[break_stmt] : Break statement terminating the loop */
  751. break;
  752. }
  753. if( ucOptionCode == ( uint8_t ) dhcpIPv4_ZERO_PAD_OPTION_CODE )
  754. {
  755. /* The value zero is used as a pad byte,
  756. * it is not followed by a length byte. */
  757. uxIndex = uxIndex + 1U;
  758. continue;
  759. }
  760. /* Stop if the response is malformed. */
  761. if( ( uxIndex + 1U ) < uxPayloadDataLength )
  762. {
  763. /* Fetch the length byte. */
  764. uxLength = ( size_t ) pucByte[ uxIndex + 1U ];
  765. uxIndex = uxIndex + 2U;
  766. if( !( ( ( uxIndex + uxLength ) - 1U ) < uxPayloadDataLength ) )
  767. {
  768. /* There are not as many bytes left as there should be. */
  769. break;
  770. }
  771. }
  772. else
  773. {
  774. /* The length byte is missing. */
  775. break;
  776. }
  777. /* In most cases, a 4-byte network-endian parameter follows,
  778. * just get it once here and use later. */
  779. if( uxLength >= sizeof( ulParameter ) )
  780. {
  781. /*
  782. * Use helper variables for memcpy() to remain
  783. * compliant with MISRA Rule 21.15. These should be
  784. * optimized away.
  785. */
  786. pvCopySource = &pucByte[ uxIndex ];
  787. pvCopyDest = &ulParameter;
  788. ( void ) memcpy( pvCopyDest, pvCopySource, sizeof( ulParameter ) );
  789. /* 'uxIndex' will be increased at the end of this loop. */
  790. }
  791. else
  792. {
  793. ulParameter = 0;
  794. }
  795. /* Confirm uxIndex is still a valid index after adjustments to uxIndex above */
  796. if( !( uxIndex < uxPayloadDataLength ) )
  797. {
  798. break;
  799. }
  800. /* Option-specific handling. */
  801. switch( ucOptionCode )
  802. {
  803. case dhcpIPv4_MESSAGE_TYPE_OPTION_CODE:
  804. if( pucByte[ uxIndex ] == ( uint8_t ) xExpectedMessageType )
  805. {
  806. /* The message type is the message type the
  807. * state machine is expecting. */
  808. ulProcessed++;
  809. }
  810. else
  811. {
  812. if( pucByte[ uxIndex ] == ( uint8_t ) dhcpMESSAGE_TYPE_NACK )
  813. {
  814. if( xExpectedMessageType == ( BaseType_t ) dhcpMESSAGE_TYPE_ACK )
  815. {
  816. /* Start again. */
  817. EP_DHCPData.eDHCPState = eInitialWait;
  818. }
  819. }
  820. /* Stop processing further options. */
  821. uxLength = 0;
  822. }
  823. break;
  824. case dhcpIPv4_SUBNET_MASK_OPTION_CODE:
  825. if( uxLength == sizeof( uint32_t ) )
  826. {
  827. EP_IPv4_SETTINGS.ulNetMask = ulParameter;
  828. }
  829. break;
  830. case dhcpIPv4_GATEWAY_OPTION_CODE:
  831. /* The DHCP server may send more than 1 gateway addresses. */
  832. if( uxLength >= sizeof( uint32_t ) )
  833. {
  834. /* ulProcessed is not incremented in this case
  835. * because the gateway is not essential. */
  836. EP_IPv4_SETTINGS.ulGatewayAddress = ulParameter;
  837. }
  838. break;
  839. case dhcpIPv4_DNS_SERVER_OPTIONS_CODE:
  840. /* ulProcessed is not incremented in this case
  841. * because the DNS server is not essential. Only the
  842. * first DNS server address is taken. */
  843. EP_IPv4_SETTINGS.ulDNSServerAddress = ulParameter;
  844. break;
  845. case dhcpIPv4_SERVER_IP_ADDRESS_OPTION_CODE:
  846. if( uxLength == sizeof( uint32_t ) )
  847. {
  848. if( xExpectedMessageType == ( BaseType_t ) dhcpMESSAGE_TYPE_OFFER )
  849. {
  850. /* Offers state the replying server. */
  851. ulProcessed++;
  852. EP_DHCPData.ulDHCPServerAddress = ulParameter;
  853. }
  854. else
  855. {
  856. /* The ack must come from the expected server. */
  857. if( EP_DHCPData.ulDHCPServerAddress == ulParameter )
  858. {
  859. ulProcessed++;
  860. }
  861. }
  862. }
  863. break;
  864. case dhcpIPv4_LEASE_TIME_OPTION_CODE:
  865. if( uxLength == sizeof( EP_DHCPData.ulLeaseTime ) )
  866. {
  867. /* ulProcessed is not incremented in this case
  868. * because the lease time is not essential. */
  869. /* The DHCP parameter is in seconds, convert
  870. * to host-endian format. */
  871. EP_DHCPData.ulLeaseTime = FreeRTOS_ntohl( ulParameter );
  872. /* Divide the lease time by two to ensure a renew
  873. * request is sent before the lease actually expires. */
  874. EP_DHCPData.ulLeaseTime >>= 1UL;
  875. /* Multiply with configTICK_RATE_HZ to get clock ticks. */
  876. EP_DHCPData.ulLeaseTime = ( uint32_t ) configTICK_RATE_HZ * ( uint32_t ) EP_DHCPData.ulLeaseTime;
  877. }
  878. break;
  879. default:
  880. /* Not interested in this field. */
  881. break;
  882. }
  883. /* Jump over the data to find the next option code. */
  884. if( uxLength == 0U )
  885. {
  886. break;
  887. }
  888. uxIndex = uxIndex + uxLength;
  889. }
  890. /* Were all the mandatory options received? */
  891. if( ulProcessed >= ulMandatoryOptions )
  892. {
  893. /* HT:endian: used to be network order */
  894. EP_DHCPData.ulOfferedIPAddress = pxDHCPMessage->ulYourIPAddress_yiaddr;
  895. FreeRTOS_printf( ( "vDHCPProcess: offer %lxip\n", FreeRTOS_ntohl( EP_DHCPData.ulOfferedIPAddress ) ) );
  896. xReturn = pdPASS;
  897. }
  898. }
  899. }
  900. FreeRTOS_ReleaseUDPPayloadBuffer( pucUDPPayload );
  901. } /* if( lBytes > 0 ) */
  902. return xReturn;
  903. }
  904. /*-----------------------------------------------------------*/
  905. /**
  906. * @brief Create a partial DHCP message by filling in all the 'constant' fields.
  907. *
  908. * @param[out] pxAddress: Address to be filled in.
  909. * @param[out] xOpcode: Opcode to be filled in the packet. Will always be 'dhcpREQUEST_OPCODE'.
  910. * @param[in] pucOptionsArray: The options to be added to the packet.
  911. * @param[in,out] pxOptionsArraySize: Byte count of the options. Its value might change.
  912. *
  913. * @return Ethernet buffer of the partially created DHCP packet.
  914. */
  915. static uint8_t * prvCreatePartDHCPMessage( struct freertos_sockaddr * pxAddress,
  916. BaseType_t xOpcode,
  917. const uint8_t * const pucOptionsArray,
  918. size_t * pxOptionsArraySize )
  919. {
  920. DHCPMessage_IPv4_t * pxDHCPMessage;
  921. size_t uxRequiredBufferSize = sizeof( DHCPMessage_IPv4_t ) + *pxOptionsArraySize;
  922. const NetworkBufferDescriptor_t * pxNetworkBuffer;
  923. uint8_t * pucUDPPayloadBuffer = NULL;
  924. #if ( ipconfigDHCP_REGISTER_HOSTNAME == 1 )
  925. const char * pucHostName = pcApplicationHostnameHook();
  926. size_t uxNameLength = strlen( pucHostName );
  927. uint8_t * pucPtr;
  928. /* memcpy() helper variables for MISRA Rule 21.15 compliance*/
  929. const void * pvCopySource;
  930. void * pvCopyDest;
  931. /* Two extra bytes for option code and length. */
  932. uxRequiredBufferSize += ( 2U + uxNameLength );
  933. #endif /* if ( ipconfigDHCP_REGISTER_HOSTNAME == 1 ) */
  934. /* Obtain a network buffer with the required amount of storage. It doesn't make much sense
  935. * to use a time-out here, because that would cause the IP-task to wait for itself. */
  936. pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( sizeof( UDPPacket_t ) + uxRequiredBufferSize, 0U );
  937. if( pxNetworkBuffer != NULL )
  938. {
  939. /* Leave space for the UDP header. */
  940. pucUDPPayloadBuffer = &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET_IPv4 ] );
  941. pxDHCPMessage = ipCAST_PTR_TO_TYPE_PTR( DHCPMessage_IPv4_t, pucUDPPayloadBuffer );
  942. /* Most fields need to be zero. */
  943. ( void ) memset( pxDHCPMessage, 0x00, sizeof( DHCPMessage_IPv4_t ) );
  944. /* Create the message. */
  945. pxDHCPMessage->ucOpcode = ( uint8_t ) xOpcode;
  946. pxDHCPMessage->ucAddressType = ( uint8_t ) dhcpADDRESS_TYPE_ETHERNET;
  947. pxDHCPMessage->ucAddressLength = ( uint8_t ) dhcpETHERNET_ADDRESS_LENGTH;
  948. pxDHCPMessage->ulTransactionID = FreeRTOS_htonl( EP_DHCPData.ulTransactionId );
  949. pxDHCPMessage->ulDHCPCookie = ( uint32_t ) dhcpCOOKIE;
  950. if( EP_DHCPData.xUseBroadcast != pdFALSE )
  951. {
  952. pxDHCPMessage->usFlags = ( uint16_t ) dhcpBROADCAST;
  953. }
  954. else
  955. {
  956. pxDHCPMessage->usFlags = 0U;
  957. }
  958. ( void ) memcpy( &( pxDHCPMessage->ucClientHardwareAddress[ 0 ] ), ipLOCAL_MAC_ADDRESS, sizeof( MACAddress_t ) );
  959. /* Copy in the const part of the options options. */
  960. ( void ) memcpy( &( pucUDPPayloadBuffer[ dhcpFIRST_OPTION_BYTE_OFFSET ] ), pucOptionsArray, *pxOptionsArraySize );
  961. #if ( ipconfigDHCP_REGISTER_HOSTNAME == 1 )
  962. {
  963. /* With this option, the hostname can be registered as well which makes
  964. * it easier to lookup a device in a router's list of DHCP clients. */
  965. /* Point to where the OPTION_END was stored to add data. */
  966. pucPtr = &( pucUDPPayloadBuffer[ dhcpFIRST_OPTION_BYTE_OFFSET + ( *pxOptionsArraySize - 1U ) ] );
  967. pucPtr[ 0U ] = dhcpIPv4_DNS_HOSTNAME_OPTIONS_CODE;
  968. pucPtr[ 1U ] = ( uint8_t ) uxNameLength;
  969. /*
  970. * Use helper variables for memcpy() to remain
  971. * compliant with MISRA Rule 21.15. These should be
  972. * optimized away.
  973. */
  974. pvCopySource = pucHostName;
  975. pvCopyDest = &pucPtr[ 2U ];
  976. ( void ) memcpy( pvCopyDest, pvCopySource, uxNameLength );
  977. pucPtr[ 2U + uxNameLength ] = ( uint8_t ) dhcpOPTION_END_BYTE;
  978. *pxOptionsArraySize += ( size_t ) ( 2U + uxNameLength );
  979. }
  980. #endif /* if ( ipconfigDHCP_REGISTER_HOSTNAME == 1 ) */
  981. /* Map in the client identifier. */
  982. ( void ) memcpy( &( pucUDPPayloadBuffer[ dhcpFIRST_OPTION_BYTE_OFFSET + dhcpCLIENT_IDENTIFIER_OFFSET ] ),
  983. ipLOCAL_MAC_ADDRESS, sizeof( MACAddress_t ) );
  984. /* Set the addressing. */
  985. pxAddress->sin_addr = ipBROADCAST_IP_ADDRESS;
  986. pxAddress->sin_port = ( uint16_t ) dhcpSERVER_PORT_IPv4;
  987. }
  988. return pucUDPPayloadBuffer;
  989. }
  990. /*-----------------------------------------------------------*/
  991. /**
  992. * @brief Create and send a DHCP request message through the DHCP socket.
  993. * @return Returns pdPASS when the message is successfully created and sent.
  994. */
  995. static BaseType_t prvSendDHCPRequest( void )
  996. {
  997. BaseType_t xResult = pdFAIL;
  998. uint8_t * pucUDPPayloadBuffer;
  999. struct freertos_sockaddr xAddress;
  1000. static const uint8_t ucDHCPRequestOptions[] =
  1001. {
  1002. /* Do not change the ordering without also changing
  1003. * dhcpCLIENT_IDENTIFIER_OFFSET, dhcpREQUESTED_IP_ADDRESS_OFFSET and
  1004. * dhcpDHCP_SERVER_IP_ADDRESS_OFFSET. */
  1005. dhcpIPv4_MESSAGE_TYPE_OPTION_CODE, 1, dhcpMESSAGE_TYPE_REQUEST, /* Message type option. */
  1006. dhcpIPv4_CLIENT_IDENTIFIER_OPTION_CODE, 7, 1, 0, 0, 0, 0, 0, 0, /* Client identifier. */
  1007. dhcpIPv4_REQUEST_IP_ADDRESS_OPTION_CODE, 4, 0, 0, 0, 0, /* The IP address being requested. */
  1008. dhcpIPv4_SERVER_IP_ADDRESS_OPTION_CODE, 4, 0, 0, 0, 0, /* The IP address of the DHCP server. */
  1009. dhcpOPTION_END_BYTE
  1010. };
  1011. size_t uxOptionsLength = sizeof( ucDHCPRequestOptions );
  1012. /* memcpy() helper variables for MISRA Rule 21.15 compliance*/
  1013. const void * pvCopySource;
  1014. void * pvCopyDest;
  1015. pucUDPPayloadBuffer = prvCreatePartDHCPMessage( &xAddress,
  1016. ( BaseType_t ) dhcpREQUEST_OPCODE,
  1017. ucDHCPRequestOptions,
  1018. &( uxOptionsLength ) );
  1019. if( pucUDPPayloadBuffer != NULL )
  1020. {
  1021. /* Copy in the IP address being requested. */
  1022. /*
  1023. * Use helper variables for memcpy() source & dest to remain
  1024. * compliant with MISRA Rule 21.15. These should be
  1025. * optimized away.
  1026. */
  1027. pvCopySource = &EP_DHCPData.ulOfferedIPAddress;
  1028. pvCopyDest = &pucUDPPayloadBuffer[ dhcpFIRST_OPTION_BYTE_OFFSET + dhcpREQUESTED_IP_ADDRESS_OFFSET ];
  1029. ( void ) memcpy( pvCopyDest, pvCopySource, sizeof( EP_DHCPData.ulOfferedIPAddress ) );
  1030. /* Copy in the address of the DHCP server being used. */
  1031. pvCopySource = &EP_DHCPData.ulDHCPServerAddress;
  1032. pvCopyDest = &pucUDPPayloadBuffer[ dhcpFIRST_OPTION_BYTE_OFFSET + dhcpDHCP_SERVER_IP_ADDRESS_OFFSET ];
  1033. ( void ) memcpy( pvCopyDest, pvCopySource, sizeof( EP_DHCPData.ulDHCPServerAddress ) );
  1034. FreeRTOS_debug_printf( ( "vDHCPProcess: reply %lxip\n", FreeRTOS_ntohl( EP_DHCPData.ulOfferedIPAddress ) ) );
  1035. iptraceSENDING_DHCP_REQUEST();
  1036. if( FreeRTOS_sendto( xDHCPSocket, pucUDPPayloadBuffer, sizeof( DHCPMessage_IPv4_t ) + uxOptionsLength, FREERTOS_ZERO_COPY, &xAddress, sizeof( xAddress ) ) == 0 )
  1037. {
  1038. /* The packet was not successfully queued for sending and must be
  1039. * returned to the stack. */
  1040. FreeRTOS_ReleaseUDPPayloadBuffer( pucUDPPayloadBuffer );
  1041. }
  1042. else
  1043. {
  1044. xResult = pdPASS;
  1045. }
  1046. }
  1047. return xResult;
  1048. }
  1049. /*-----------------------------------------------------------*/
  1050. /**
  1051. * @brief Create and send a DHCP discover packet through the DHCP socket.
  1052. * @return Returns pdPASS when the message is successfully created and sent.
  1053. */
  1054. static BaseType_t prvSendDHCPDiscover( void )
  1055. {
  1056. BaseType_t xResult = pdFAIL;
  1057. uint8_t const * pucUDPPayloadBuffer;
  1058. struct freertos_sockaddr xAddress;
  1059. static const uint8_t ucDHCPDiscoverOptions[] =
  1060. {
  1061. /* Do not change the ordering without also changing dhcpCLIENT_IDENTIFIER_OFFSET. */
  1062. dhcpIPv4_MESSAGE_TYPE_OPTION_CODE, 1, dhcpMESSAGE_TYPE_DISCOVER, /* Message type option. */
  1063. dhcpIPv4_CLIENT_IDENTIFIER_OPTION_CODE, 7, 1, 0, 0, 0, 0, 0, 0, /* Client identifier. */
  1064. dhcpIPv4_PARAMETER_REQUEST_OPTION_CODE, 3, dhcpIPv4_SUBNET_MASK_OPTION_CODE, dhcpIPv4_GATEWAY_OPTION_CODE, dhcpIPv4_DNS_SERVER_OPTIONS_CODE, /* Parameter request option. */
  1065. dhcpOPTION_END_BYTE
  1066. };
  1067. size_t uxOptionsLength = sizeof( ucDHCPDiscoverOptions );
  1068. pucUDPPayloadBuffer = prvCreatePartDHCPMessage( &xAddress,
  1069. ( BaseType_t ) dhcpREQUEST_OPCODE,
  1070. ucDHCPDiscoverOptions,
  1071. &( uxOptionsLength ) );
  1072. if( pucUDPPayloadBuffer != NULL )
  1073. {
  1074. FreeRTOS_debug_printf( ( "vDHCPProcess: discover\n" ) );
  1075. iptraceSENDING_DHCP_DISCOVER();
  1076. if( FreeRTOS_sendto( xDHCPSocket,
  1077. pucUDPPayloadBuffer,
  1078. sizeof( DHCPMessage_IPv4_t ) + uxOptionsLength,
  1079. FREERTOS_ZERO_COPY,
  1080. &( xAddress ),
  1081. sizeof( xAddress ) ) == 0 )
  1082. {
  1083. /* The packet was not successfully queued for sending and must be
  1084. * returned to the stack. */
  1085. FreeRTOS_ReleaseUDPPayloadBuffer( pucUDPPayloadBuffer );
  1086. }
  1087. xResult = pdTRUE;
  1088. }
  1089. return xResult;
  1090. }
  1091. /*-----------------------------------------------------------*/
  1092. #if ( ipconfigDHCP_FALL_BACK_AUTO_IP != 0 )
  1093. /**
  1094. * @brief When DHCP has failed, the code can assign a Link-Layer address, and check if
  1095. * another device already uses the IP-address.
  1096. */
  1097. static void prvPrepareLinkLayerIPLookUp( void )
  1098. {
  1099. uint8_t ucLinkLayerIPAddress[ 2 ];
  1100. uint32_t ulNumbers[ 2 ];
  1101. /* After DHCP has failed to answer, prepare everything to start
  1102. * trying-out LinkLayer IP-addresses, using the random method. */
  1103. EP_DHCPData.xDHCPTxTime = xTaskGetTickCount();
  1104. xApplicationGetRandomNumber( &( ulNumbers[ 0 ] ) );
  1105. xApplicationGetRandomNumber( &( ulNumbers[ 1 ] ) );
  1106. ucLinkLayerIPAddress[ 0 ] = ( uint8_t ) 1 + ( uint8_t ) ( ulNumbers[ 0 ] % 0xFDU ); /* get value 1..254 for IP-address 3rd byte of IP address to try. */
  1107. ucLinkLayerIPAddress[ 1 ] = ( uint8_t ) 1 + ( uint8_t ) ( ulNumbers[ 1 ] % 0xFDU ); /* get value 1..254 for IP-address 4th byte of IP address to try. */
  1108. EP_IPv4_SETTINGS.ulGatewayAddress = 0UL;
  1109. /* prepare xDHCPData with data to test. */
  1110. EP_DHCPData.ulOfferedIPAddress =
  1111. FreeRTOS_inet_addr_quick( LINK_LAYER_ADDRESS_0, LINK_LAYER_ADDRESS_1, ucLinkLayerIPAddress[ 0 ], ucLinkLayerIPAddress[ 1 ] );
  1112. EP_DHCPData.ulLeaseTime = dhcpDEFAULT_LEASE_TIME; /* don't care about lease time. just put anything. */
  1113. EP_IPv4_SETTINGS.ulNetMask =
  1114. FreeRTOS_inet_addr_quick( LINK_LAYER_NETMASK_0, LINK_LAYER_NETMASK_1, LINK_LAYER_NETMASK_2, LINK_LAYER_NETMASK_3 );
  1115. /* DHCP completed. The IP address can now be used, and the
  1116. * timer set to the lease timeout time. */
  1117. *( ipLOCAL_IP_ADDRESS_POINTER ) = EP_DHCPData.ulOfferedIPAddress;
  1118. /* Setting the 'local' broadcast address, something like 192.168.1.255' */
  1119. EP_IPv4_SETTINGS.ulBroadcastAddress = ( EP_DHCPData.ulOfferedIPAddress & EP_IPv4_SETTINGS.ulNetMask ) | ~EP_IPv4_SETTINGS.ulNetMask;
  1120. /* Close socket to ensure packets don't queue on it. not needed anymore as DHCP failed. but still need timer for ARP testing. */
  1121. prvCloseDHCPSocket();
  1122. xApplicationGetRandomNumber( &( ulNumbers[ 0 ] ) );
  1123. EP_DHCPData.xDHCPTxPeriod = pdMS_TO_TICKS( 3000UL + ( ulNumbers[ 0 ] & 0x3ffUL ) ); /* do ARP test every (3 + 0-1024mS) seconds. */
  1124. xARPHadIPClash = pdFALSE; /* reset flag that shows if have ARP clash. */
  1125. vARPSendGratuitous();
  1126. }
  1127. #endif /* ipconfigDHCP_FALL_BACK_AUTO_IP */
  1128. /*-----------------------------------------------------------*/
  1129. #endif /* ipconfigUSE_DHCP != 0 */