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  * Copyright (C) 2010-2018 Oryx Embedded SARL. All rights reserved.
8  *
9  * This file is part of CycloneTCP Open.
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software Foundation,
23  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24  *
25  * @section Description
26  *
27  * The Dynamic Host Configuration Protocol for IPv6 enables DHCP servers to
28  * pass configuration parameters such as IPv6 network addresses to IPv6
29  * nodes. This protocol is a stateful counterpart to IPv6 Stateless Address
30  * Autoconfiguration (RFC 2462), and can be used separately or concurrently
31  * with the latter to obtain configuration parameters. Refer to RFC 3315
32  *
33  * @author Oryx Embedded SARL (www.oryx-embedded.com)
34  * @version 1.9.0
35  **/
36 
37 //Switch to the appropriate trace level
38 #define TRACE_LEVEL DHCPV6_TRACE_LEVEL
39 
40 //Dependencies
41 #include "core/net.h"
42 #include "dhcpv6/dhcpv6_common.h"
43 #include "debug.h"
44 
45 //Check TCP/IP stack configuration
46 #if (IPV6_SUPPORT == ENABLED)
47 
48 //All DHCPv6 relay agents and servers (FF02::1:2)
50  IPV6_ADDR(0xFF02, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002);
51 
52 //All DHCPv6 servers (FF05::1:3)
54  IPV6_ADDR(0xFF05, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0003);
55 
56 
57 /**
58  * @brief Retrieve status code
59  *
60  * This function returns a status indication related to the DHCPv6
61  * message or option in which it appears
62  *
63  * @param[in] options Pointer to the Options field
64  * @param[in] length Length of the Options field
65  * @return Status code
66  **/
67 
69 {
70  uint16_t statusCode;
71  Dhcpv6Option *option;
72  Dhcpv6StatusCodeOption *statusCodeOption;
73 
74  //Search for the Status Code option
76 
77  //Check whether the option has been found
78  if(option != NULL && ntohs(option->length) >= sizeof(Dhcpv6StatusCodeOption))
79  {
80  //The option contains a status code and a status message
81  statusCodeOption = (Dhcpv6StatusCodeOption *) option->value;
82 
83  //Convert the status code from network byte order
84  statusCode = ntohs(statusCodeOption->statusCode);
85  }
86  else
87  {
88  //If the Status Code option does not appear in a message in which the option
89  //could appear, the status of the message is assumed to be Success
91  }
92 
93  //Return status code
95 }
96 
97 
98 /**
99  * @brief Add an option to a DHCPv6 message
100  * @param[in] message Pointer to the DHCPv6 message
101  * @param[in,out] messageLen Length of the overall DHCPv6 message
102  * @param[in] optionCode Option code
103  * @param[in] optionValue Option value
104  * @param[in] optionLen Length of the option value
105  * @return If the option was successfully added, a pointer to the freshly
106  * created option is returned. Otherwise NULL pointer is returned
107  **/
108 
109 Dhcpv6Option *dhcpv6AddOption(void *message, size_t *messageLen,
110  uint16_t optionCode, const void *optionValue, size_t optionLen)
111 {
112  Dhcpv6Option *option;
113 
114  //Check the length of the DHCPv6 message
115  if(*messageLen < sizeof(Dhcpv6Message))
116  return NULL;
117  //Check the length of the option
118  if(optionLen > UINT16_MAX)
119  return NULL;
120 
121  //Make sure there is enough room to add the option
122  if((*messageLen + sizeof(Dhcpv6Option) + optionLen) > DHCPV6_MAX_MSG_SIZE)
123  return NULL;
124 
125  //Point to the end of the DHCPv6 message
126  option = (Dhcpv6Option *) ((uint8_t *) message + *messageLen);
127  //Write specified option at current location
128  option->code = htons(optionCode);
129  option->length = htons(optionLen);
130  //Copy option data
131  memcpy(option->value, optionValue, optionLen);
132 
133  //Update the length of the DHCPv6 message
134  *messageLen += sizeof(Dhcpv6Option) + optionLen;
135  //Return a pointer to the freshly created option
136  return option;
137 }
138 
139 
140 /**
141  * @brief Add a suboption under an existing base option
142  * @param[in] baseOption Pointer to the base option
143  * @param[in,out] messageLen Length of the overall DHCPv6 message
144  * @param[in] optionCode Option code
145  * @param[in] optionValue Option value
146  * @param[in] optionLen Length of the option value
147  * @return If the option was successfully added, a pointer to the freshly
148  * created option is returned. Otherwise NULL pointer is returned
149  **/
150 
151 Dhcpv6Option *dhcpv6AddSubOption(Dhcpv6Option *baseOption, size_t *messageLen,
152  uint16_t optionCode, const void *optionValue, size_t optionLen)
153 {
154  uint_t n;
155  Dhcpv6Option *option;
156 
157  //The pointer to the base option must be valid
158  if(baseOption == NULL)
159  return NULL;
160  //Check the length of the DHCPv6 message
161  if(*messageLen < sizeof(Dhcpv6Message))
162  return NULL;
163  //Check the length of the suboption
164  if(optionLen > UINT16_MAX)
165  return NULL;
166 
167  //Make sure there is enough room to add the option
168  if((*messageLen + sizeof(Dhcpv6Option) + optionLen) > DHCPV6_MAX_MSG_SIZE)
169  return NULL;
170 
171  //Get the actual length of the base option
172  n = ntohs(baseOption->length);
173 
174  //Point to the location that follows the base option
175  option = (Dhcpv6Option *) (baseOption->value + n);
176 
177  //Write specified option at current location
178  option->code = htons(optionCode);
179  option->length = htons(optionLen);
180  //Copy option data
181  memcpy(option->value, optionValue, optionLen);
182 
183  //Update the length of the base option
184  n += sizeof(Dhcpv6Option) + optionLen;
185  //Convert the 16-bit value to network byte order
186  baseOption->length = htons(n);
187 
188  //Update the length of the DHCPv6 message
189  *messageLen += sizeof(Dhcpv6Option) + optionLen;
190  //Return a pointer to the freshly created option
191  return option;
192 }
193 
194 
195 /**
196  * @brief Find the specified option in a DHCPv6 message
197  * @param[in] options Pointer to the Options field
198  * @param[in] optionsLength Length of the Options field
199  * @param[in] optionCode Code of the option to find
200  * @return If the specified option was found, a pointer to the corresponding
201  * option is returned. Otherwise NULL pointer is returned
202  **/
203 
205  size_t optionsLength, uint16_t optionCode)
206 {
207  uint_t i;
208  Dhcpv6Option *option;
209 
210  //Parse DHCPv6 options
211  for(i = 0; i < optionsLength; )
212  {
213  //Point to the current option
214  option = (Dhcpv6Option *) (options + i);
215 
216  //Make sure the option is valid
217  if((i + sizeof(Dhcpv6Option)) > optionsLength)
218  break;
219  //Check the length of the option data
220  if((i + sizeof(Dhcpv6Option) + ntohs(option->length)) > optionsLength)
221  break;
222 
223  //Option code matches the specified one?
224  if(ntohs(option->code) == optionCode)
225  return option;
226 
227  //Jump to the next option
228  i += sizeof(Dhcpv6Option) + ntohs(option->length);
229  }
230 
231  //The specified option code was not found
232  return NULL;
233 }
234 
235 
236 /**
237  * @brief Multiplication by a randomization factor
238  *
239  * Each of the computations of a new RT include a randomization factor
240  * RAND, which is a random number chosen with a uniform distribution
241  * between -0.1 and +0.1. The randomization factor is included to
242  * minimize synchronization of messages transmitted by DHCPv6 clients
243  *
244  * @param[in] value Input value
245  * @return Value resulting from the randomization process
246  **/
247 
248 int32_t dhcpv6Rand(int32_t value)
249 {
250  //Use a randomization factor chosen with a uniform
251  //distribution between -0.1 and +0.1
252  return value * dhcpv6RandRange(-100, 100) / 1000;
253 }
254 
255 
256 /**
257  * @brief Get a random value in the specified range
258  * @param[in] min Lower bound
259  * @param[in] max Upper bound
260  * @return Random value in the specified range
261  **/
262 
263 int32_t dhcpv6RandRange(int32_t min, int32_t max)
264 {
265  //Return a random value in the given range
266  return min + netGetRand() % (max - min + 1);
267 }
268 
269 #endif
__start_packed struct @134 Dhcpv6Option
DHCPv6 option.
Dhcpv6Option * dhcpv6GetOption(const uint8_t *options, size_t optionsLength, uint16_t optionCode)
Find the specified option in a DHCPv6 message.
uint8_t options[]
Definition: tcp.h:318
TCP/IP stack core.
Dhcpv6StatusCode
Status code.
Debugging facilities.
uint8_t message[]
Definition: chap.h:150
uint16_t statusCode
__start_packed struct @183 Ipv6Addr
IPv6 network address.
int32_t dhcpv6RandRange(int32_t min, int32_t max)
Get a random value in the specified range.
#define htons(value)
Definition: cpu_endian.h:390
const Ipv6Addr DHCPV6_ALL_SERVERS_ADDR
Definition: dhcpv6_common.c:53
int32_t dhcpv6Rand(int32_t value)
Multiplication by a randomization factor.
const Ipv6Addr DHCPV6_ALL_RELAY_AGENTS_AND_SERVERS_ADDR
Definition: dhcpv6_common.c:49
Dhcpv6Option * dhcpv6AddSubOption(Dhcpv6Option *baseOption, size_t *messageLen, uint16_t optionCode, const void *optionValue, size_t optionLen)
Add a suboption under an existing base option.
__start_packed struct @143 Dhcpv6StatusCodeOption
Status Code option.
Definitions common to DHCPv6 client, server and relay agent.
#define ntohs(value)
Definition: cpu_endian.h:396
uint32_t netGetRand(void)
Get a random value.
Definition: net.c:1523
#define IPV6_ADDR(a, b, c, d, e, f, g, h)
Definition: ipv6.h:110
Dhcpv6StatusCode dhcpv6GetStatusCode(const uint8_t *options, size_t length)
Retrieve status code.
Definition: dhcpv6_common.c:68
unsigned int uint_t
Definition: compiler_port.h:43
uint8_t value[]
Definition: dtls_misc.h:141
#define DHCPV6_MAX_MSG_SIZE
Definition: dhcpv6_common.h:42
uint8_t length
Definition: dtls_misc.h:140
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.
__start_packed struct @132 Dhcpv6Message
DHCPv6 message.