xref: /FreeRTOS-Plus-TCP-v4.0.0/source/include/FreeRTOS_DHCP.h (revision df5aed9e58a72e2489b6c1936788885672c62981)
1 /*
2  * FreeRTOS+TCP <DEVELOPMENT BRANCH>
3  * Copyright (C) 2022 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
4  *
5  * SPDX-License-Identifier: MIT
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy of
8  * this software and associated documentation files (the "Software"), to deal in
9  * the Software without restriction, including without limitation the rights to
10  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11  * the Software, and to permit persons to whom the Software is furnished to do so,
12  * subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in all
15  * copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  *
24  * http://aws.amazon.com/freertos
25  * http://www.FreeRTOS.org
26  */
27 
28 #ifndef FREERTOS_DHCP_H
29 #define FREERTOS_DHCP_H
30 
31 #include "FreeRTOS.h"
32 
33 /* Application level configuration options. */
34 #include "FreeRTOSIPConfig.h"
35 #include "IPTraceMacroDefaults.h"
36 
37 #include "FreeRTOS_Sockets.h"
38 
39 /* *INDENT-OFF* */
40 #ifdef __cplusplus
41     extern "C" {
42 #endif
43 
44 #if ( ipconfigUSE_DHCP != 0 ) && ( ipconfigNETWORK_MTU < 586U )
45 
46 /* DHCP must be able to receive an options field of 312 bytes, the fixed
47  * part of the DHCP packet is 240 bytes, and the IP/UDP headers take 28 bytes. */
48     #error ipconfigNETWORK_MTU needs to be at least 586 to use DHCP
49 #endif
50 
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 
56 /* Timer parameters */
57 #ifndef dhcpINITIAL_TIMER_PERIOD
58     /** @brief The interval at which the DHCP state handler is called. */
59     #define dhcpINITIAL_TIMER_PERIOD    ( pdMS_TO_TICKS( 250U ) )
60 #endif
61 
62 #ifndef dhcpINITIAL_DHCP_TX_PERIOD
63 
64 /** @brief The initial amount of time to wait for a DHCP reply.  When repeating an
65  * unanswered request, this time-out shall be multiplied by 2. */
66     #define dhcpINITIAL_DHCP_TX_PERIOD    ( pdMS_TO_TICKS( 5000U ) )
67 #endif
68 
69 #define dhcpIPv6_CLIENT_DUID_LENGTH                ( 14U )
70 
71 /* Codes of interest found in the DHCP options field. */
72 #define dhcpIPv4_ZERO_PAD_OPTION_CODE              ( 0U )      /**< Used to pad other options to make them aligned. See RFC 2132. */
73 #define dhcpIPv4_SUBNET_MASK_OPTION_CODE           ( 1U )      /**< Subnet mask. See RFC 2132. */
74 #define dhcpIPv4_GATEWAY_OPTION_CODE               ( 3U )      /**< Available routers. See RFC 2132. */
75 #define dhcpIPv4_DNS_SERVER_OPTIONS_CODE           ( 6U )      /**< Domain name server. See RFC 2132. */
76 #define dhcpIPv4_DNS_HOSTNAME_OPTIONS_CODE         ( 12U )     /**< Host name. See RFC 2132. */
77 #define dhcpIPv4_REQUEST_IP_ADDRESS_OPTION_CODE    ( 50U )     /**< Requested IP-address. See RFC 2132. */
78 #define dhcpIPv4_LEASE_TIME_OPTION_CODE            ( 51U )     /**< IP-address lease time. See RFC 2132. */
79 #define dhcpIPv4_MESSAGE_TYPE_OPTION_CODE          ( 53U )     /**< DHCP message type. See RFC 2132. */
80 #define dhcpIPv4_SERVER_IP_ADDRESS_OPTION_CODE     ( 54U )     /**< Server Identifier. See RFC 2132. */
81 #define dhcpIPv4_PARAMETER_REQUEST_OPTION_CODE     ( 55U )     /**< Parameter Request list. See RFC 2132. */
82 #define dhcpIPv4_CLIENT_IDENTIFIER_OPTION_CODE     ( 61U )     /**<  Client Identifier. See RFC 2132. */
83 
84 /* The four DHCP message types of interest. */
85 #define dhcpMESSAGE_TYPE_DISCOVER                  ( 1 )     /**< DHCP discover message. */
86 #define dhcpMESSAGE_TYPE_OFFER                     ( 2 )     /**< DHCP offer message. */
87 #define dhcpMESSAGE_TYPE_REQUEST                   ( 3 )     /**< DHCP request message. */
88 #define dhcpMESSAGE_TYPE_ACK                       ( 5 )     /**< DHCP acknowledgement. */
89 #define dhcpMESSAGE_TYPE_NACK                      ( 6 )     /**< DHCP NACK. (Negative acknowledgement) */
90 
91 /* Offsets into the transmitted DHCP options fields at which various parameters
92  * are located. */
93 #define dhcpCLIENT_IDENTIFIER_OFFSET               ( 6U )      /**< Offset for the client ID option. */
94 #define dhcpREQUESTED_IP_ADDRESS_OFFSET            ( 14U )     /**< Offset for the requested IP-address option. */
95 #define dhcpDHCP_SERVER_IP_ADDRESS_OFFSET          ( 20U )     /**< Offset for the server IP-address option. */
96 #define dhcpOPTION_50_OFFSET                       ( 12U )     /**< Offset of option-50. */
97 #define dhcpOPTION_50_SIZE                         ( 6U )      /**< Number of bytes included in option-50. */
98 
99 
100 /* Values used in the DHCP packets. */
101 #define dhcpREQUEST_OPCODE              ( 1U )                /**< DHCP request opcode. */
102 #define dhcpREPLY_OPCODE                ( 2U )                /**< DHCP reply opcode. */
103 #define dhcpADDRESS_TYPE_ETHERNET       ( 1U )                /**< Address type: ethernet opcode. */
104 #define dhcpETHERNET_ADDRESS_LENGTH     ( 6U )                /**< Ethernet address length opcode. */
105 
106 /* The following define is temporary and serves to make the /single source
107  * code more similar to the /multi version. TODO */
108 //#define EP_DHCPData                     xDHCPData              /**< Temporary define to make /single source similar to /multi version. */
109 //#define EP_IPv4_SETTINGS                xNetworkAddressing     /**< Temporary define to make /single source similar to /multi version. */
110 
111 /** @brief If a lease time is not received, use the default of two days (48 hours in ticks).
112  * Can not use pdMS_TO_TICKS() as integer overflow can occur. */
113 #define dhcpDEFAULT_LEASE_TIME          ( ( 48UL * 60UL * 60UL ) * configTICK_RATE_HZ )
114 
115 /** @brief Don't allow the lease time to be too short. */
116 #define dhcpMINIMUM_LEASE_TIME          ( pdMS_TO_TICKS( 60000UL ) )            /* 60 seconds in ticks. */
117 
118 /** @brief Marks the end of the variable length options field in the DHCP packet. */
119 #define dhcpOPTION_END_BYTE             0xffu
120 
121 /** @brief Offset into a DHCP message at which the first byte of the options is
122  * located. */
123 #define dhcpFIRST_OPTION_BYTE_OFFSET    ( 0xf0U )
124 
125 /* Standard DHCP port numbers and magic cookie value.
126  * DHCPv4 uses UDP port number 68 for clients and port number 67 for servers.
127  */
128 #if ( ipconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN )
129     #define dhcpCLIENT_PORT_IPv4    0x4400U          /**< Little endian representation of port 68. */
130     #define dhcpSERVER_PORT_IPv4    0x4300U          /**< Little endian representation of port 67. */
131     #define dhcpCOOKIE              0x63538263UL     /**< Little endian representation of magic cookie. */
132     #define dhcpBROADCAST           0x0080U          /**< Little endian representation of broadcast flag. */
133 #else
134     #define dhcpCLIENT_PORT_IPv4    0x0044U          /**< Big endian representation of port 68. */
135     #define dhcpSERVER_PORT_IPv4    0x0043U          /**< Big endian representation of port 67. */
136     #define dhcpCOOKIE              0x63825363UL     /**< Big endian representation of magic cookie. */
137     #define dhcpBROADCAST           0x8000U          /**< Big endian representation of broadcast flag. */
138 #endif /* ( ipconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN ) */
139 
140 #include "pack_struct_start.h"
141 struct xDHCPMessage_IPv4
142 {
143     uint8_t ucOpcode;                                                      /**< Operation Code: Specifies the general type of message. */
144     uint8_t ucAddressType;                                                 /**< Hardware type used on the local network. */
145     uint8_t ucAddressLength;                                               /**< Hardware Address Length: Specifies how long hardware
146                                                                             * addresses are in this message. */
147     uint8_t ucHops;                                                        /**< Hops. */
148     uint32_t ulTransactionID;                                              /**< A 32-bit identification field generated by the client,
149                                                                             * to allow it to match up the request with replies received
150                                                                             * from DHCP servers. */
151     uint16_t usElapsedTime;                                                /**< Number of seconds elapsed since a client began an attempt to acquire or renew a lease. */
152     uint16_t usFlags;                                                      /**< Just one bit used to indicate broadcast. */
153     uint32_t ulClientIPAddress_ciaddr;                                     /**< Client's IP address if it has one or 0 is put in this field. */
154     uint32_t ulYourIPAddress_yiaddr;                                       /**< The IP address that the server is assigning to the client. */
155     uint32_t ulServerIPAddress_siaddr;                                     /**< The DHCP server address that the client should use. */
156     uint32_t ulRelayAgentIPAddress_giaddr;                                 /**< Gateway IP address in case the server client are on different subnets. */
157     uint8_t ucClientHardwareAddress[ dhcpCLIENT_HARDWARE_ADDRESS_LENGTH ]; /**< The client hardware address. */
158     uint8_t ucServerHostName[ dhcpSERVER_HOST_NAME_LENGTH ];               /**< Server's hostname. */
159     uint8_t ucBootFileName[ dhcpBOOT_FILE_NAME_LENGTH ];                   /**< Boot file full directory path. */
160     uint32_t ulDHCPCookie;                                                 /**< Magic cookie option. */
161     /* Option bytes from here on. */
162 }
163 #include "pack_struct_end.h"
164 typedef struct xDHCPMessage_IPv4 DHCPMessage_IPv4_t;
165 
166 
167 #if ( ipconfigUSE_DHCP_HOOK != 0 )
168     /* Used in the DHCP callback if ipconfigUSE_DHCP_HOOK is set to 1. */
169     typedef enum eDHCP_PHASE
170     {
171         eDHCPPhasePreDiscover, /**< Driver is about to send a DHCP discovery. */
172         eDHCPPhasePreRequest   /**< Driver is about to request DHCP an IP address. */
173     } eDHCPCallbackPhase_t;
174 
175 /** @brief Used in the DHCP callback if ipconfigUSE_DHCP_HOOK is set to 1. */
176     typedef enum eDHCP_ANSWERS
177     {
178         eDHCPContinue,      /**< Continue the DHCP process */
179         eDHCPUseDefaults,   /**< Stop DHCP and use the static defaults. */
180         eDHCPStopNoChanges, /**< Stop DHCP and continue with current settings. */
181     } eDHCPCallbackAnswer_t;
182 #endif /* #if( ipconfigUSE_DHCP_HOOK != 0 ) */
183 
184 /** @brief DHCP state machine states. */
185 typedef enum
186 {
187     eInitialWait = 0,          /**< Initial state: open a socket and wait a short time. */
188     eWaitingSendFirstDiscover, /**< Send a discover the first time it is called, and reset all timers. */
189     eWaitingOffer,             /**< Either resend the discover, or, if the offer is forthcoming, send a request. */
190     eWaitingAcknowledge,       /**< Either resend the request. */
191     eSendDHCPRequest,          /**< Sendto failed earlier, resend the request to lease the IP-address offered. */
192     #if ( ipconfigDHCP_FALL_BACK_AUTO_IP != 0 )
193         eGetLinkLayerAddress,  /**< When DHCP didn't respond, try to obtain a LinkLayer address 168.254.x.x. */
194     #endif
195     eLeasedAddress,            /**< Resend the request at the appropriate time to renew the lease. */
196     eNotUsingLeasedAddress     /**< DHCP failed, and a default IP address is being used. */
197 } eDHCPState_t;
198 
199 /** @brief Hold information in between steps in the DHCP state machine. */
200 struct xDHCP_DATA
201 {
202     uint32_t ulTransactionId;      /**< The ID used in all transactions. */
203     uint32_t ulOfferedIPAddress;   /**< The IP-address offered by the DHCP server. */
204     uint32_t ulPreferredIPAddress; /**< A preferred IP address */
205     uint32_t ulDHCPServerAddress;  /**< The IP-address of the DHCP server. */
206     uint32_t ulLeaseTime;          /**< The maximum time that the IP-address can be leased. */
207     /* Hold information on the current timer state. */
208     TickType_t xDHCPTxTime;        /**< The time at which a request was sent, initialised with xTaskGetTickCount(). */
209     TickType_t xDHCPTxPeriod;      /**< The maximum time to wait for a response. */
210     /* Try both without and with the broadcast flag */
211     BaseType_t xUseBroadcast;      /**< pdTRUE if the broadcast bit 'dhcpBROADCAST' must be set. */
212     /* Maintains the DHCP state machine state. */
213     eDHCPState_t eDHCPState;       /**< The current state of the DHCP state machine. */
214     eDHCPState_t eExpectedState;   /**< If the state is not equal the the expected state, no cycle needs to be done. */
215     Socket_t xDHCPSocket;
216     /**< Record latest client ID for DHCPv6. */
217     uint8_t ucClientDUID[ dhcpIPv6_CLIENT_DUID_LENGTH ];
218 };
219 
220 typedef struct xDHCP_DATA DHCPData_t;
221 
222 /** brief: a set of parameters that are passed to helper functions. */
223 typedef struct xProcessSet
224 {
225     uint8_t ucOptionCode;       /**< The code currently being handled. */
226     size_t uxIndex;             /**< The index within 'pucByte'. */
227     size_t uxPayloadDataLength; /**< The number of bytes in the UDP payload. */
228     size_t uxLength;            /**< The size of the current option. */
229     uint32_t ulParameter;       /**< The uint32 value of the answer, if available. */
230     uint32_t ulProcessed;       /**< The number of essential options that were parsed. */
231     const uint8_t * pucByte;    /**< A pointer to the data to be analysed. */
232 } ProcessSet_t;
233 
234 /* Returns the current state of a DHCP process. */
235 eDHCPState_t eGetDHCPState( const struct xNetworkEndPoint * pxEndPoint );
236 
237 /*
238  * NOT A PUBLIC API FUNCTION.
239  * It will be called when the DHCP timer expires, or when
240  * data has been received on the DHCP socket.
241  */
242 void vDHCPProcess( BaseType_t xReset,
243                     struct xNetworkEndPoint * pxEndPoint );
244 
245 /* Internal call: returns true if socket is the current DHCP socket */
246 BaseType_t xIsDHCPSocket( const ConstSocket_t xSocket );
247 
248 
249 #if ( ipconfigUSE_DHCP_HOOK != 0 )
250 
251 /* Prototype of the hook (or callback) function that must be provided by the
252  * application if ipconfigUSE_DHCP_HOOK is set to 1.  See the following URL for
253  * usage information:
254  * http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_IP_Configuration.html#ipconfigUSE_DHCP_HOOK
255  */
256     #if ( ipconfigIPv4_BACKWARD_COMPATIBLE == 1 )
257         eDHCPCallbackAnswer_t xApplicationDHCPHook( eDHCPCallbackPhase_t eDHCPPhase,
258                                                     uint32_t ulIPAddress );
259     #else /* ( ipconfigIPv4_BACKWARD_COMPATIBLE == 1 ) */
260         eDHCPCallbackAnswer_t xApplicationDHCPHook_Multi( eDHCPCallbackPhase_t eDHCPPhase,
261                                                           struct xNetworkEndPoint * pxEndPoint,
262                                                           IP_Address_t * pxIPAddress );
263     #endif /* ( ipconfigIPv4_BACKWARD_COMPATIBLE == 1 ) */
264 #endif /* ( ipconfigUSE_DHCP_HOOK != 0 ) */
265 
266 #if ( ipconfigDHCP_FALL_BACK_AUTO_IP != 0 )
267     struct xNetworkEndPoint;
268 
269 /**
270  * @brief When DHCP has failed, the code can assign a Link-Layer
271  *        address, and check if another device already uses the IP-address.
272  *
273  * param[in] pxEndPoint: The end-point that wants to obtain a link-layer address.
274  */
275     void prvPrepareLinkLayerIPLookUp( struct xNetworkEndPoint * pxEndPoint );
276 #endif
277 
278 /* *INDENT-OFF* */
279 #ifdef __cplusplus
280     } /* extern "C" */
281 #endif
282 /* *INDENT-ON* */
283 
284 #endif /* FREERTOS_DHCP_H */
285