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