dhcpv6_client.c
Go to the documentation of this file.
1 /**
2  * @file dhcpv6_client.c
3  * @brief DHCPv6 client (Dynamic Host Configuration Protocol for IPv6)
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2026 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @section Description
28  *
29  * The Dynamic Host Configuration Protocol for IPv6 enables DHCP servers to
30  * pass configuration parameters such as IPv6 network addresses to IPv6
31  * nodes. This protocol is a stateful counterpart to IPv6 Stateless Address
32  * Autoconfiguration (RFC 2462), and can be used separately or concurrently
33  * with the latter to obtain configuration parameters. Refer to RFC 3315
34  *
35  * @author Oryx Embedded SARL (www.oryx-embedded.com)
36  * @version 2.6.0
37  **/
38 
39 //Switch to the appropriate trace level
40 #define TRACE_LEVEL DHCPV6_TRACE_LEVEL
41 
42 //Dependencies
43 #include "core/net.h"
44 #include "ipv6/ipv6.h"
45 #include "ipv6/ipv6_misc.h"
46 #include "dhcpv6/dhcpv6_client.h"
48 #include "debug.h"
49 
50 //Check TCP/IP stack configuration
51 #if (IPV6_SUPPORT == ENABLED && DHCPV6_CLIENT_SUPPORT == ENABLED)
52 
53 
54 /**
55  * @brief Initialize settings with default values
56  * @param[out] settings Structure that contains DHCPv6 client settings
57  **/
58 
60 {
61  //Network interface to configure
62  settings->interface = NULL;
63 
64  //Support for quick configuration using rapid commit
65  settings->rapidCommit = FALSE;
66  //Use the DNS servers provided by the DHCPv6 server
67  settings->manualDnsConfig = FALSE;
68  //DHCPv6 configuration timeout
69  settings->timeout = 0;
70 
71  //DHCPv6 configuration timeout event
72  settings->timeoutEvent = NULL;
73  //Link state change event
74  settings->linkChangeEvent = NULL;
75  //FSM state change event
76  settings->stateChangeEvent = NULL;
77 
78  //Add DHCPv6 options callback
79  settings->addOptionsCallback = NULL;
80  //Parse DHCPv6 options callback
81  settings->parseOptionsCallback = NULL;
82 }
83 
84 
85 /**
86  * @brief DHCPv6 client initialization
87  * @param[in] context Pointer to the DHCPv6 client context
88  * @param[in] settings DHCPv6 client specific settings
89  * @return Error code
90  **/
91 
93  const Dhcpv6ClientSettings *settings)
94 {
95  error_t error;
96  NetInterface *interface;
97 
98  //Debug message
99  TRACE_INFO("Initializing DHCPv6 client...\r\n");
100 
101  //Ensure the parameters are valid
102  if(context == NULL || settings == NULL)
104 
105  //The DHCPv6 client must be bound to a valid interface
106  if(settings->interface == NULL)
108 
109  //Point to the underlying network interface
110  interface = settings->interface;
111 
112  //Clear the DHCPv6 client context
113  osMemset(context, 0, sizeof(Dhcpv6ClientContext));
114 
115  //Attach TCP/IP stack context
116  context->netContext = settings->interface->netContext;
117 
118  //Save user settings
119  context->interface = settings->interface;
120  context->rapidCommit = settings->rapidCommit;
121  context->manualDnsConfig = settings->manualDnsConfig;
122  context->configTimeout = settings->timeout;
123  context->timeoutEvent = settings->timeoutEvent;
124  context->linkChangeEvent = settings->linkChangeEvent;
125  context->stateChangeEvent = settings->stateChangeEvent;
126  context->addOptionsCallback = settings->addOptionsCallback;
127  context->parseOptionsCallback = settings->parseOptionsCallback;
128 
129  //Generate client's DUID
130  error = dhcpv6ClientGenerateDuid(context);
131  //any error to report?
132  if(error)
133  return error;
134 
135  //DHCPv6 client is currently suspended
136  context->running = FALSE;
137  //Initialize state machine
138  context->state = DHCPV6_STATE_INIT;
139 
140  //Get exclusive access
141  netLock(context->netContext);
142  //Attach the DHCPv6 client context to the network interface
143  interface->dhcpv6ClientContext = context;
144  //Release exclusive access
145  netUnlock(context->netContext);
146 
147  //Successful initialization
148  return NO_ERROR;
149 }
150 
151 
152 /**
153  * @brief Start DHCPv6 client
154  * @param[in] context Pointer to the DHCPv6 client context
155  * @return Error code
156  **/
157 
159 {
160  error_t error;
161  NetInterface *interface;
162 
163  //Make sure the DHCPv6 client context is valid
164  if(context == NULL)
166 
167  //Debug message
168  TRACE_INFO("Starting DHCPv6 client...\r\n");
169 
170  //Get exclusive access
171  netLock(context->netContext);
172 
173  //Point to the underlying network interface
174  interface = context->interface;
175 
176  //Check the operational state of the DHCPv6 client
177  if(!context->running)
178  {
179  //Flush the list of IPv6 addresses from the client's IA
180  dhcpv6ClientFlushAddrList(context);
181 
182  //Automatic DNS server configuration?
183  if(!context->manualDnsConfig)
184  {
185  //Clear the list of DNS servers
186  ipv6FlushDnsServerList(interface);
187  }
188 
189  //Check if the link is up?
190  if(interface->linkState)
191  {
192  //A link-local address is formed by combining the well-known
193  //link-local prefix fe80::/10 with the interface identifier
195  }
196 
197  //Initialize state machine
198  context->state = DHCPV6_STATE_INIT;
199 
200  //Register the callback function to be called whenever a UDP datagram
201  //is received on port 546
202  error = udpRegisterRxCallback(interface, DHCPV6_CLIENT_PORT,
203  dhcpv6ClientProcessMessage, context);
204 
205  //Check status code
206  if(!error)
207  {
208  //Start DHCPv6 client
209  context->running = TRUE;
210  }
211  }
212  else
213  {
214  //The DHCP client is already running
215  error = ERROR_ALREADY_RUNNING;
216  }
217 
218  //Release exclusive access
219  netUnlock(context->netContext);
220 
221  //Return status code
222  return error;
223 }
224 
225 
226 /**
227  * @brief Stop DHCPv6 client
228  * @param[in] context Pointer to the DHCPv6 client context
229  * @return Error code
230  **/
231 
233 {
234  //Make sure the DHCPv6 client context is valid
235  if(context == NULL)
237 
238  //Debug message
239  TRACE_INFO("Stopping DHCPv6 client...\r\n");
240 
241  //Get exclusive access
242  netLock(context->netContext);
243 
244  //Check whether the DHCPv6 client is running
245  if(context->running)
246  {
247  //Unregister callback function
248  udpUnregisterRxCallback(context->interface, DHCPV6_CLIENT_PORT);
249 
250  //Stop DHCPv6 client
251  context->running = FALSE;
252  //Reinitialize state machine
253  context->state = DHCPV6_STATE_INIT;
254  }
255 
256  //Release exclusive access
257  netUnlock(context->netContext);
258 
259  //Successful processing
260  return NO_ERROR;
261 }
262 
263 
264 /**
265  * @brief Release DHCPv6 lease
266  * @param[in] context Pointer to the DHCPv6 client context
267  * @return Error code
268  **/
269 
271 {
272  uint_t i;
273  Dhcpv6ClientAddrEntry *entry;
274 
275  //Check parameter
276  if(context == NULL)
278 
279  //Debug message
280  TRACE_INFO("Releasing DHCPv6 lease...\r\n");
281 
282  //Get exclusive access
283  netLock(context->netContext);
284 
285  //Check whether the DHCPv6 client is running
286  if(context->running)
287  {
288  //BOUND state?
289  if(context->state == DHCPV6_STATE_BOUND)
290  {
291  //Loop through the IPv6 addresses recorded by the DHCPv6 client
292  for(i = 0; i < DHCPV6_CLIENT_ADDR_LIST_SIZE; i++)
293  {
294  //Point to the current entry
295  entry = &context->ia.addrList[i];
296 
297  //Valid IPv6 address?
298  if(entry->validLifetime > 0)
299  {
300  //The client must stop using the addresses being released as soon
301  //as the client begins the Release message exchange process
302  ipv6RemoveAddr(context->interface, &entry->addr);
303  }
304  }
305 
306  //Switch to the RELEASE state
308  }
309  else
310  {
311  //Stop DHCPv6 client
312  context->running = FALSE;
313  //Reinitialize state machine
314  context->state = DHCPV6_STATE_INIT;
315  }
316  }
317 
318  //Release exclusive access
319  netUnlock(context->netContext);
320 
321  //Successful processing
322  return NO_ERROR;
323 }
324 
325 
326 /**
327  * @brief Retrieve current state
328  * @param[in] context Pointer to the DHCPv6 client context
329  * @return Current DHCPv6 client state
330  **/
331 
333 {
334  Dhcpv6State state;
335 
336  //Get exclusive access
337  netLock(context->netContext);
338  //Get current state
339  state = context->state;
340  //Release exclusive access
341  netUnlock(context->netContext);
342 
343  //Return current state
344  return state;
345 }
346 
347 
348 /**
349  * @brief Release DHCPv6 client context
350  * @param[in] context Pointer to the DHCPv6 client context
351  **/
352 
354 {
355  NetInterface *interface;
356 
357  //Make sure the DHCPv6 client context is valid
358  if(context != NULL)
359  {
360  //Get exclusive access
361  netLock(context->netContext);
362 
363  //Point to the underlying network interface
364  interface = context->interface;
365  //Detach the DHCPv6 client context from the network interface
366  interface->dhcpv6ClientContext = NULL;
367 
368  //Release exclusive access
369  netUnlock(context->netContext);
370 
371  //Clear DHCPv6 client context
372  osMemset(context, 0, sizeof(Dhcpv6ClientContext));
373  }
374 }
375 
376 #endif
IPv6 (Internet Protocol Version 6)
void netUnlock(NetContext *context)
Release exclusive access to the core of the TCP/IP stack.
Definition: net.c:319
bool_t rapidCommit
Quick configuration using rapid commit.
error_t udpUnregisterRxCallback(NetInterface *interface, uint16_t port)
Unregister user callback.
Definition: udp.c:1062
Dhcpv6ParseOptionsCallback parseOptionsCallback
Parse DHCPv6 options callback.
Dhcpv6StateChangeCallback stateChangeEvent
FSM state change event.
#define DHCPV6_CLIENT_PORT
Definition: dhcpv6_common.h:40
#define TRUE
Definition: os_port.h:50
void dhcpv6ClientFlushAddrList(Dhcpv6ClientContext *context)
Flush the list of IPv6 addresses from the IA.
@ DHCPV6_STATE_INIT
#define DHCPV6_CLIENT_ADDR_LIST_SIZE
Definition: dhcpv6_client.h:54
Helper functions for DHCPv6 client.
Ipv6Addr addr
IPv6 address.
bool_t manualDnsConfig
Force manual DNS configuration.
NetInterface * interface
Network interface to configure.
#define FALSE
Definition: os_port.h:46
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
void ipv6FlushDnsServerList(NetInterface *interface)
Flush the list of DNS servers.
Definition: ipv6_misc.c:776
error_t
Error codes.
Definition: error.h:43
uint32_t validLifetime
Valid lifetime.
DHCPv6 client (Dynamic Host Configuration Protocol for IPv6)
error_t dhcpv6ClientStop(Dhcpv6ClientContext *context)
Stop DHCPv6 client.
IA address entry.
#define NetInterface
Definition: net.h:40
Dhcpv6TimeoutCallback timeoutEvent
DHCPv6 configuration timeout event.
void dhcpv6ClientProcessMessage(NetInterface *interface, const IpPseudoHeader *pseudoHeader, const UdpHeader *udpHeader, const NetBuffer *buffer, size_t offset, const NetRxAncillary *ancillary, void *param)
Process incoming DHCPv6 message.
Helper functions for IPv6.
Dhcpv6State dhcpv6ClientGetState(Dhcpv6ClientContext *context)
Retrieve current state.
#define Dhcpv6ClientContext
DHCPv6 client settings.
systime_t timeout
DHCPv6 configuration timeout.
#define TRACE_INFO(...)
Definition: debug.h:105
void ipv6RemoveAddr(NetInterface *interface, const Ipv6Addr *addr)
Remove an entry from the list of IPv6 addresses.
Definition: ipv6_misc.c:359
Dhcpv6State
DHCPv6 client FSM states.
@ DHCPV6_STATE_BOUND
error_t dhcpv6ClientRelease(Dhcpv6ClientContext *context)
Release DHCPv6 lease.
error_t dhcpv6ClientInit(Dhcpv6ClientContext *context, const Dhcpv6ClientSettings *settings)
DHCPv6 client initialization.
Definition: dhcpv6_client.c:92
@ DHCPV6_STATE_RELEASE
error_t dhcpv6ClientGenerateDuid(Dhcpv6ClientContext *context)
Generate client's DUID.
error_t dhcpv6ClientStart(Dhcpv6ClientContext *context)
Start DHCPv6 client.
Dhcpv6LinkChangeCallback linkChangeEvent
Link state change event.
void dhcpv6ClientGetDefaultSettings(Dhcpv6ClientSettings *settings)
Initialize settings with default values.
Definition: dhcpv6_client.c:59
error_t dhcpv6ClientGenerateLinkLocalAddr(Dhcpv6ClientContext *context)
Generate a link-local address.
void netLock(NetContext *context)
Get exclusive access to the core of the TCP/IP stack.
Definition: net.c:307
Dhcpv6AddOptionsCallback addOptionsCallback
Add DHCPv6 options callback.
void dhcpv6ClientDeinit(Dhcpv6ClientContext *context)
Release DHCPv6 client context.
error_t udpRegisterRxCallback(NetInterface *interface, uint16_t port, UdpRxCallback callback, void *param)
Register user callback.
Definition: udp.c:1021
unsigned int uint_t
Definition: compiler_port.h:57
#define osMemset(p, value, length)
Definition: os_port.h:138
TCP/IP stack core.
void dhcpv6ClientChangeState(Dhcpv6ClientContext *context, Dhcpv6State newState, systime_t delay)
Update DHCPv6 FSM state.
@ ERROR_ALREADY_RUNNING
Definition: error.h:294
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.