Sergey Pastor / 1

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers dhcpv6_common.c Source File

dhcpv6_common.c

Go to the documentation of this file.
00001 /**
00002  * @file dhcpv6_common.c
00003  * @brief Functions common to DHCPv6 client, server and relay agent
00004  *
00005  * @section License
00006  *
00007  * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
00008  *
00009  * This file is part of CycloneTCP Open.
00010  *
00011  * This program is free software; you can redistribute it and/or
00012  * modify it under the terms of the GNU General Public License
00013  * as published by the Free Software Foundation; either version 2
00014  * of the License, or (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software Foundation,
00023  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00024  *
00025  * @section Description
00026  *
00027  * The Dynamic Host Configuration Protocol for IPv6 enables DHCP servers to
00028  * pass configuration parameters such as IPv6 network addresses to IPv6
00029  * nodes. This protocol is a stateful counterpart to IPv6 Stateless Address
00030  * Autoconfiguration (RFC 2462), and can be used separately or concurrently
00031  * with the latter to obtain configuration parameters. Refer to RFC 3315
00032  *
00033  * @author Oryx Embedded SARL (www.oryx-embedded.com)
00034  * @version 1.7.6
00035  **/
00036 
00037 //Switch to the appropriate trace level
00038 #define TRACE_LEVEL DHCPV6_TRACE_LEVEL
00039 
00040 //Dependencies
00041 #include "core/net.h"
00042 #include "dhcpv6/dhcpv6_common.h"
00043 #include "debug.h"
00044 
00045 //Check TCP/IP stack configuration
00046 #if (IPV6_SUPPORT == ENABLED)
00047 
00048 //All DHCPv6 relay agents and servers (FF02::1:2)
00049 const Ipv6Addr DHCPV6_ALL_RELAY_AGENTS_AND_SERVERS_ADDR =
00050    IPV6_ADDR(0xFF02, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002);
00051 
00052 //All DHCPv6 servers (FF05::1:3)
00053 const Ipv6Addr DHCPV6_ALL_SERVERS_ADDR =
00054    IPV6_ADDR(0xFF05, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0003);
00055 
00056 
00057 /**
00058  * @brief Retrieve status code
00059  *
00060  * This function returns a status indication related to the DHCPv6
00061  * message or option in which it appears
00062  *
00063  * @param[in] options Pointer to the Options field
00064  * @param[in] length Length of the Options field
00065  * @return Status code
00066  **/
00067 
00068 Dhcpv6StatusCode dhcpv6GetStatusCode(const uint8_t *options, size_t length)
00069 {
00070    uint16_t statusCode;
00071    Dhcpv6Option *option;
00072    Dhcpv6StatusCodeOption *statusCodeOption;
00073 
00074    //Search for the Status Code option
00075    option = dhcpv6GetOption(options, length, DHCPV6_OPTION_STATUS_CODE);
00076 
00077    //Check whether the option has been found
00078    if(option != NULL && ntohs(option->length) >= sizeof(Dhcpv6StatusCodeOption))
00079    {
00080       //The option contains a status code and a status message
00081       statusCodeOption = (Dhcpv6StatusCodeOption *) option->value;
00082 
00083       //Convert the status code from network byte order
00084       statusCode = ntohs(statusCodeOption->statusCode);
00085    }
00086    else
00087    {
00088       //If the Status Code option does not appear in a message in which the option
00089       //could appear, the status of the message is assumed to be Success
00090       statusCode = DHCPV6_STATUS_SUCCESS;
00091    }
00092 
00093    //Return status code
00094    return (Dhcpv6StatusCode) statusCode;
00095 }
00096 
00097 
00098 /**
00099  * @brief Add an option to a DHCPv6 message
00100  * @param[in] message Pointer to the DHCPv6 message
00101  * @param[in,out] messageLength Length of the overall DHCPv6 message
00102  * @param[in] optionCode Option code
00103  * @param[in] optionValue Option value
00104  * @param[in] optionLength Length of the option value
00105  * @return If the option was successfully added, a pointer to the freshly
00106  *   created option is returned. Otherwise NULL pointer is returned
00107  **/
00108 
00109 Dhcpv6Option *dhcpv6AddOption(void *message, size_t *messageLength,
00110    uint16_t optionCode, const void *optionValue, size_t optionLength)
00111 {
00112    Dhcpv6Option *option;
00113 
00114    //Check the length of the DHCPv6 message
00115    if(*messageLength < sizeof(Dhcpv6Message))
00116       return NULL;
00117    //Check the length of the option
00118    if(optionLength > UINT16_MAX)
00119       return NULL;
00120 
00121    //Make sure there is enough room to add the option
00122    if((*messageLength + sizeof(Dhcpv6Option) + optionLength) > DHCPV6_MAX_MSG_SIZE)
00123       return NULL;
00124 
00125    //Point to the end of the DHCPv6 message
00126    option = (Dhcpv6Option *) ((uint8_t *) message + *messageLength);
00127    //Write specified option at current location
00128    option->code = htons(optionCode);
00129    option->length = htons(optionLength);
00130    //Copy option data
00131    memcpy(option->value, optionValue, optionLength);
00132 
00133    //Update the length of the DHCPv6 message
00134    *messageLength += sizeof(Dhcpv6Option) + optionLength;
00135    //Return a pointer to the freshly created option
00136    return option;
00137 }
00138 
00139 
00140 /**
00141  * @brief Add a suboption under an existing base option
00142  * @param[in] baseOption Pointer to the base option
00143  * @param[in,out] messageLength Length of the overall DHCPv6 message
00144  * @param[in] optionCode Option code
00145  * @param[in] optionValue Option value
00146  * @param[in] optionLength Length of the option value
00147  * @return If the option was successfully added, a pointer to the freshly
00148  *   created option is returned. Otherwise NULL pointer is returned
00149  **/
00150 
00151 Dhcpv6Option *dhcpv6AddSubOption(Dhcpv6Option *baseOption, size_t *messageLength,
00152    uint16_t optionCode, const void *optionValue, size_t optionLength)
00153 {
00154    uint_t n;
00155    Dhcpv6Option *option;
00156 
00157    //The pointer to the base option must be valid
00158    if(baseOption == NULL)
00159       return NULL;
00160    //Check the length of the DHCPv6 message
00161    if(*messageLength < sizeof(Dhcpv6Message))
00162       return NULL;
00163    //Check the length of the suboption
00164    if(optionLength > UINT16_MAX)
00165       return NULL;
00166 
00167    //Make sure there is enough room to add the option
00168    if((*messageLength + sizeof(Dhcpv6Option) + optionLength) > DHCPV6_MAX_MSG_SIZE)
00169       return NULL;
00170 
00171    //Get the actual length of the base option
00172    n = ntohs(baseOption->length);
00173 
00174    //Point to the location that follows the base option
00175    option = (Dhcpv6Option *) (baseOption->value + n);
00176 
00177    //Write specified option at current location
00178    option->code = htons(optionCode);
00179    option->length = htons(optionLength);
00180    //Copy option data
00181    memcpy(option->value, optionValue, optionLength);
00182 
00183    //Update the length of the base option
00184    n += sizeof(Dhcpv6Option) + optionLength;
00185    //Convert the 16-bit value to network byte order
00186    baseOption->length = htons(n);
00187 
00188    //Update the length of the DHCPv6 message
00189    *messageLength += sizeof(Dhcpv6Option) + optionLength;
00190    //Return a pointer to the freshly created option
00191    return option;
00192 }
00193 
00194 
00195 /**
00196  * @brief Find the specified option in a DHCPv6 message
00197  * @param[in] options Pointer to the Options field
00198  * @param[in] optionsLength Length of the Options field
00199  * @param[in] optionCode Code of the option to find
00200  * @return If the specified option was found, a pointer to the corresponding
00201  *   option is returned. Otherwise NULL pointer is returned
00202  **/
00203 
00204 Dhcpv6Option *dhcpv6GetOption(const uint8_t *options,
00205    size_t optionsLength, uint16_t optionCode)
00206 {
00207    uint_t i;
00208    Dhcpv6Option *option;
00209 
00210    //Parse DHCPv6 options
00211    for(i = 0; i < optionsLength; )
00212    {
00213       //Point to the current option
00214       option = (Dhcpv6Option *) (options + i);
00215 
00216       //Make sure the option is valid
00217       if((i + sizeof(Dhcpv6Option)) > optionsLength)
00218          break;
00219       //Check the length of the option data
00220       if((i + sizeof(Dhcpv6Option) + ntohs(option->length)) > optionsLength)
00221          break;
00222 
00223       //Option code matches the specified one?
00224       if(ntohs(option->code) == optionCode)
00225          return option;
00226 
00227       //Jump to the next option
00228       i += sizeof(Dhcpv6Option) + ntohs(option->length);
00229    }
00230 
00231    //The specified option code was not found
00232    return NULL;
00233 }
00234 
00235 
00236 /**
00237  * @brief Multiplication by a randomization factor
00238  *
00239  * Each of the computations of a new RT include a randomization factor
00240  * RAND, which is a random number chosen with a uniform distribution
00241  * between -0.1 and +0.1. The randomization factor is included to
00242  * minimize synchronization of messages transmitted by DHCPv6 clients
00243  *
00244  * @param[in] value Input value
00245  * @return Value resulting from the randomization process
00246  **/
00247 
00248 int32_t dhcpv6Rand(int32_t value)
00249 {
00250    //Use a randomization factor chosen with a uniform
00251    //distribution between -0.1 and +0.1
00252    return value * dhcpv6RandRange(-100, 100) / 1000;
00253 }
00254 
00255 
00256 /**
00257  * @brief Get a random value in the specified range
00258  * @param[in] min Lower bound
00259  * @param[in] max Upper bound
00260  * @return Random value in the specified range
00261  **/
00262 
00263 int32_t dhcpv6RandRange(int32_t min, int32_t max)
00264 {
00265    //Return a random value in the given range
00266    return min + netGetRand() % (max - min + 1);
00267 }
00268 
00269 #endif
00270