dhcpv6_common.c
Go to the documentation of this file.
1 /**
2  * @file dhcpv6_common.c
3  * @brief Definitions common to DHCPv6 client, server and relay agent
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2024 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.4.4
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 "dhcpv6/dhcpv6_client.h"
45 #include "dhcpv6/dhcpv6_relay.h"
46 #include "dhcpv6/dhcpv6_common.h"
47 #include "debug.h"
48 
49 //Check TCP/IP stack configuration
50 #if (IPV6_SUPPORT == ENABLED && (DHCPV6_CLIENT_SUPPORT == ENABLED || \
51  DHCPV6_RELAY_SUPPORT == ENABLED))
52 
53 //All DHCPv6 relay agents and servers (ff02::1:2)
55  IPV6_ADDR(0xFF02, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002);
56 
57 //All DHCPv6 servers (ff05::1:3)
59  IPV6_ADDR(0xFF05, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0003);
60 
61 
62 /**
63  * @brief Retrieve status code
64  *
65  * This function returns a status indication related to the DHCPv6
66  * message or option in which it appears
67  *
68  * @param[in] options Pointer to the Options field
69  * @param[in] length Length of the Options field
70  * @return Status code
71  **/
72 
74 {
75  uint16_t statusCode;
76  Dhcpv6Option *option;
77  Dhcpv6StatusCodeOption *statusCodeOption;
78 
79  //Search for the Status Code option
81 
82  //Option found?
83  if(option != NULL && ntohs(option->length) >= sizeof(Dhcpv6StatusCodeOption))
84  {
85  //The option contains a status code and a status message
86  statusCodeOption = (Dhcpv6StatusCodeOption *) option->value;
87 
88  //Convert the status code from network byte order
89  statusCode = ntohs(statusCodeOption->statusCode);
90  }
91  else
92  {
93  //If the Status Code option does not appear in a message in which the option
94  //could appear, the status of the message is assumed to be Success
95  statusCode = DHCPV6_STATUS_SUCCESS;
96  }
97 
98  //Return status code
99  return (Dhcpv6StatusCode) statusCode;
100 }
101 
102 
103 /**
104  * @brief Add an option to a DHCPv6 message
105  * @param[in] message Pointer to the DHCPv6 message
106  * @param[in,out] messageLen Actual length of the DHCPv6 message
107  * @param[in] optionCode Option code
108  * @param[in] optionValue Option value
109  * @param[in] optionLen Length of the option value
110  * @return If the option was successfully added, a pointer to the freshly
111  * created option is returned. Otherwise NULL pointer is returned
112  **/
113 
114 Dhcpv6Option *dhcpv6AddOption(void *message, size_t *messageLen,
115  uint16_t optionCode, const void *optionValue, size_t optionLen)
116 {
117  Dhcpv6Option *option;
118 
119  //Check parameters
120  if(message == NULL || messageLen == NULL)
121  return NULL;
122 
123  //Check the length of the DHCPv6 message
124  if(*messageLen < sizeof(Dhcpv6Message))
125  return NULL;
126 
127  //Check the length of the option
128  if(optionLen > 0 && optionValue == NULL)
129  return NULL;
130 
131  if(optionLen > UINT16_MAX)
132  return NULL;
133 
134  //Ensure that the length of the resulting message will not exceed the
135  //maximum DHCPv6 message size
136  if((*messageLen + sizeof(Dhcpv6Option) + optionLen) > DHCPV6_MAX_MSG_SIZE)
137  return NULL;
138 
139  //Point to the end of the DHCPv6 message
140  option = (Dhcpv6Option *) ((uint8_t *) message + *messageLen);
141 
142  //Write specified option at current location
143  option->code = htons(optionCode);
144  option->length = htons(optionLen);
145 
146  //Copy option data
147  osMemcpy(option->value, optionValue, optionLen);
148 
149  //Update the length of the DHCPv6 message
150  *messageLen += sizeof(Dhcpv6Option) + optionLen;
151 
152  //Return a pointer to the freshly created option
153  return option;
154 }
155 
156 
157 /**
158  * @brief Add a suboption under an existing base option
159  * @param[in] baseOption Pointer to the base option
160  * @param[in,out] messageLen Length of the overall DHCPv6 message
161  * @param[in] optionCode Option code
162  * @param[in] optionValue Option value
163  * @param[in] optionLen Length of the option value
164  * @return If the option was successfully added, a pointer to the freshly
165  * created option is returned. Otherwise NULL pointer is returned
166  **/
167 
168 Dhcpv6Option *dhcpv6AddSubOption(Dhcpv6Option *baseOption, size_t *messageLen,
169  uint16_t optionCode, const void *optionValue, size_t optionLen)
170 {
171  uint_t n;
172  Dhcpv6Option *option;
173 
174  //The pointer to the base option must be valid
175  if(baseOption == NULL)
176  return NULL;
177 
178  //Check the length of the DHCPv6 message
179  if(*messageLen < sizeof(Dhcpv6Message))
180  return NULL;
181 
182  //Check the length of the suboption
183  if(optionLen > 0 && optionValue == NULL)
184  return NULL;
185 
186  if(optionLen > UINT16_MAX)
187  return NULL;
188 
189  //Ensure that the length of the resulting message will not exceed the
190  //maximum DHCPv6 message size
191  if((*messageLen + sizeof(Dhcpv6Option) + optionLen) > DHCPV6_MAX_MSG_SIZE)
192  return NULL;
193 
194  //Get the actual length of the base option
195  n = ntohs(baseOption->length);
196 
197  //Point to the location that follows the base option
198  option = (Dhcpv6Option *) (baseOption->value + n);
199 
200  //Write specified option at current location
201  option->code = htons(optionCode);
202  option->length = htons(optionLen);
203 
204  //Copy option data
205  osMemcpy(option->value, optionValue, optionLen);
206 
207  //Update the length of the base option
208  n += sizeof(Dhcpv6Option) + optionLen;
209  //Convert the 16-bit value to network byte order
210  baseOption->length = htons(n);
211 
212  //Update the length of the DHCPv6 message
213  *messageLen += sizeof(Dhcpv6Option) + optionLen;
214 
215  //Return a pointer to the freshly created option
216  return option;
217 }
218 
219 
220 /**
221  * @brief Search a DHCPv6 message for a given option
222  * @param[in] options Pointer to the Options field
223  * @param[in] optionsLength Length of the Options field
224  * @param[in] optionCode Code of the option to find
225  * @return If the specified option was found, a pointer to the corresponding
226  * option is returned. Otherwise NULL pointer is returned
227  **/
228 
230  size_t optionsLength, uint16_t optionCode)
231 {
232  uint_t i;
233  Dhcpv6Option *option;
234 
235  //Parse DHCPv6 options
236  for(i = 0; i < optionsLength; )
237  {
238  //Point to the current option
239  option = (Dhcpv6Option *) (options + i);
240 
241  //Make sure the option is valid
242  if((i + sizeof(Dhcpv6Option)) > optionsLength)
243  break;
244 
245  //Check the length of the option data
246  if((i + sizeof(Dhcpv6Option) + ntohs(option->length)) > optionsLength)
247  break;
248 
249  //Option code matches the specified one?
250  if(ntohs(option->code) == optionCode)
251  return option;
252 
253  //Jump to the next option
254  i += sizeof(Dhcpv6Option) + ntohs(option->length);
255  }
256 
257  //The specified option code was not found
258  return NULL;
259 }
260 
261 #endif
#define htons(value)
Definition: cpu_endian.h:413
DHCPv6 relay agent (Dynamic Host Configuration Protocol for IPv6)
#define IPV6_ADDR(a, b, c, d, e, f, g, h)
Definition: ipv6.h:118
uint8_t message[]
Definition: chap.h:154
Definitions common to DHCPv6 client, server and relay agent.
Ipv6Addr
Definition: ipv6.h:260
const Ipv6Addr DHCPV6_ALL_RELAY_AGENTS_AND_SERVERS_ADDR
Definition: dhcpv6_common.c:54
Dhcpv6Option * dhcpv6AddSubOption(Dhcpv6Option *baseOption, size_t *messageLen, uint16_t optionCode, const void *optionValue, size_t optionLen)
Add a suboption under an existing base option.
Dhcpv6Message
Dhcpv6Option * dhcpv6GetOption(const uint8_t *options, size_t optionsLength, uint16_t optionCode)
Search a DHCPv6 message for a given option.
@ DHCPV6_STATUS_SUCCESS
#define DHCPV6_MAX_MSG_SIZE
Definition: dhcpv6_common.h:44
#define osMemcpy(dest, src, length)
Definition: os_port.h:141
Dhcpv6StatusCode dhcpv6GetStatusCode(const uint8_t *options, size_t length)
Retrieve status code.
Definition: dhcpv6_common.c:73
DHCPv6 client (Dynamic Host Configuration Protocol for IPv6)
Dhcpv6Option
const Ipv6Addr DHCPV6_ALL_SERVERS_ADDR
Definition: dhcpv6_common.c:58
Dhcpv6StatusCodeOption
Dhcpv6StatusCode
Status code.
uint8_t length
Definition: tcp.h:368
#define ntohs(value)
Definition: cpu_endian.h:421
uint8_t n
Dhcpv6Option * dhcpv6AddOption(void *message, size_t *messageLen, uint16_t optionCode, const void *optionValue, size_t optionLen)
Add an option to a DHCPv6 message.
uint8_t options[]
Definition: tcp.h:357
unsigned int uint_t
Definition: compiler_port.h:50
TCP/IP stack core.
@ DHCPV6_OPT_STATUS_CODE
Debugging facilities.