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-2019 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 1.9.6
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  //Check whether the option has been 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 Length of the overall 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 the length of the DHCPv6 message
117  if(*messageLen < sizeof(Dhcpv6Message))
118  return NULL;
119  //Check the length of the option
120  if(optionLen > UINT16_MAX)
121  return NULL;
122 
123  //Make sure there is enough room to add the option
124  if((*messageLen + sizeof(Dhcpv6Option) + optionLen) > DHCPV6_MAX_MSG_SIZE)
125  return NULL;
126 
127  //Point to the end of the DHCPv6 message
128  option = (Dhcpv6Option *) ((uint8_t *) message + *messageLen);
129  //Write specified option at current location
130  option->code = htons(optionCode);
131  option->length = htons(optionLen);
132  //Copy option data
133  memcpy(option->value, optionValue, optionLen);
134 
135  //Update the length of the DHCPv6 message
136  *messageLen += sizeof(Dhcpv6Option) + optionLen;
137  //Return a pointer to the freshly created option
138  return option;
139 }
140 
141 
142 /**
143  * @brief Add a suboption under an existing base option
144  * @param[in] baseOption Pointer to the base option
145  * @param[in,out] messageLen Length of the overall DHCPv6 message
146  * @param[in] optionCode Option code
147  * @param[in] optionValue Option value
148  * @param[in] optionLen Length of the option value
149  * @return If the option was successfully added, a pointer to the freshly
150  * created option is returned. Otherwise NULL pointer is returned
151  **/
152 
153 Dhcpv6Option *dhcpv6AddSubOption(Dhcpv6Option *baseOption, size_t *messageLen,
154  uint16_t optionCode, const void *optionValue, size_t optionLen)
155 {
156  uint_t n;
157  Dhcpv6Option *option;
158 
159  //The pointer to the base option must be valid
160  if(baseOption == NULL)
161  return NULL;
162  //Check the length of the DHCPv6 message
163  if(*messageLen < sizeof(Dhcpv6Message))
164  return NULL;
165  //Check the length of the suboption
166  if(optionLen > UINT16_MAX)
167  return NULL;
168 
169  //Make sure there is enough room to add the option
170  if((*messageLen + sizeof(Dhcpv6Option) + optionLen) > DHCPV6_MAX_MSG_SIZE)
171  return NULL;
172 
173  //Get the actual length of the base option
174  n = ntohs(baseOption->length);
175 
176  //Point to the location that follows the base option
177  option = (Dhcpv6Option *) (baseOption->value + n);
178 
179  //Write specified option at current location
180  option->code = htons(optionCode);
181  option->length = htons(optionLen);
182  //Copy option data
183  memcpy(option->value, optionValue, optionLen);
184 
185  //Update the length of the base option
186  n += sizeof(Dhcpv6Option) + optionLen;
187  //Convert the 16-bit value to network byte order
188  baseOption->length = htons(n);
189 
190  //Update the length of the DHCPv6 message
191  *messageLen += sizeof(Dhcpv6Option) + optionLen;
192  //Return a pointer to the freshly created option
193  return option;
194 }
195 
196 
197 /**
198  * @brief Find the specified option in a DHCPv6 message
199  * @param[in] options Pointer to the Options field
200  * @param[in] optionsLength Length of the Options field
201  * @param[in] optionCode Code of the option to find
202  * @return If the specified option was found, a pointer to the corresponding
203  * option is returned. Otherwise NULL pointer is returned
204  **/
205 
207  size_t optionsLength, uint16_t optionCode)
208 {
209  uint_t i;
210  Dhcpv6Option *option;
211 
212  //Parse DHCPv6 options
213  for(i = 0; i < optionsLength; )
214  {
215  //Point to the current option
216  option = (Dhcpv6Option *) (options + i);
217 
218  //Make sure the option is valid
219  if((i + sizeof(Dhcpv6Option)) > optionsLength)
220  break;
221  //Check the length of the option data
222  if((i + sizeof(Dhcpv6Option) + ntohs(option->length)) > optionsLength)
223  break;
224 
225  //Option code matches the specified one?
226  if(ntohs(option->code) == optionCode)
227  return option;
228 
229  //Jump to the next option
230  i += sizeof(Dhcpv6Option) + ntohs(option->length);
231  }
232 
233  //The specified option code was not found
234  return NULL;
235 }
236 
237 
238 /**
239  * @brief Multiplication by a randomization factor
240  *
241  * Each of the computations of a new RT include a randomization factor
242  * RAND, which is a random number chosen with a uniform distribution
243  * between -0.1 and +0.1. The randomization factor is included to
244  * minimize synchronization of messages transmitted by DHCPv6 clients
245  *
246  * @param[in] value Input value
247  * @return Value resulting from the randomization process
248  **/
249 
250 int32_t dhcpv6Rand(int32_t value)
251 {
252  //Use a randomization factor chosen with a uniform
253  //distribution between -0.1 and +0.1
254  return value * dhcpv6RandRange(-100, 100) / 1000;
255 }
256 
257 
258 /**
259  * @brief Get a random value in the specified range
260  * @param[in] min Lower bound
261  * @param[in] max Upper bound
262  * @return Random value in the specified range
263  **/
264 
265 int32_t dhcpv6RandRange(int32_t min, int32_t max)
266 {
267  //Return a random value in the given range
268  return min + netGetRand() % (max - min + 1);
269 }
270 
271 #endif
#define htons(value)
Definition: cpu_endian.h:392
uint8_t length
Definition: dtls_misc.h:149
__start_packed struct @130 Dhcpv6Option
DHCPv6 option.
#define IPV6_ADDR(a, b, c, d, e, f, g, h)
Definition: ipv6.h:112
int32_t dhcpv6RandRange(int32_t min, int32_t max)
Get a random value in the specified range.
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)
Find the specified option in a DHCPv6 message.
#define DHCPV6_MAX_MSG_SIZE
Definition: dhcpv6_common.h:44
__start_packed struct @139 Dhcpv6StatusCodeOption
Status Code option.
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:320
const Ipv6Addr DHCPV6_ALL_SERVERS_ADDR
Definition: dhcpv6_common.c:55
__start_packed struct @128 Dhcpv6Message
DHCPv6 message.
int32_t dhcpv6Rand(int32_t value)
Multiplication by a randomization factor.
__start_packed struct @179 Ipv6Addr
IPv6 network address.
Dhcpv6StatusCode
Status code.
uint32_t netGetRand(void)
Get a random value.
Definition: net.c:1810
#define ntohs(value)
Definition: cpu_endian.h:398
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
uint8_t value[]
Definition: dtls_misc.h:150
unsigned int uint_t
Definition: compiler_port.h:45
TCP/IP stack core.
Debugging facilities.