PageRenderTime 56ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/platform/FNET/fnet_stack/services/dhcp/fnet_dhcp.c

https://gitlab.com/fuggles/ucos
C | 1331 lines | 795 code | 199 blank | 337 comment | 105 complexity | feefc34b71e028b1806882c461cdac1c MD5 | raw file
Possible License(s): GPL-3.0, LGPL-3.0

Large files files are truncated, but you can click here to view the full file

  1. /**************************************************************************
  2. *
  3. * Copyright 2011-2015 by Andrey Butok. FNET Community.
  4. * Copyright 2008-2010 by Andrey Butok. Freescale Semiconductor, Inc.
  5. *
  6. ***************************************************************************
  7. * This program is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU Lesser General Public License Version 3
  9. * or later (the "LGPL").
  10. *
  11. * As a special exception, the copyright holders of the FNET project give you
  12. * permission to link the FNET sources with independent modules to produce an
  13. * executable, regardless of the license terms of these independent modules,
  14. * and to copy and distribute the resulting executable under terms of your
  15. * choice, provided that you also meet, for each linked independent module,
  16. * the terms and conditions of the license of that module.
  17. * An independent module is a module which is not derived from or based
  18. * on this library.
  19. * If you modify the FNET sources, you may extend this exception
  20. * to your version of the FNET sources, but you are not obligated
  21. * to do so. If you do not wish to do so, delete this
  22. * exception statement from your version.
  23. *
  24. * This program is distributed in the hope that it will be useful,
  25. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  26. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  27. *
  28. * You should have received a copy of the GNU General Public License
  29. * and the GNU Lesser General Public License along with this program.
  30. * If not, see <http://www.gnu.org/licenses/>.
  31. *
  32. **********************************************************************/ /*!
  33. *
  34. * @file fnet_dhcp.c
  35. *
  36. * @author Andrey Butok
  37. *
  38. * @brief DHCP/BOOTP Client implementation.
  39. *
  40. * BOOTP is based on Peter Baertschi contribution (Siemens Building Technologies).
  41. *
  42. ***************************************************************************/
  43. /*
  44. * Boot file name (or two-step bootstrap procedure) is not suported.
  45. */
  46. #include "fnet.h"
  47. #if FNET_CFG_DHCP && FNET_CFG_IP4
  48. #if FNET_CFG_DEBUG_DHCP
  49. #define FNET_DEBUG_DHCP FNET_DEBUG
  50. #else
  51. #define FNET_DEBUG_DHCP(...)
  52. #endif
  53. /************************************************************************
  54. * Definitions
  55. *************************************************************************/
  56. #define FNET_DHCP_OP_BOOTREQUEST (1U)
  57. #define FNET_DHCP_FLAGS_BROADCAST (0x8000U)
  58. #if !FNET_CFG_DHCP_BOOTP /* Not used by BOOTP */
  59. #define FNET_DHCP_OP_BOOTREPLY (2U)
  60. #define FNET_DHCP_LEASE_MAX (0xFFFFFFFFU/(1000U*2U)) /* Maximum lease time value (cause of timer counter is in ms) */
  61. #define FNET_DHCP_STATE_REBOOTING_SEND_TIMEOUT (4U*1000U) /*(ms) timeout for ACK => request retransmission.*/
  62. #define FNET_DHCP_STATE_REBOOTING_TIMEOUT (2U*FNET_DHCP_STATE_REBOOTING_SEND_TIMEOUT) /*(ms) timeout to go to INIT state.*/
  63. #define FNET_DHCP_STATE_RENEWING_SEND_TIMEOUT (60U*1000U) /*(ms) timeout for ACK => request retransmission.*/
  64. #define FNET_DHCP_STATE_REBINDING_SEND_TIMEOUT (60U*1000U) /*(ms) timeout for ACK => request retransmission.*/
  65. #endif /* !FNET_CFG_DHCP_BOOTP */
  66. #define FNET_DHCP_STATE_REQUESTING_SEND_TIMEOUT (4U*1000U) /*(ms) timeout for ACK => request retransmission.*/
  67. #define FNET_DHCP_STATE_REQUESTING_TIMEOUT (4U*FNET_DHCP_STATE_REQUESTING_SEND_TIMEOUT) /*(ms) timeout to go to INIT state.*/
  68. #define FNET_DHCP_STATE_SELECTING_SEND_TIMEOUT (FNET_CFG_DHCP_RESPONSE_TIMEOUT*1000U) /*(ms) timeout for OFFER => INIT.*/
  69. #define FNET_DHCP_ERR_SOCKET_CREATION "ERROR: Socket creation error."
  70. #define FNET_DHCP_ERR_SOCKET_BIND "ERROR: Socket Error during bind."
  71. #define FNET_DHCP_ERR_IS_INITIALIZED "ERROR: DHCP is already initialized."
  72. #define FNET_DHCP_ERR_NONETWORK "ERROR: Network Interface is not configurated."
  73. #define FNET_DHCP_ERR_SERVICE "ERROR: Service registration is failed."
  74. #define FNET_DHCP_ISTIMEOUT (-1)
  75. /************************************************************************
  76. * DHCP Options. [RFC 2132] definitions
  77. *************************************************************************/
  78. #define FNET_DHCP_OPTION_PAD (0U) /* Pad option.*/
  79. #define FNET_DHCP_OPTION_SUBNETMASK (1U) /* Subnet mask.*/
  80. #define FNET_DHCP_OPTION_SUBNETMASK_LENGTH (4U)
  81. #define FNET_DHCP_OPTION_ROUTER (3U) /* Router option (gateway).*/
  82. #define FNET_DHCP_OPTION_ROUTER_MULTIPLE (4U)
  83. #define FNET_DHCP_OPTION_DNS (6U) /* Domain Name Server option. */
  84. #define FNET_DHCP_OPTION_DNS_LENGTH_MIN (4U) /* The minimum length for this option is 4 octets,
  85. * and the length MUST always be a multiple of 4. */
  86. #define FNET_DHCP_OPTION_HOSTNAME (12U) /* Hostname */
  87. #define FNET_DHCP_OPTION_HOSTNAME_LENGTH (32U)
  88. #define FNET_DHCP_OPTION_FILELENGTH (13U) /* File Length */
  89. #define FNET_DHCP_OPTION_FILELENGTH_LENGTH (2U)
  90. #define FNET_DHCP_OPTION_ROOTPATH (17U) /* Rootpath.*/
  91. #define FNET_DHCP_OPTION_ROOTPATH_LENGTH (32U)
  92. #define FNET_DHCP_OPTION_BROADCAST (28U) /* Broadcast Address option. */
  93. #define FNET_DHCP_OPTION_BROADCAST_LENGTH (4U)
  94. #define FNET_DHCP_OPTION_REQ_ADDRESS (50U) /* Requested IP address.*/
  95. #define FNET_DHCP_OPTION_REQ_ADDRESS_LENGTH (4U)
  96. #define FNET_DHCP_OPTION_LEASE (51U) /* IP Address lease time (seconds).*/
  97. #define FNET_DHCP_OPTION_LEASE_LENGTH (4U)
  98. #define FNET_DHCP_OPTION_OVERLOAD (52U) /* Option overload.*/
  99. #define FNET_DHCP_OPTION_OVERLOAD_LENGTH (1U)
  100. #define FNET_DHCP_OPTION_OVERLOAD_NONE (0U)
  101. #define FNET_DHCP_OPTION_OVERLOAD_FILE (1U) /* The 'file' field is used to hold options.*/
  102. #define FNET_DHCP_OPTION_OVERLOAD_SNAME (2U) /* The 'sname' field is used to hold options.*/
  103. #define FNET_DHCP_OPTION_OVERLOAD_BOTH (3U) /* Both fields are used to hold options.*/
  104. #define FNET_DHCP_OPTION_TYPE (53U) /* DHCP Message Type.*/
  105. #define FNET_DHCP_OPTION_TYPE_LENGTH (1U)
  106. #define FNET_DHCP_OPTION_TYPE_DISCOVER (1U)
  107. #define FNET_DHCP_OPTION_TYPE_OFFER (2U)
  108. #define FNET_DHCP_OPTION_TYPE_REQUEST (3U)
  109. #define FNET_DHCP_OPTION_TYPE_DECLINE (4U)
  110. #define FNET_DHCP_OPTION_TYPE_ACK (5U)
  111. #define FNET_DHCP_OPTION_TYPE_NAK (6U)
  112. #define FNET_DHCP_OPTION_TYPE_RELEASE (7U)
  113. #define FNET_DHCP_OPTION_TYPE_INFORM (8U)
  114. #define FNET_DHCP_OPTION_SERVER_ID (54U) /* Server Identifier (ip address).*/
  115. #define FNET_DHCP_OPTION_SERVER_ID_LENGTH (4U)
  116. #define FNET_DHCP_OPTION_PARAMETER_REQ_LIST (55U) /* Parameter Request List. */
  117. #define FNET_DHCP_OPTION_MESSAGE_SIZE (57U) /* Maximum DHCP Message Size. The minimum legal value is 576.*/
  118. #define FNET_DHCP_OPTION_MESSAGE_SIZE_LENGTH (2U)
  119. #define FNET_DHCP_OPTION_T1 (58U) /* Renewal (T1) Time Value.*/
  120. #define FNET_DHCP_OPTION_T1_LENGTH (4U)
  121. #define FNET_DHCP_OPTION_T2 (59U) /* Rebinding (T2) Time Value. */
  122. #define FNET_DHCP_OPTION_T2_LENGTH (4U)
  123. #define FNET_DHCP_OPTION_CLIENT_ID (61U) /* Client-identifier.*/
  124. #define FNET_DHCP_OPTION_CLIENT_ID_LENGTH (sizeof(fnet_mac_addr_t)+1U)
  125. #define FNET_DHCP_OPTION_END (255U) /* End option. */
  126. static const unsigned char fnet_dhcp_magic_cookie [] =
  127. {
  128. 99, 130, 83, 99
  129. }; /* The first four octets of the vendor information
  130. * field have been assigned to the "magic cookie".*/
  131. #define FNET_DHCP_OPTIONS_LENGTH (312U) /* [RFC2131, 2] A DHCP client must be prepared to receive DHCP messages
  132. * with an 'options' field of at least length 312 octets.*/
  133. /**************************************************************************/ /*!
  134. * Private DHCP options.
  135. ******************************************************************************/
  136. struct fnet_dhcp_options_prv
  137. {
  138. unsigned char message_type; /* The DHCP Message Type.
  139. * This option is used to convey the type of the
  140. * last DHCP message.
  141. */
  142. #if FNET_CFG_DHCP_OVERLOAD && !FNET_CFG_DHCP_BOOTP
  143. unsigned char overload; /* Overload Option.
  144. * If this option is present, the DHCP client interprets
  145. * the specified additional fields after it concludes
  146. * interpretation of the standard option fields.
  147. */
  148. #endif
  149. };
  150. /**************************************************************************/ /*!
  151. * All DHCP options are retrieved from a DHCP server.
  152. ******************************************************************************/
  153. struct fnet_dhcp_options_in
  154. {
  155. struct fnet_dhcp_options public_options;
  156. struct fnet_dhcp_options_prv private_options;
  157. };
  158. /************************************************************************
  159. * DHCP header [RFC2131, 2]
  160. *************************************************************************
  161. 0 1 2 3
  162. 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  163. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  164. | op (1) | htype (1) | hlen (1) | hops (1) |
  165. +---------------+---------------+---------------+---------------+
  166. | xid (4) - Transaction ID |
  167. +-------------------------------+-------------------------------+
  168. | secs (2) | flags (2) |
  169. +-------------------------------+-------------------------------+
  170. | ciaddr (4) - client IP addr |
  171. +---------------------------------------------------------------+
  172. | yiaddr (4) - your (client) IP addr |
  173. +---------------------------------------------------------------+
  174. | siaddr (4) - server IP addr |
  175. +---------------------------------------------------------------+
  176. | giaddr (4) - relay aget IP addr |
  177. +---------------------------------------------------------------+
  178. | |
  179. | chaddr (16) - client HW adress. |
  180. | |
  181. | |
  182. +---------------------------------------------------------------+
  183. | |
  184. | sname (64) - server host name |
  185. +---------------------------------------------------------------+
  186. | |
  187. | file (128) - boot file name |
  188. +---------------------------------------------------------------+
  189. | DHCP magic cookie (4) |
  190. +---------------------------------------------------------------+
  191. | |
  192. | options (variable) |
  193. +---------------------------------------------------------------+
  194. | opt end = 0xFF|
  195. +---------------+*/
  196. FNET_COMP_PACKED_BEGIN
  197. typedef struct
  198. {
  199. unsigned char op FNET_COMP_PACKED; /* Message op code / message type:
  200. * 1 = BOOTREQUEST, 2 = BOOTREPLY */
  201. unsigned char htype FNET_COMP_PACKED; /* Hardware address type, see ARP section in "Assigned
  202. * Numbers" RFC; e.g., '1' = 10mb ethernet.*/
  203. unsigned char hlen FNET_COMP_PACKED; /* Hardware address length (e.g. '6' for 10mb ethernet).*/
  204. unsigned char hops FNET_COMP_PACKED; /* Client sets to zero, optionally used by relay agents
  205. * when booting via a relay agent.*/
  206. unsigned long xid FNET_COMP_PACKED; /* Transaction ID, a random number chosen by the
  207. * client, used by the client and server to associate
  208. * messages and responses between a client and a server.*/
  209. unsigned short secs FNET_COMP_PACKED; /* Filled in by client, seconds elapsed since client
  210. * began address acquisition or renewal process.*/
  211. unsigned short flags FNET_COMP_PACKED; /* Flags.*/
  212. fnet_ip4_addr_t ciaddr FNET_COMP_PACKED; /* Client IP address; only filled in if client is in BOUND,
  213. * RENEW or REBINDING state and can respond to ARP requests.*/
  214. fnet_ip4_addr_t yiaddr FNET_COMP_PACKED; /* Your (client) IP address.*/
  215. fnet_ip4_addr_t siaddr FNET_COMP_PACKED; /* IP address of next server to use in bootstrap;
  216. * returned in DHCPOFFER, DHCPACK by server.*/
  217. fnet_ip4_addr_t giaddr FNET_COMP_PACKED; /* Relay agent IP address, used in booting via a relay agent.*/
  218. unsigned char chaddr[16] FNET_COMP_PACKED;/* Client hardware address.*/
  219. unsigned char sname[64] FNET_COMP_PACKED; /* Optional server host name, null terminated string.*/
  220. unsigned char file[128] FNET_COMP_PACKED; /* Boot file name, null terminated string; "generic"
  221. * name or null in DHCPDISCOVER, fully qualified
  222. * directory-path name in DHCPOFFER.*/
  223. char magic_cookie[4] FNET_COMP_PACKED;
  224. unsigned char options[FNET_DHCP_OPTIONS_LENGTH] FNET_COMP_PACKED; /* Optional parameters field. See [RFC2132].*/
  225. } fnet_dhcp_header_t;
  226. FNET_COMP_PACKED_END
  227. /************************************************************************
  228. * DHCP message control structure.
  229. *************************************************************************/
  230. typedef struct
  231. {
  232. unsigned char *next_option_position;
  233. unsigned char *end_position;
  234. fnet_dhcp_header_t header;
  235. } fnet_dhcp_message_t;
  236. /************************************************************************
  237. * DHCP interface interface structure
  238. *************************************************************************/
  239. typedef struct
  240. {
  241. SOCKET socket_client;
  242. fnet_dhcp_state_t state; /* Current state.*/
  243. #if !FNET_CFG_DHCP_BOOTP
  244. unsigned long state_timeout; /* Current State timeout (ticks).*/
  245. fnet_dhcp_state_t state_timeout_next_state; /* Next state on state timeout.*/
  246. unsigned long lease_obtained_time;
  247. #endif
  248. unsigned long state_send_timeout; /* Current State send request timeout (ticks).*/
  249. unsigned long send_request_time; /* Time at which the client sent the REQUEST message */
  250. fnet_mac_addr_t macaddr;
  251. unsigned long xid;
  252. fnet_dhcp_message_t message;
  253. struct fnet_dhcp_params in_params; /* Input user parameters.*/
  254. struct fnet_dhcp_options_in current_options; /* parsed options */
  255. struct fnet_dhcp_options_in offered_options; /* parsed options */
  256. fnet_netif_desc_t netif;
  257. fnet_poll_desc_t service_descriptor;
  258. fnet_dhcp_handler_updated_t handler_updated; /* Optional ponter to the handler
  259. * callback function, that is
  260. * called when the DHCP client has
  261. * updated the IP parameters.
  262. */
  263. fnet_dhcp_handler_discover_t handler_discover; /* Optional pointer to the handler
  264. * callback function, that is
  265. * called when the DHCP client send
  266. * the DHCP discover message.
  267. */
  268. void *handler_discover_param; /* Optional user-application specific parameter.
  269. * It's passed to @ref fnet_dhcp_handler_discover_t.
  270. */
  271. void *handler_updated_param; /* Optional user-application specific parameter.
  272. * It's passed to @ref fnet_dhcp_handler_updated_t
  273. * event handler.
  274. */
  275. } fnet_dhcp_if_t;
  276. /* DHCP client interface */
  277. static fnet_dhcp_if_t fnet_dhcp_if;
  278. /* List of dhcp parameter/options we request.*/
  279. static const char fnet_dhcp_parameter_request_list [] =
  280. {
  281. FNET_DHCP_OPTION_SUBNETMASK,
  282. FNET_DHCP_OPTION_ROUTER,
  283. #if FNET_CFG_DNS
  284. FNET_DHCP_OPTION_DNS,
  285. #endif
  286. #if FNET_CFG_DHCP_BROADCAST
  287. FNET_DHCP_OPTION_BROADCAST,
  288. #endif
  289. FNET_DHCP_OPTION_LEASE,
  290. FNET_DHCP_OPTION_T1,
  291. FNET_DHCP_OPTION_T2
  292. };
  293. static int fnet_dhcp_add_option( fnet_dhcp_message_t *message, unsigned char option_code,
  294. unsigned char option_length, void *option_value );
  295. static unsigned char *fnet_dhcp_next_option( fnet_dhcp_message_t *message );
  296. static void fnet_dhcp_parse_options( fnet_dhcp_message_t *message, struct fnet_dhcp_options_in *options );
  297. static int fnet_dhcp_send_message( fnet_dhcp_if_t *dhcp );
  298. static int fnet_dhcp_receive_message( fnet_dhcp_if_t *dhcp, struct fnet_dhcp_options_in *options );
  299. static void fnet_dhcp_apply_params(fnet_dhcp_if_t *dhcp);
  300. static void fnet_dhcp_change_state( fnet_dhcp_if_t *dhcp, fnet_dhcp_state_t state );
  301. static void fnet_dhcp_state_machine( void *fnet_dhcp_if_p );
  302. #if FNET_CFG_DEBUG_DHCP /* Debug functions */
  303. /************************************************************************
  304. * NAME: fnet_dhcp_print_header
  305. *
  306. * DESCRIPTION: Print DHCP header. For debug needs.
  307. ************************************************************************/
  308. static void fnet_dhcp_print_header( fnet_dhcp_header_t *header )
  309. {
  310. char ip_str[FNET_IP4_ADDR_STR_SIZE];
  311. int i;
  312. FNET_DEBUG_DHCP("DHCP: Message header:");
  313. FNET_DEBUG_DHCP(" op \t %02X", header->op);
  314. FNET_DEBUG_DHCP(" htype \t %02X", header->htype);
  315. FNET_DEBUG_DHCP(" hlen \t %02X", header->hlen);
  316. FNET_DEBUG_DHCP(" hops \t %02X", header->hops);
  317. FNET_DEBUG_DHCP(" xid \t %08X", fnet_ntohl(header->xid));
  318. FNET_DEBUG_DHCP(" secs \t %04X", fnet_ntohs(header->secs));
  319. FNET_DEBUG_DHCP(" secs \t %04X", fnet_ntohs(header->flags));
  320. fnet_inet_ntoa(*(struct in_addr *)(&header->ciaddr), ip_str);
  321. FNET_DEBUG_DHCP(" ciaddr \t %s", ip_str);
  322. fnet_inet_ntoa(*(struct in_addr *)(&header->yiaddr), ip_str);
  323. FNET_DEBUG_DHCP(" yiaddr \t %s", ip_str);
  324. fnet_inet_ntoa(*(struct in_addr *)(&header->siaddr), ip_str);
  325. FNET_DEBUG_DHCP(" siaddr \t %s", ip_str);
  326. fnet_inet_ntoa(*(struct in_addr *)(&header->giaddr), ip_str);
  327. FNET_DEBUG_DHCP(" giaddr \t %s", ip_str);
  328. FNET_DEBUG_DHCP(" chaddr \t ");
  329. for (i = 0; i < 16; i++)
  330. FNET_DEBUG_DHCP("%02X", header->chaddr[i]);
  331. FNET_DEBUG_DHCP("");
  332. FNET_DEBUG_DHCP(" sname \t %s", header->sname);
  333. FNET_DEBUG_DHCP(" file \t %s", header->file);
  334. }
  335. /************************************************************************
  336. * NAME: fnet_dhcp_print_state
  337. *
  338. * DESCRIPTION: Print DHCP current state. For debug needs.
  339. ************************************************************************/
  340. static void fnet_dhcp_print_state( fnet_dhcp_if_t *dhcp )
  341. {
  342. FNET_DEBUG_DHCP("\nDHCP: State ");
  343. switch(dhcp->state)
  344. {
  345. case FNET_DHCP_STATE_DISABLED:
  346. FNET_DEBUG_DHCP("DISABLED");
  347. break;
  348. case FNET_DHCP_STATE_INIT:
  349. FNET_DEBUG_DHCP("INIT");
  350. break;
  351. case FNET_DHCP_STATE_SELECTING:
  352. FNET_DEBUG_DHCP("SELECTING");
  353. break;
  354. case FNET_DHCP_STATE_BOUND:
  355. FNET_DEBUG_DHCP("BOUND");
  356. break;
  357. #if !FNET_CFG_DHCP_BOOTP
  358. case FNET_DHCP_STATE_REQUESTING:
  359. FNET_DEBUG_DHCP("REQUESTING");
  360. break;
  361. case FNET_DHCP_STATE_RENEWING:
  362. FNET_DEBUG_DHCP("RENEWING");
  363. break;
  364. case FNET_DHCP_STATE_REBINDING:
  365. FNET_DEBUG_DHCP("REBINDING");
  366. break;
  367. case FNET_DHCP_STATE_INIT_REBOOT:
  368. FNET_DEBUG_DHCP("INIT_REBOOT");
  369. break;
  370. case FNET_DHCP_STATE_REBOOTING:
  371. FNET_DEBUG_DHCP("REBOOTING");
  372. break;
  373. case FNET_DHCP_STATE_RELEASE:
  374. FNET_DEBUG_DHCP("RELEASE");
  375. break;
  376. #endif /* !FNET_CFG_DHCP_BOOTP */
  377. }
  378. }
  379. /************************************************************************
  380. * NAME: fnet_dhcp_print_options
  381. *
  382. * DESCRIPTION: Print DHCP options. For debug needs.
  383. ************************************************************************/
  384. static void fnet_dhcp_print_options( struct fnet_dhcp_options_in *options )
  385. {
  386. char ip_str[FNET_IP4_ADDR_STR_SIZE];
  387. FNET_DEBUG_DHCP("DHCP: Options:");
  388. FNET_DEBUG_DHCP(" message_type \t\t %02X", options->private_options.message_type);
  389. fnet_inet_ntoa(*(struct in_addr *)(&options->public_options.ip_address), ip_str);
  390. FNET_DEBUG_DHCP(" ip_address \t\t %s", ip_str);
  391. fnet_inet_ntoa(*(struct in_addr *)(&options->public_options.dhcp_server), ip_str);
  392. FNET_DEBUG_DHCP(" dhcp_server \t %s", ip_str);
  393. fnet_inet_ntoa(*(struct in_addr *)(&options->public_options.netmask), ip_str);
  394. FNET_DEBUG_DHCP(" netmask \t\t %s", ip_str);
  395. #if FNET_CFG_DHCP_BROADCAST
  396. fnet_inet_ntoa(*(struct in_addr *)(&options->public_options.broadcast), ip_str);
  397. FNET_DEBUG_DHCP(" broadcast \t\t %s", ip_str);
  398. #endif
  399. fnet_inet_ntoa(*(struct in_addr *)(&options->public_options.gateway), ip_str);
  400. FNET_DEBUG_DHCP(" gateway \t\t %s", ip_str);
  401. FNET_DEBUG_DHCP(" t1 \t\t\t 0x%08X", fnet_ntohl(options->public_options.t1));
  402. FNET_DEBUG_DHCP(" t2 \t\t\t 0x%08X", fnet_ntohl(options->public_options.t2));
  403. FNET_DEBUG_DHCP(" lease_time \t\t 0x%08X", options->public_options.lease_time);
  404. #if FNET_CFG_DHCP_OVERLOAD
  405. FNET_DEBUG_DHCP(" overload \t\t 0x%02X", options->public_options.overload);
  406. #endif
  407. }
  408. #else
  409. #define fnet_dhcp_print_header(x) do{}while(0)
  410. #define fnet_dhcp_print_state(x) do{}while(0)
  411. #define fnet_dhcp_print_options(x) do{}while(0)
  412. #endif /* FNET_CFG_DEBUG_DHCP */
  413. /************************************************************************
  414. * NAME: fnet_dhcp_add_option
  415. *
  416. * DESCRIPTION: Add option to a DHCP options field.
  417. ************************************************************************/
  418. static int fnet_dhcp_add_option( fnet_dhcp_message_t *message, unsigned char option_code,
  419. unsigned char option_length, void *option_value )
  420. {
  421. if((&message->header.options[FNET_DHCP_OPTIONS_LENGTH] - message->next_option_position)
  422. < (unsigned int)(option_length + 2U))
  423. return 1;
  424. *message->next_option_position++ = option_code;
  425. *message->next_option_position++ = option_length;
  426. fnet_memcpy(message->next_option_position, option_value, (unsigned int)option_length);
  427. message->next_option_position += option_length;
  428. return 0;
  429. }
  430. /************************************************************************
  431. * NAME: fnet_dhcp_next_option
  432. *
  433. * DESCRIPTION: Go to the next DHCP option.
  434. ************************************************************************/
  435. static unsigned char *fnet_dhcp_next_option( fnet_dhcp_message_t *message )
  436. {
  437. unsigned char *current_position = message->next_option_position;
  438. unsigned char length;
  439. unsigned char *result = FNET_NULL;
  440. /* Check for the end of DHCP packet.
  441. * as we don't want try to access an unmapped memory.*/
  442. if(current_position + 1 >= message->end_position)
  443. goto EXIT;
  444. /* Skip pad options.*/
  445. while(*current_position == FNET_DHCP_OPTION_PAD)
  446. if(++current_position >= message->end_position)
  447. goto EXIT;
  448. /* Check End option.*/
  449. if(*current_position == FNET_DHCP_OPTION_END)
  450. goto EXIT;
  451. length = *(current_position + 1);
  452. /* Check Option Length overflow.*/
  453. if(current_position + length + 2 > message->end_position)
  454. goto EXIT;
  455. message->next_option_position = current_position + length + 2;
  456. result = current_position;
  457. EXIT:
  458. return result;
  459. }
  460. /************************************************************************
  461. * NAME: fnet_dhcp_parse_options
  462. *
  463. * DESCRIPTION: Parse DHCP options from message.
  464. ************************************************************************/
  465. static void fnet_dhcp_parse_options( fnet_dhcp_message_t *message, struct fnet_dhcp_options_in *options )
  466. {
  467. unsigned char *current_option;
  468. while((current_option = fnet_dhcp_next_option(message)) != 0)
  469. {
  470. unsigned char *option_data = current_option + 2;
  471. unsigned char option_length = *(current_option + 1);
  472. switch(*current_option)
  473. {
  474. case FNET_DHCP_OPTION_SERVER_ID:
  475. if(option_length == FNET_DHCP_OPTION_SERVER_ID_LENGTH)
  476. options->public_options.dhcp_server.s_addr = *(unsigned long *)option_data;
  477. break;
  478. case FNET_DHCP_OPTION_SUBNETMASK:
  479. if(option_length == FNET_DHCP_OPTION_SUBNETMASK_LENGTH)
  480. options->public_options.netmask.s_addr = *(unsigned long *)option_data;
  481. break;
  482. case FNET_DHCP_OPTION_ROUTER:
  483. if(option_length >= FNET_DHCP_OPTION_ROUTER_MULTIPLE)
  484. options->public_options.gateway.s_addr = *(unsigned long *)option_data;
  485. break;
  486. #if FNET_CFG_DHCP_BROADCAST
  487. case FNET_DHCP_OPTION_BROADCAST:
  488. if(option_length == FNET_DHCP_OPTION_BROADCAST_LENGTH)
  489. options->public_options.broadcast.s_addr = *(unsigned long *)option_data;
  490. break;
  491. #endif
  492. #if FNET_CFG_DNS
  493. case FNET_DHCP_OPTION_DNS:
  494. if(option_length >= FNET_DHCP_OPTION_DNS_LENGTH_MIN)
  495. options->public_options.dns.s_addr = *(unsigned long *)option_data;
  496. break;
  497. #endif
  498. #if !FNET_CFG_DHCP_BOOTP
  499. case FNET_DHCP_OPTION_TYPE:
  500. if(option_length == FNET_DHCP_OPTION_TYPE_LENGTH)
  501. options->private_options.message_type = *option_data;
  502. break;
  503. case FNET_DHCP_OPTION_LEASE:
  504. if(option_length == FNET_DHCP_OPTION_LEASE_LENGTH)
  505. options->public_options.lease_time = *(unsigned long *)option_data;
  506. break;
  507. #if FNET_CFG_DHCP_OVERLOAD
  508. case FNET_DHCP_OPTION_OVERLOAD:
  509. if(option_length == FNET_DHCP_OPTION_OVERLOAD_LENGTH
  510. && *option_data <= FNET_DHCP_OPTION_OVERLOAD_BOTH)
  511. options->private_options.overload = *option_data;
  512. break;
  513. #endif
  514. case FNET_DHCP_OPTION_T1:
  515. if(option_length == FNET_DHCP_OPTION_T1_LENGTH)
  516. options->public_options.t1 = *(unsigned long *)option_data;
  517. break;
  518. case FNET_DHCP_OPTION_T2:
  519. if(option_length == FNET_DHCP_OPTION_T2_LENGTH)
  520. options->public_options.t2 = *(unsigned long *)option_data;
  521. break;
  522. #endif /* !FNET_CFG_DHCP_BOOTP */
  523. /* Todo Other Options. */
  524. }
  525. }
  526. }
  527. /************************************************************************
  528. * NAME: fnet_dhcp_send_message
  529. *
  530. * DESCRIPTION: Send DHCP message.
  531. ************************************************************************/
  532. static int fnet_dhcp_send_message( fnet_dhcp_if_t *dhcp )
  533. {
  534. fnet_dhcp_message_t *message = &dhcp->message;
  535. struct sockaddr addr_send;
  536. unsigned int length;
  537. struct in_addr ip_address;
  538. #if !FNET_CFG_DHCP_BOOTP
  539. unsigned short max_message_size;
  540. unsigned char client_id[FNET_DHCP_OPTION_CLIENT_ID_LENGTH];
  541. unsigned char message_type;
  542. #endif
  543. fnet_memset_zero(&message->header, sizeof(message->header));
  544. message->header.op = FNET_DHCP_OP_BOOTREQUEST;
  545. message->header.htype = 1U; /* Ethernet */
  546. message->header.hlen = sizeof(dhcp->macaddr);
  547. message->header.xid = fnet_htonl(dhcp->xid); /* TBD PFI */
  548. message->header.flags = FNET_HTONS(FNET_DHCP_FLAGS_BROADCAST);
  549. fnet_memcpy(message->header.chaddr, dhcp->macaddr, sizeof(dhcp->macaddr)); /* Client HW address */
  550. /* Add "magic cookie" */
  551. fnet_memcpy(message->header.magic_cookie, fnet_dhcp_magic_cookie, sizeof(fnet_dhcp_magic_cookie));
  552. message->next_option_position = message->header.options;
  553. /* Add options */
  554. switch(dhcp->state)
  555. {
  556. #if FNET_CFG_DHCP_BOOTP
  557. case FNET_DHCP_STATE_SELECTING: /*=>Requesting*/
  558. ip_address.s_addr = INADDR_BROADCAST;
  559. break;
  560. #else /* DHCP */
  561. case FNET_DHCP_STATE_REQUESTING: /*=>Requesting*/
  562. ip_address.s_addr = INADDR_BROADCAST;
  563. fnet_dhcp_add_option(message, FNET_DHCP_OPTION_REQ_ADDRESS,
  564. FNET_DHCP_OPTION_REQ_ADDRESS_LENGTH, &dhcp->offered_options.public_options.ip_address);
  565. fnet_dhcp_add_option(message, FNET_DHCP_OPTION_SERVER_ID,
  566. FNET_DHCP_OPTION_SERVER_ID_LENGTH, &dhcp->offered_options.public_options.dhcp_server);
  567. message_type = FNET_DHCP_OPTION_TYPE_REQUEST;
  568. break;
  569. case FNET_DHCP_STATE_SELECTING:
  570. ip_address.s_addr = INADDR_BROADCAST;
  571. message_type = FNET_DHCP_OPTION_TYPE_DISCOVER;
  572. break;
  573. case FNET_DHCP_STATE_REBOOTING: /*=>Requesting*/
  574. ip_address.s_addr = INADDR_BROADCAST;
  575. fnet_dhcp_add_option(message, FNET_DHCP_OPTION_REQ_ADDRESS,
  576. FNET_DHCP_OPTION_REQ_ADDRESS_LENGTH, &dhcp->in_params.requested_ip_address);
  577. message_type = FNET_DHCP_OPTION_TYPE_REQUEST;
  578. break;
  579. case FNET_DHCP_STATE_RENEWING:
  580. ip_address = dhcp->current_options.public_options.dhcp_server; /* Send REQUEST to leasing server*/
  581. message->header.ciaddr = dhcp->current_options.public_options.ip_address.s_addr;
  582. message_type = FNET_DHCP_OPTION_TYPE_REQUEST;
  583. break;
  584. case FNET_DHCP_STATE_REBINDING:
  585. ip_address.s_addr = INADDR_BROADCAST;
  586. message_type = FNET_DHCP_OPTION_TYPE_REQUEST;
  587. message->header.ciaddr = dhcp->current_options.public_options.ip_address.s_addr;
  588. break;
  589. case FNET_DHCP_STATE_RELEASE:
  590. ip_address = dhcp->current_options.public_options.dhcp_server;
  591. message->header.ciaddr = dhcp->current_options.public_options.ip_address.s_addr;
  592. message_type = FNET_DHCP_OPTION_TYPE_RELEASE;
  593. break;
  594. #endif /* !FNET_CFG_DHCP_BOOTP */
  595. default:
  596. return FNET_ERR;
  597. };
  598. #if FNET_CFG_DHCP_BOOTP
  599. /* Record time when client sent the DHCPREQUEST */
  600. dhcp->send_request_time = fnet_timer_ticks();
  601. #else /* DHCP */
  602. fnet_dhcp_add_option(message, FNET_DHCP_OPTION_TYPE, FNET_DHCP_OPTION_TYPE_LENGTH, &message_type);
  603. if((message_type == FNET_DHCP_OPTION_TYPE_REQUEST) || (message_type == FNET_DHCP_OPTION_TYPE_DISCOVER))
  604. {
  605. /* Record time when client sent the DHCPREQUEST */
  606. dhcp->send_request_time = fnet_timer_ticks();
  607. /* Request a lease time for the IP address */
  608. if(dhcp->in_params.requested_lease_time)
  609. fnet_dhcp_add_option(message, FNET_DHCP_OPTION_LEASE,
  610. FNET_DHCP_OPTION_LEASE_LENGTH, &dhcp->in_params.requested_lease_time);
  611. /* Add Parameter Request list */
  612. fnet_dhcp_add_option(message,
  613. FNET_DHCP_OPTION_PARAMETER_REQ_LIST,
  614. sizeof(fnet_dhcp_parameter_request_list),
  615. (void *) &fnet_dhcp_parameter_request_list);
  616. }
  617. /* Add Maximum DHCP message size option. */
  618. max_message_size = fnet_htons(sizeof(fnet_dhcp_header_t));
  619. fnet_dhcp_add_option(message, FNET_DHCP_OPTION_MESSAGE_SIZE,
  620. FNET_DHCP_OPTION_MESSAGE_SIZE_LENGTH, &max_message_size);
  621. /* Client ID (MAC) option */
  622. client_id[0] = message->header.htype;
  623. fnet_memcpy(&client_id[1], dhcp->macaddr, sizeof(dhcp->macaddr));
  624. fnet_dhcp_add_option(&dhcp->message, FNET_DHCP_OPTION_CLIENT_ID,
  625. FNET_DHCP_OPTION_CLIENT_ID_LENGTH, &client_id);
  626. #endif /* FNET_CFG_DHCP_BOOTP */
  627. /* End Option */
  628. *message->next_option_position++ = FNET_DHCP_OPTION_END;
  629. /* Send message. */
  630. fnet_memset_zero(&addr_send, sizeof(addr_send));
  631. ((struct sockaddr_in *)(&addr_send))->sin_family = AF_INET;
  632. ((struct sockaddr_in *)(&addr_send))->sin_port = FNET_CFG_DHCP_PORT_SERVER;
  633. ((struct sockaddr_in *)(&addr_send))->sin_addr = ip_address;
  634. length = message->next_option_position - (unsigned char *) &message->header;
  635. return sendto(dhcp->socket_client, (char *) &message->header, length, 0, (struct sockaddr *) &addr_send, sizeof(addr_send));
  636. }
  637. /************************************************************************
  638. * NAME: dhcp_receive_message
  639. *
  640. * DESCRIPTION: Receive DHCP message (non blocking).
  641. ************************************************************************/
  642. static int fnet_dhcp_receive_message( fnet_dhcp_if_t *dhcp, struct fnet_dhcp_options_in *options )
  643. {
  644. int size;
  645. struct sockaddr addr_from;
  646. fnet_dhcp_header_t *dhcp_header = &dhcp->message.header;
  647. unsigned int addr_len = sizeof(addr_from);
  648. size = recvfrom(dhcp->socket_client, (char *) dhcp_header, sizeof(fnet_dhcp_header_t),
  649. 0U, (struct sockaddr *) &addr_from, &addr_len);
  650. if(fnet_timer_get_interval(dhcp->send_request_time, fnet_timer_ticks()) < dhcp->state_send_timeout)
  651. {
  652. if((size < (int)(sizeof(fnet_dhcp_header_t) - FNET_DHCP_OPTIONS_LENGTH))
  653. || (dhcp_header->xid != fnet_htonl(dhcp->xid)) /* Is message for us? */
  654. || (dhcp_header->hlen != sizeof(dhcp->macaddr))
  655. || fnet_memcmp(dhcp_header->chaddr, dhcp->macaddr, sizeof(dhcp->macaddr))
  656. || fnet_memcmp(&dhcp_header->magic_cookie[0], fnet_dhcp_magic_cookie,
  657. sizeof(fnet_dhcp_magic_cookie)))
  658. {
  659. size = 0;
  660. }
  661. else
  662. {
  663. fnet_memset_zero(options, sizeof(*options)); /* Clear old options.*/
  664. options->public_options.ip_address.s_addr = dhcp_header->yiaddr; /* our IP address */
  665. /* Parse options field */
  666. dhcp->message.next_option_position = &dhcp_header->options[0];
  667. dhcp->message.end_position = (unsigned char *) dhcp_header + size - 1;
  668. fnet_dhcp_parse_options(&dhcp->message, options);
  669. #if FNET_CFG_DHCP_OVERLOAD && !FNET_CFG_DHCP_BOOTP
  670. /* Parse overload options in sname/file */
  671. if(options->public_options.overload)
  672. {
  673. if(options->public_options.overload & FNET_DHCP_OPTION_OVERLOAD_SNAME)
  674. dhcp->message->next_option_position = &dhcp_header->sname[0];
  675. else
  676. dhcp->message->next_option_position = &dhcp_header->file[0];
  677. if(options->public_options.overload & FNET_DHCP_OPTION_OVERLOAD_FILE)
  678. dhcp->message->end_position = &dhcp_header->file[128];
  679. else
  680. dhcp->message->end_position = &dhcp_header->sname[64];
  681. fnet_dhcp_parse_options(dhcp->message, options);
  682. }
  683. #endif
  684. }
  685. }
  686. else
  687. {
  688. size = FNET_DHCP_ISTIMEOUT;
  689. }
  690. return size;
  691. }
  692. /************************************************************************
  693. * NAME: fnet_dhcp_change_state
  694. *
  695. * DESCRIPTION: Change state of DHCP client.
  696. ************************************************************************/
  697. static void fnet_dhcp_change_state( fnet_dhcp_if_t *dhcp, fnet_dhcp_state_t state )
  698. {
  699. dhcp->state = state;
  700. fnet_dhcp_print_state(dhcp);
  701. switch(state)
  702. {
  703. #if !FNET_CFG_DHCP_BOOTP
  704. case FNET_DHCP_STATE_INIT_REBOOT:
  705. #endif
  706. case FNET_DHCP_STATE_INIT:
  707. fnet_netif_set_ip4_addr(dhcp->netif, 0U); /* Set zero address. DHCP messages broadcast
  708. * by a client prior to that client obtaining
  709. * its IP address must have the source address
  710. * field in IP header set to 0.*/
  711. dhcp->xid++; /* Todo must be random.*/
  712. break;
  713. case FNET_DHCP_STATE_SELECTING:
  714. fnet_dhcp_send_message(dhcp); /* Send DISCOVER */
  715. dhcp->state_send_timeout = FNET_DHCP_STATE_SELECTING_SEND_TIMEOUT
  716. / FNET_TIMER_PERIOD_MS; /* Wait OFFER */
  717. break;
  718. case FNET_DHCP_STATE_BOUND:
  719. #if !FNET_CFG_DHCP_BOOTP
  720. dhcp->state_timeout_next_state = FNET_DHCP_STATE_RENEWING;
  721. dhcp->lease_obtained_time = dhcp->send_request_time;
  722. if(dhcp->current_options.public_options.t1 == FNET_HTONL(FNET_DHCP_LEASE_INFINITY))
  723. dhcp->state_timeout = FNET_DHCP_LEASE_INFINITY;
  724. else
  725. dhcp->state_timeout = (fnet_ntohl(dhcp->current_options.public_options.t1) * 1000U) / FNET_TIMER_PERIOD_MS;
  726. #endif /* !FNET_CFG_DHCP_BOOTP */
  727. break;
  728. #if !FNET_CFG_DHCP_BOOTP
  729. case FNET_DHCP_STATE_REQUESTING:
  730. fnet_dhcp_send_message(dhcp); /* Send REQUEST.*/
  731. dhcp->state_timeout_next_state = FNET_DHCP_STATE_INIT;
  732. dhcp->lease_obtained_time = dhcp->send_request_time;
  733. dhcp->state_send_timeout = FNET_DHCP_STATE_REQUESTING_SEND_TIMEOUT
  734. / FNET_TIMER_PERIOD_MS; /* Wait ACK */
  735. dhcp->state_timeout = FNET_DHCP_STATE_REQUESTING_TIMEOUT / FNET_TIMER_PERIOD_MS;
  736. break;
  737. case FNET_DHCP_STATE_REBOOTING:
  738. fnet_dhcp_send_message(dhcp); /* Send REQUEST.*/
  739. dhcp->state_timeout_next_state = FNET_DHCP_STATE_INIT;
  740. dhcp->lease_obtained_time = dhcp->send_request_time; /* To follow state machine rules.*/
  741. dhcp->state_timeout = FNET_DHCP_STATE_REBOOTING_TIMEOUT / FNET_TIMER_PERIOD_MS;
  742. dhcp->state_send_timeout = FNET_DHCP_STATE_REBOOTING_SEND_TIMEOUT / FNET_TIMER_PERIOD_MS;
  743. break;
  744. case FNET_DHCP_STATE_RENEWING:
  745. fnet_dhcp_send_message(dhcp); /* Send REQUEST.*/
  746. dhcp->state_timeout_next_state = FNET_DHCP_STATE_REBINDING;
  747. dhcp->state_timeout = (fnet_ntohl(dhcp->current_options.public_options.t2) * 1000U)
  748. / FNET_TIMER_PERIOD_MS;
  749. dhcp->state_send_timeout = FNET_DHCP_STATE_RENEWING_SEND_TIMEOUT / FNET_TIMER_PERIOD_MS;
  750. break;
  751. case FNET_DHCP_STATE_REBINDING:
  752. fnet_dhcp_send_message(dhcp); /* Send REQUEST.*/
  753. dhcp->state_timeout_next_state = FNET_DHCP_STATE_INIT;
  754. dhcp->state_timeout = (fnet_ntohl(dhcp->current_options.public_options.lease_time) * 1000U) / FNET_TIMER_PERIOD_MS;
  755. dhcp->state_send_timeout = FNET_DHCP_STATE_REBINDING_SEND_TIMEOUT / FNET_TIMER_PERIOD_MS;
  756. break;
  757. case FNET_DHCP_STATE_RELEASE:
  758. break;
  759. default:
  760. break; /* do nothing, avoid compiler warning "enumeration value not handled in switch" */
  761. #endif /* !FNET_CFG_DHCP_BOOTP */
  762. };
  763. }
  764. /************************************************************************
  765. * NAME: fnet_dhcp_apply_params
  766. *
  767. * DESCRIPTION: Apply DHCP parameters to the interface.
  768. ************************************************************************/
  769. static void fnet_dhcp_apply_params(fnet_dhcp_if_t *dhcp)
  770. {
  771. /* Apply parameters. */
  772. fnet_netif_set_ip4_addr(dhcp->netif, dhcp->current_options.public_options.ip_address.s_addr);
  773. fnet_netif_set_ip4_subnet_mask(dhcp->netif, dhcp->current_options.public_options.netmask.s_addr);
  774. fnet_netif_set_ip4_gateway(dhcp->netif, dhcp->current_options.public_options.gateway.s_addr);
  775. #if FNET_CFG_DNS
  776. fnet_netif_set_ip4_dns(dhcp->netif, dhcp->current_options.public_options.dns.s_addr);
  777. #endif
  778. fnet_netif_set_ip4_addr_automatic(dhcp->netif);
  779. fnet_dhcp_change_state(dhcp, FNET_DHCP_STATE_BOUND); /* => BOUND */
  780. /* Rise event. */
  781. if(dhcp->handler_updated)
  782. dhcp->handler_updated(dhcp->netif, dhcp->handler_updated_param);
  783. }
  784. /************************************************************************
  785. * NAME: fnet_dhcp_state_machine
  786. *
  787. * DESCRIPTION: DHCP client state machine.
  788. ************************************************************************/
  789. /*
  790. State-transition diagram for DHCP clients [RFC 2131]:
  791. -------- -------
  792. | | +-------------------------->| |<-------------------+
  793. | INIT- | | +-------------------->| INIT | |
  794. | REBOOT |DHCPNAK/ +---------->| |<---+ |
  795. | |Restart| | ------- | |
  796. -------- | DHCPNAK/ | | |
  797. | Discard offer | -/Send DHCPDISCOVER |
  798. -/Send DHCPREQUEST | | |
  799. | | | DHCPACK v | |
  800. ----------- | (not accept.)/ ----------- | |
  801. | | | Send DHCPDECLINE | | |
  802. | REBOOTING | | | | SELECTING |<----+ |
  803. | | | / | | |DHCPOFFER/ |
  804. ----------- | / ----------- | |Collect |
  805. | | / | | | replies |
  806. DHCPACK/ | / +----------------+ +-------+ |
  807. Record lease, set| | v Select offer/ |
  808. timers T1, T2 ------------ send DHCPREQUEST | |
  809. | +----->| | DHCPNAK, Lease expired/ |
  810. | | | REQUESTING | Halt network |
  811. DHCPOFFER/ | | | |
  812. Discard ------------ | |
  813. | | | | ----------- |
  814. | +--------+ DHCPACK/ | | |
  815. | Record lease, set -----| REBINDING | |
  816. | timers T1, T2 / | | |
  817. | | DHCPACK/ ----------- |
  818. | v Record lease, set ^ |
  819. +----------------> ------- /timers T1,T2 | |
  820. +----->| |<---+ | |
  821. | | BOUND |<---+ | |
  822. DHCPOFFER, DHCPACK, | | | T2 expires/ DHCPNAK/
  823. DHCPNAK/Discard ------- | Broadcast Halt network
  824. | | | | DHCPREQUEST |
  825. +-------+ | DHCPACK/ | |
  826. T1 expires/ Record lease, set | |
  827. Send DHCPREQUEST timers T1, T2 | |
  828. to leasing server | | |
  829. | ---------- | |
  830. | | |------------+ |
  831. +->| RENEWING | |
  832. | |----------------------------+
  833. ----------
  834. */
  835. /* BOOTP:
  836. BOOTREPLY/
  837. ------- -/Send --------------- Configure client -------
  838. | | BOOTPREQUEST | | and StopTask | |
  839. | INIT |--------------->| BOOTP_REQUEST |------------------->| BOUND |
  840. | | | (SELECTING) | | |
  841. ------- --------------- -------
  842. ^ |
  843. | Timeout/- |
  844. +---------------------------+
  845. */
  846. static void fnet_dhcp_state_machine( void *fnet_dhcp_if_p )
  847. {
  848. fnet_dhcp_if_t *dhcp = (fnet_dhcp_if_t *)fnet_dhcp_if_p;
  849. struct fnet_dhcp_options_in options;
  850. int res;
  851. switch(dhcp->state)
  852. {
  853. /*---- INIT ----------------------------------------------------*/
  854. case FNET_DHCP_STATE_INIT:
  855. /* Todo: The client SHOULD wait a random time between one and ten seconds to
  856. * desynchronize the use of DHCP at startup. */
  857. fnet_dhcp_change_state(dhcp, FNET_DHCP_STATE_SELECTING); /* => SELECTING */
  858. if(dhcp->handler_discover)
  859. dhcp->handler_discover(dhcp->netif, dhcp->handler_discover_param);
  860. break;
  861. /*---- SELECTING --------------------------------------------*/
  862. case FNET_DHCP_STATE_SELECTING:
  863. /* Waiting for OFFER */
  864. res = fnet_dhcp_receive_message(dhcp, &options);
  865. if(res == FNET_DHCP_ISTIMEOUT)
  866. {
  867. fnet_dhcp_change_state(dhcp, FNET_DHCP_STATE_INIT); /* => INIT */
  868. }
  869. #if FNET_CFG_DHCP_BOOTP
  870. else if(res>0)
  871. {
  872. /* Todo: The client SHOULD perform a check on the suggested address
  873. * to ensure that the address is not already in use.*/
  874. fnet_dhcp_print_options(&options);
  875. /* Apply parameters. */
  876. dhcp->current_options = options;
  877. fnet_dhcp_apply_params(dhcp);
  878. }
  879. #else /* DHCP */
  880. else if(res > 0 && options.private_options.message_type == FNET_DHCP_OPTION_TYPE_OFFER)
  881. {
  882. dhcp->offered_options = options; /* Save offered options */
  883. fnet_dhcp_change_state(dhcp, FNET_DHCP_STATE_REQUESTING); /* => REQUESTING */
  884. }
  885. #endif
  886. break;
  887. /*---- BOUND ------------------------------------------------*/
  888. case FNET_DHCP_STATE_BOUND:
  889. #if FNET_CFG_DHCP_BOOTP
  890. fnet_dhcp_release();
  891. #else /* DHCP */
  892. if(fnet_netif_get_ip4_addr_automatic(dhcp->netif)) /* If user changed parameters manually.*/
  893. {
  894. struct sockaddr addr_from;
  895. unsigned int addr_len = sizeof(addr_from);
  896. /* Discard all input data. */
  897. recvfrom(dhcp->socket_client, (char *) &dhcp->message.header, sizeof(fnet_dhcp_header_t),
  898. 0U, (struct sockaddr *) &addr_from, &addr_len);
  899. /* If T1 expired. */
  900. if(fnet_timer_get_interval(dhcp->lease_obtained_time, fnet_timer_ticks()) > dhcp->state_timeout)
  901. {
  902. fnet_dhcp_change_state(dhcp, dhcp->state_timeout_next_state); /* => INIT *…

Large files files are truncated, but you can click here to view the full file