Webserver+3d print

Dependents:   Nucleo

Committer:
Sergunb
Date:
Sat Feb 04 18:15:49 2017 +0000
Revision:
0:8918a71cdbe9
nothing else

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Sergunb 0:8918a71cdbe9 1 /**
Sergunb 0:8918a71cdbe9 2 * @file dhcpv6_client.c
Sergunb 0:8918a71cdbe9 3 * @brief DHCPv6 client (Dynamic Host Configuration Protocol for IPv6)
Sergunb 0:8918a71cdbe9 4 *
Sergunb 0:8918a71cdbe9 5 * @section License
Sergunb 0:8918a71cdbe9 6 *
Sergunb 0:8918a71cdbe9 7 * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
Sergunb 0:8918a71cdbe9 8 *
Sergunb 0:8918a71cdbe9 9 * This file is part of CycloneTCP Open.
Sergunb 0:8918a71cdbe9 10 *
Sergunb 0:8918a71cdbe9 11 * This program is free software; you can redistribute it and/or
Sergunb 0:8918a71cdbe9 12 * modify it under the terms of the GNU General Public License
Sergunb 0:8918a71cdbe9 13 * as published by the Free Software Foundation; either version 2
Sergunb 0:8918a71cdbe9 14 * of the License, or (at your option) any later version.
Sergunb 0:8918a71cdbe9 15 *
Sergunb 0:8918a71cdbe9 16 * This program is distributed in the hope that it will be useful,
Sergunb 0:8918a71cdbe9 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Sergunb 0:8918a71cdbe9 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Sergunb 0:8918a71cdbe9 19 * GNU General Public License for more details.
Sergunb 0:8918a71cdbe9 20 *
Sergunb 0:8918a71cdbe9 21 * You should have received a copy of the GNU General Public License
Sergunb 0:8918a71cdbe9 22 * along with this program; if not, write to the Free Software Foundation,
Sergunb 0:8918a71cdbe9 23 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Sergunb 0:8918a71cdbe9 24 *
Sergunb 0:8918a71cdbe9 25 * @section Description
Sergunb 0:8918a71cdbe9 26 *
Sergunb 0:8918a71cdbe9 27 * The Dynamic Host Configuration Protocol for IPv6 enables DHCP servers to
Sergunb 0:8918a71cdbe9 28 * pass configuration parameters such as IPv6 network addresses to IPv6
Sergunb 0:8918a71cdbe9 29 * nodes. This protocol is a stateful counterpart to IPv6 Stateless Address
Sergunb 0:8918a71cdbe9 30 * Autoconfiguration (RFC 2462), and can be used separately or concurrently
Sergunb 0:8918a71cdbe9 31 * with the latter to obtain configuration parameters. Refer to RFC 3315
Sergunb 0:8918a71cdbe9 32 *
Sergunb 0:8918a71cdbe9 33 * @author Oryx Embedded SARL (www.oryx-embedded.com)
Sergunb 0:8918a71cdbe9 34 * @version 1.7.6
Sergunb 0:8918a71cdbe9 35 **/
Sergunb 0:8918a71cdbe9 36
Sergunb 0:8918a71cdbe9 37 //Switch to the appropriate trace level
Sergunb 0:8918a71cdbe9 38 #define TRACE_LEVEL DHCPV6_TRACE_LEVEL
Sergunb 0:8918a71cdbe9 39
Sergunb 0:8918a71cdbe9 40 //Dependencies
Sergunb 0:8918a71cdbe9 41 #include <stdlib.h>
Sergunb 0:8918a71cdbe9 42 #include "core/net.h"
Sergunb 0:8918a71cdbe9 43 #include "ipv6/ipv6.h"
Sergunb 0:8918a71cdbe9 44 #include "ipv6/ipv6_misc.h"
Sergunb 0:8918a71cdbe9 45 #include "ipv6/ndp.h"
Sergunb 0:8918a71cdbe9 46 #include "dhcpv6/dhcpv6_client.h"
Sergunb 0:8918a71cdbe9 47 #include "dhcpv6/dhcpv6_common.h"
Sergunb 0:8918a71cdbe9 48 #include "dhcpv6/dhcpv6_debug.h"
Sergunb 0:8918a71cdbe9 49 #include "dns/dns_common.h"
Sergunb 0:8918a71cdbe9 50 #include "date_time.h"
Sergunb 0:8918a71cdbe9 51 #include "debug.h"
Sergunb 0:8918a71cdbe9 52
Sergunb 0:8918a71cdbe9 53 //Check TCP/IP stack configuration
Sergunb 0:8918a71cdbe9 54 #if (IPV6_SUPPORT == ENABLED && DHCPV6_CLIENT_SUPPORT == ENABLED)
Sergunb 0:8918a71cdbe9 55
Sergunb 0:8918a71cdbe9 56 //Tick counter to handle periodic operations
Sergunb 0:8918a71cdbe9 57 systime_t dhcpv6ClientTickCounter;
Sergunb 0:8918a71cdbe9 58
Sergunb 0:8918a71cdbe9 59 //Requested DHCPv6 options
Sergunb 0:8918a71cdbe9 60 static const uint16_t dhcpv6OptionList[] =
Sergunb 0:8918a71cdbe9 61 {
Sergunb 0:8918a71cdbe9 62 HTONS(DHCPV6_OPTION_DNS_SERVERS),
Sergunb 0:8918a71cdbe9 63 HTONS(DHCPV6_OPTION_DOMAIN_LIST),
Sergunb 0:8918a71cdbe9 64 HTONS(DHCPV6_OPTION_FQDN)
Sergunb 0:8918a71cdbe9 65 };
Sergunb 0:8918a71cdbe9 66
Sergunb 0:8918a71cdbe9 67
Sergunb 0:8918a71cdbe9 68 /**
Sergunb 0:8918a71cdbe9 69 * @brief Initialize settings with default values
Sergunb 0:8918a71cdbe9 70 * @param[out] settings Structure that contains DHCPv6 client settings
Sergunb 0:8918a71cdbe9 71 **/
Sergunb 0:8918a71cdbe9 72
Sergunb 0:8918a71cdbe9 73 void dhcpv6ClientGetDefaultSettings(Dhcpv6ClientSettings *settings)
Sergunb 0:8918a71cdbe9 74 {
Sergunb 0:8918a71cdbe9 75 //Use default interface
Sergunb 0:8918a71cdbe9 76 settings->interface = netGetDefaultInterface();
Sergunb 0:8918a71cdbe9 77
Sergunb 0:8918a71cdbe9 78 //Support for quick configuration using rapid commit
Sergunb 0:8918a71cdbe9 79 settings->rapidCommit = FALSE;
Sergunb 0:8918a71cdbe9 80 //Use the DNS servers provided by the DHCPv6 server
Sergunb 0:8918a71cdbe9 81 settings->manualDnsConfig = FALSE;
Sergunb 0:8918a71cdbe9 82 //DHCPv6 configuration timeout
Sergunb 0:8918a71cdbe9 83 settings->timeout = 0;
Sergunb 0:8918a71cdbe9 84 //DHCPv6 configuration timeout event
Sergunb 0:8918a71cdbe9 85 settings->timeoutEvent = NULL;
Sergunb 0:8918a71cdbe9 86 //Link state change event
Sergunb 0:8918a71cdbe9 87 settings->linkChangeEvent = NULL;
Sergunb 0:8918a71cdbe9 88 //FSM state change event
Sergunb 0:8918a71cdbe9 89 settings->stateChangeEvent = NULL;
Sergunb 0:8918a71cdbe9 90 }
Sergunb 0:8918a71cdbe9 91
Sergunb 0:8918a71cdbe9 92
Sergunb 0:8918a71cdbe9 93 /**
Sergunb 0:8918a71cdbe9 94 * @brief DHCPv6 client initialization
Sergunb 0:8918a71cdbe9 95 * @param[in] context Pointer to the DHCPv6 client context
Sergunb 0:8918a71cdbe9 96 * @param[in] settings DHCPv6 client specific settings
Sergunb 0:8918a71cdbe9 97 * @return Error code
Sergunb 0:8918a71cdbe9 98 **/
Sergunb 0:8918a71cdbe9 99
Sergunb 0:8918a71cdbe9 100 error_t dhcpv6ClientInit(Dhcpv6ClientContext *context, const Dhcpv6ClientSettings *settings)
Sergunb 0:8918a71cdbe9 101 {
Sergunb 0:8918a71cdbe9 102 error_t error;
Sergunb 0:8918a71cdbe9 103 NetInterface *interface;
Sergunb 0:8918a71cdbe9 104
Sergunb 0:8918a71cdbe9 105 //Debug message
Sergunb 0:8918a71cdbe9 106 TRACE_INFO("Initializing DHCPv6 client...\r\n");
Sergunb 0:8918a71cdbe9 107
Sergunb 0:8918a71cdbe9 108 //Ensure the parameters are valid
Sergunb 0:8918a71cdbe9 109 if(context == NULL || settings == NULL)
Sergunb 0:8918a71cdbe9 110 return ERROR_INVALID_PARAMETER;
Sergunb 0:8918a71cdbe9 111
Sergunb 0:8918a71cdbe9 112 //A valid pointer to the interface being configured is required
Sergunb 0:8918a71cdbe9 113 if(settings->interface == NULL)
Sergunb 0:8918a71cdbe9 114 return ERROR_INVALID_PARAMETER;
Sergunb 0:8918a71cdbe9 115
Sergunb 0:8918a71cdbe9 116 //Point to the underlying network interface
Sergunb 0:8918a71cdbe9 117 interface = settings->interface;
Sergunb 0:8918a71cdbe9 118
Sergunb 0:8918a71cdbe9 119 //Clear the DHCPv6 client context
Sergunb 0:8918a71cdbe9 120 memset(context, 0, sizeof(Dhcpv6ClientContext));
Sergunb 0:8918a71cdbe9 121 //Save user settings
Sergunb 0:8918a71cdbe9 122 context->settings = *settings;
Sergunb 0:8918a71cdbe9 123
Sergunb 0:8918a71cdbe9 124 //Generate client's DUID
Sergunb 0:8918a71cdbe9 125 error = dhcpv6ClientGenerateDuid(context);
Sergunb 0:8918a71cdbe9 126 //any error to report?
Sergunb 0:8918a71cdbe9 127 if(error)
Sergunb 0:8918a71cdbe9 128 return error;
Sergunb 0:8918a71cdbe9 129
Sergunb 0:8918a71cdbe9 130 //Generate client's fully qualified domain name
Sergunb 0:8918a71cdbe9 131 error = dhcpv6ClientGenerateFqdn(context);
Sergunb 0:8918a71cdbe9 132 //any error to report?
Sergunb 0:8918a71cdbe9 133 if(error)
Sergunb 0:8918a71cdbe9 134 return error;
Sergunb 0:8918a71cdbe9 135
Sergunb 0:8918a71cdbe9 136 //Callback function to be called when a DHCPv6 message is received
Sergunb 0:8918a71cdbe9 137 error = udpAttachRxCallback(interface, DHCPV6_CLIENT_PORT,
Sergunb 0:8918a71cdbe9 138 dhcpv6ClientProcessMessage, context);
Sergunb 0:8918a71cdbe9 139 //Failed to register callback function?
Sergunb 0:8918a71cdbe9 140 if(error)
Sergunb 0:8918a71cdbe9 141 return error;
Sergunb 0:8918a71cdbe9 142
Sergunb 0:8918a71cdbe9 143 //DHCPv6 client is currently suspended
Sergunb 0:8918a71cdbe9 144 context->running = FALSE;
Sergunb 0:8918a71cdbe9 145 //Initialize state machine
Sergunb 0:8918a71cdbe9 146 context->state = DHCPV6_STATE_INIT;
Sergunb 0:8918a71cdbe9 147
Sergunb 0:8918a71cdbe9 148 //Attach the DHCPv6 client context to the network interface
Sergunb 0:8918a71cdbe9 149 interface->dhcpv6ClientContext = context;
Sergunb 0:8918a71cdbe9 150
Sergunb 0:8918a71cdbe9 151 //Successful initialization
Sergunb 0:8918a71cdbe9 152 return NO_ERROR;
Sergunb 0:8918a71cdbe9 153 }
Sergunb 0:8918a71cdbe9 154
Sergunb 0:8918a71cdbe9 155
Sergunb 0:8918a71cdbe9 156 /**
Sergunb 0:8918a71cdbe9 157 * @brief Start DHCPv6 client
Sergunb 0:8918a71cdbe9 158 * @param[in] context Pointer to the DHCPv6 client context
Sergunb 0:8918a71cdbe9 159 * @return Error code
Sergunb 0:8918a71cdbe9 160 **/
Sergunb 0:8918a71cdbe9 161
Sergunb 0:8918a71cdbe9 162 error_t dhcpv6ClientStart(Dhcpv6ClientContext *context)
Sergunb 0:8918a71cdbe9 163 {
Sergunb 0:8918a71cdbe9 164 NetInterface *interface;
Sergunb 0:8918a71cdbe9 165
Sergunb 0:8918a71cdbe9 166 //Check parameter
Sergunb 0:8918a71cdbe9 167 if(context == NULL)
Sergunb 0:8918a71cdbe9 168 return ERROR_INVALID_PARAMETER;
Sergunb 0:8918a71cdbe9 169
Sergunb 0:8918a71cdbe9 170 //Debug message
Sergunb 0:8918a71cdbe9 171 TRACE_INFO("Starting DHCPv6 client...\r\n");
Sergunb 0:8918a71cdbe9 172
Sergunb 0:8918a71cdbe9 173 //Get exclusive access
Sergunb 0:8918a71cdbe9 174 osAcquireMutex(&netMutex);
Sergunb 0:8918a71cdbe9 175
Sergunb 0:8918a71cdbe9 176 //Point to the underlying network interface
Sergunb 0:8918a71cdbe9 177 interface = context->settings.interface;
Sergunb 0:8918a71cdbe9 178
Sergunb 0:8918a71cdbe9 179 //Flush the list of IPv6 addresses from the client's IA
Sergunb 0:8918a71cdbe9 180 dhcpv6ClientFlushAddrList(context);
Sergunb 0:8918a71cdbe9 181
Sergunb 0:8918a71cdbe9 182 //Automatic DNS server configuration?
Sergunb 0:8918a71cdbe9 183 if(!context->settings.manualDnsConfig)
Sergunb 0:8918a71cdbe9 184 {
Sergunb 0:8918a71cdbe9 185 //Clear the list of DNS servers
Sergunb 0:8918a71cdbe9 186 ipv6FlushDnsServerList(interface);
Sergunb 0:8918a71cdbe9 187 }
Sergunb 0:8918a71cdbe9 188
Sergunb 0:8918a71cdbe9 189 //Check if the link is up?
Sergunb 0:8918a71cdbe9 190 if(interface->linkState)
Sergunb 0:8918a71cdbe9 191 {
Sergunb 0:8918a71cdbe9 192 //A link-local address is formed by combining the well-known
Sergunb 0:8918a71cdbe9 193 //link-local prefix fe80::/10 with the interface identifier
Sergunb 0:8918a71cdbe9 194 dhcpv6ClientGenerateLinkLocalAddr(context);
Sergunb 0:8918a71cdbe9 195 }
Sergunb 0:8918a71cdbe9 196
Sergunb 0:8918a71cdbe9 197 //Start DHCPv6 client
Sergunb 0:8918a71cdbe9 198 context->running = TRUE;
Sergunb 0:8918a71cdbe9 199 //Initialize state machine
Sergunb 0:8918a71cdbe9 200 context->state = DHCPV6_STATE_INIT;
Sergunb 0:8918a71cdbe9 201
Sergunb 0:8918a71cdbe9 202 //Release exclusive access
Sergunb 0:8918a71cdbe9 203 osReleaseMutex(&netMutex);
Sergunb 0:8918a71cdbe9 204
Sergunb 0:8918a71cdbe9 205 //Successful processing
Sergunb 0:8918a71cdbe9 206 return NO_ERROR;
Sergunb 0:8918a71cdbe9 207 }
Sergunb 0:8918a71cdbe9 208
Sergunb 0:8918a71cdbe9 209
Sergunb 0:8918a71cdbe9 210 /**
Sergunb 0:8918a71cdbe9 211 * @brief Stop DHCPv6 client
Sergunb 0:8918a71cdbe9 212 * @param[in] context Pointer to the DHCPv6 client context
Sergunb 0:8918a71cdbe9 213 * @return Error code
Sergunb 0:8918a71cdbe9 214 **/
Sergunb 0:8918a71cdbe9 215
Sergunb 0:8918a71cdbe9 216 error_t dhcpv6ClientStop(Dhcpv6ClientContext *context)
Sergunb 0:8918a71cdbe9 217 {
Sergunb 0:8918a71cdbe9 218 //Check parameter
Sergunb 0:8918a71cdbe9 219 if(context == NULL)
Sergunb 0:8918a71cdbe9 220 return ERROR_INVALID_PARAMETER;
Sergunb 0:8918a71cdbe9 221
Sergunb 0:8918a71cdbe9 222 //Debug message
Sergunb 0:8918a71cdbe9 223 TRACE_INFO("Stopping DHCPv6 client...\r\n");
Sergunb 0:8918a71cdbe9 224
Sergunb 0:8918a71cdbe9 225 //Get exclusive access
Sergunb 0:8918a71cdbe9 226 osAcquireMutex(&netMutex);
Sergunb 0:8918a71cdbe9 227
Sergunb 0:8918a71cdbe9 228 //Stop DHCPv6 client
Sergunb 0:8918a71cdbe9 229 context->running = FALSE;
Sergunb 0:8918a71cdbe9 230 //Reinitialize state machine
Sergunb 0:8918a71cdbe9 231 context->state = DHCPV6_STATE_INIT;
Sergunb 0:8918a71cdbe9 232
Sergunb 0:8918a71cdbe9 233 //Release exclusive access
Sergunb 0:8918a71cdbe9 234 osReleaseMutex(&netMutex);
Sergunb 0:8918a71cdbe9 235
Sergunb 0:8918a71cdbe9 236 //Successful processing
Sergunb 0:8918a71cdbe9 237 return NO_ERROR;
Sergunb 0:8918a71cdbe9 238 }
Sergunb 0:8918a71cdbe9 239
Sergunb 0:8918a71cdbe9 240
Sergunb 0:8918a71cdbe9 241 /**
Sergunb 0:8918a71cdbe9 242 * @brief Release DHCPv6 lease
Sergunb 0:8918a71cdbe9 243 * @param[in] context Pointer to the DHCPv6 client context
Sergunb 0:8918a71cdbe9 244 * @return Error code
Sergunb 0:8918a71cdbe9 245 **/
Sergunb 0:8918a71cdbe9 246
Sergunb 0:8918a71cdbe9 247 error_t dhcpv6ClientRelease(Dhcpv6ClientContext *context)
Sergunb 0:8918a71cdbe9 248 {
Sergunb 0:8918a71cdbe9 249 uint_t i;
Sergunb 0:8918a71cdbe9 250 NetInterface *interface;
Sergunb 0:8918a71cdbe9 251 Dhcpv6ClientAddrEntry *entry;
Sergunb 0:8918a71cdbe9 252
Sergunb 0:8918a71cdbe9 253 //Check parameter
Sergunb 0:8918a71cdbe9 254 if(context == NULL)
Sergunb 0:8918a71cdbe9 255 return ERROR_INVALID_PARAMETER;
Sergunb 0:8918a71cdbe9 256
Sergunb 0:8918a71cdbe9 257 //Debug message
Sergunb 0:8918a71cdbe9 258 TRACE_INFO("Releasing DHCPv6 lease...\r\n");
Sergunb 0:8918a71cdbe9 259
Sergunb 0:8918a71cdbe9 260 //Get exclusive access
Sergunb 0:8918a71cdbe9 261 osAcquireMutex(&netMutex);
Sergunb 0:8918a71cdbe9 262
Sergunb 0:8918a71cdbe9 263 //Point to the underlying network interface
Sergunb 0:8918a71cdbe9 264 interface = context->settings.interface;
Sergunb 0:8918a71cdbe9 265
Sergunb 0:8918a71cdbe9 266 //Check whether the DHCPv6 client is running
Sergunb 0:8918a71cdbe9 267 if(context->running)
Sergunb 0:8918a71cdbe9 268 {
Sergunb 0:8918a71cdbe9 269 //BOUND state?
Sergunb 0:8918a71cdbe9 270 if(context->state == DHCPV6_STATE_BOUND)
Sergunb 0:8918a71cdbe9 271 {
Sergunb 0:8918a71cdbe9 272 //Loop through the IPv6 addresses recorded by the DHCPv6 client
Sergunb 0:8918a71cdbe9 273 for(i = 0; i < DHCPV6_CLIENT_ADDR_LIST_SIZE; i++)
Sergunb 0:8918a71cdbe9 274 {
Sergunb 0:8918a71cdbe9 275 //Point to the current entry
Sergunb 0:8918a71cdbe9 276 entry = &context->ia.addrList[i];
Sergunb 0:8918a71cdbe9 277
Sergunb 0:8918a71cdbe9 278 //Valid IPv6 address?
Sergunb 0:8918a71cdbe9 279 if(entry->validLifetime > 0)
Sergunb 0:8918a71cdbe9 280 {
Sergunb 0:8918a71cdbe9 281 //The client must stop using the addresses being released as soon
Sergunb 0:8918a71cdbe9 282 //as the client begins the Release message exchange process
Sergunb 0:8918a71cdbe9 283 ipv6RemoveAddr(interface, &entry->addr);
Sergunb 0:8918a71cdbe9 284 }
Sergunb 0:8918a71cdbe9 285 }
Sergunb 0:8918a71cdbe9 286
Sergunb 0:8918a71cdbe9 287 //Switch to the RELEASE state
Sergunb 0:8918a71cdbe9 288 dhcpv6ClientChangeState(context, DHCPV6_STATE_RELEASE, 0);
Sergunb 0:8918a71cdbe9 289 }
Sergunb 0:8918a71cdbe9 290 else
Sergunb 0:8918a71cdbe9 291 {
Sergunb 0:8918a71cdbe9 292 //Stop DHCPv6 client
Sergunb 0:8918a71cdbe9 293 context->running = FALSE;
Sergunb 0:8918a71cdbe9 294 //Reinitialize state machine
Sergunb 0:8918a71cdbe9 295 context->state = DHCPV6_STATE_INIT;
Sergunb 0:8918a71cdbe9 296 }
Sergunb 0:8918a71cdbe9 297 }
Sergunb 0:8918a71cdbe9 298
Sergunb 0:8918a71cdbe9 299 //Release exclusive access
Sergunb 0:8918a71cdbe9 300 osReleaseMutex(&netMutex);
Sergunb 0:8918a71cdbe9 301
Sergunb 0:8918a71cdbe9 302 //Successful processing
Sergunb 0:8918a71cdbe9 303 return NO_ERROR;
Sergunb 0:8918a71cdbe9 304 }
Sergunb 0:8918a71cdbe9 305
Sergunb 0:8918a71cdbe9 306
Sergunb 0:8918a71cdbe9 307 /**
Sergunb 0:8918a71cdbe9 308 * @brief Retrieve current state
Sergunb 0:8918a71cdbe9 309 * @param[in] context Pointer to the DHCPv6 client context
Sergunb 0:8918a71cdbe9 310 * @return Current DHCPv6 client state
Sergunb 0:8918a71cdbe9 311 **/
Sergunb 0:8918a71cdbe9 312
Sergunb 0:8918a71cdbe9 313 Dhcpv6State dhcpv6ClientGetState(Dhcpv6ClientContext *context)
Sergunb 0:8918a71cdbe9 314 {
Sergunb 0:8918a71cdbe9 315 Dhcpv6State state;
Sergunb 0:8918a71cdbe9 316
Sergunb 0:8918a71cdbe9 317 //Get exclusive access
Sergunb 0:8918a71cdbe9 318 osAcquireMutex(&netMutex);
Sergunb 0:8918a71cdbe9 319 //Get current state
Sergunb 0:8918a71cdbe9 320 state = context->state;
Sergunb 0:8918a71cdbe9 321 //Release exclusive access
Sergunb 0:8918a71cdbe9 322 osReleaseMutex(&netMutex);
Sergunb 0:8918a71cdbe9 323
Sergunb 0:8918a71cdbe9 324 //Return current state
Sergunb 0:8918a71cdbe9 325 return state;
Sergunb 0:8918a71cdbe9 326 }
Sergunb 0:8918a71cdbe9 327
Sergunb 0:8918a71cdbe9 328
Sergunb 0:8918a71cdbe9 329 /**
Sergunb 0:8918a71cdbe9 330 * @brief DHCPv6 client timer handler
Sergunb 0:8918a71cdbe9 331 *
Sergunb 0:8918a71cdbe9 332 * This routine must be periodically called by the TCP/IP stack to
Sergunb 0:8918a71cdbe9 333 * manage DHCPv6 client operation
Sergunb 0:8918a71cdbe9 334 *
Sergunb 0:8918a71cdbe9 335 * @param[in] context Pointer to the DHCPv6 client context
Sergunb 0:8918a71cdbe9 336 **/
Sergunb 0:8918a71cdbe9 337
Sergunb 0:8918a71cdbe9 338
Sergunb 0:8918a71cdbe9 339 void dhcpv6ClientTick(Dhcpv6ClientContext *context)
Sergunb 0:8918a71cdbe9 340 {
Sergunb 0:8918a71cdbe9 341 //Make sure the DHCPv6 client has been properly instantiated
Sergunb 0:8918a71cdbe9 342 if(context == NULL)
Sergunb 0:8918a71cdbe9 343 return;
Sergunb 0:8918a71cdbe9 344
Sergunb 0:8918a71cdbe9 345 //DHCPv6 client finite state machine
Sergunb 0:8918a71cdbe9 346 switch(context->state)
Sergunb 0:8918a71cdbe9 347 {
Sergunb 0:8918a71cdbe9 348 //Process INIT state
Sergunb 0:8918a71cdbe9 349 case DHCPV6_STATE_INIT:
Sergunb 0:8918a71cdbe9 350 //This is the initialization state, where a client begins the process of
Sergunb 0:8918a71cdbe9 351 //acquiring a lease. It also returns here when a lease ends, or when a
Sergunb 0:8918a71cdbe9 352 //lease negotiation fails
Sergunb 0:8918a71cdbe9 353 dhcpv6ClientStateInit(context);
Sergunb 0:8918a71cdbe9 354 break;
Sergunb 0:8918a71cdbe9 355 //Process SOLICIT state
Sergunb 0:8918a71cdbe9 356 case DHCPV6_STATE_SOLICIT:
Sergunb 0:8918a71cdbe9 357 //The client sends a Solicit message to locate servers
Sergunb 0:8918a71cdbe9 358 dhcpv6ClientStateSolicit(context);
Sergunb 0:8918a71cdbe9 359 break;
Sergunb 0:8918a71cdbe9 360 //Process REQUEST state
Sergunb 0:8918a71cdbe9 361 case DHCPV6_STATE_REQUEST:
Sergunb 0:8918a71cdbe9 362 //The client sends a Request message to request configuration
Sergunb 0:8918a71cdbe9 363 //parameters, including IP addresses, from a specific server
Sergunb 0:8918a71cdbe9 364 dhcpv6ClientStateRequest(context);
Sergunb 0:8918a71cdbe9 365 break;
Sergunb 0:8918a71cdbe9 366 //Process INIT-CONFIRM state
Sergunb 0:8918a71cdbe9 367 case DHCPV6_STATE_INIT_CONFIRM:
Sergunb 0:8918a71cdbe9 368 //When a client that already has a valid lease starts up after a
Sergunb 0:8918a71cdbe9 369 //power-down or reboot, it starts here instead of the INIT state
Sergunb 0:8918a71cdbe9 370 dhcpv6ClientStateInitConfirm(context);
Sergunb 0:8918a71cdbe9 371 break;
Sergunb 0:8918a71cdbe9 372 //Process CONFIRM state
Sergunb 0:8918a71cdbe9 373 case DHCPV6_STATE_CONFIRM:
Sergunb 0:8918a71cdbe9 374 //The client sends a Confirm message to any available server
Sergunb 0:8918a71cdbe9 375 //to determine whether the addresses it was assigned are still
Sergunb 0:8918a71cdbe9 376 //appropriate to the link to which the client is connected
Sergunb 0:8918a71cdbe9 377 dhcpv6ClientStateConfirm(context);
Sergunb 0:8918a71cdbe9 378 break;
Sergunb 0:8918a71cdbe9 379 //Process DAD state
Sergunb 0:8918a71cdbe9 380 case DHCPV6_STATE_DAD:
Sergunb 0:8918a71cdbe9 381 //The client should perform duplicate address detection on each
Sergunb 0:8918a71cdbe9 382 //of the addresses in any IAs it receives in the Reply message
Sergunb 0:8918a71cdbe9 383 //before using that address for traffic
Sergunb 0:8918a71cdbe9 384 dhcpv6ClientStateDad(context);
Sergunb 0:8918a71cdbe9 385 break;
Sergunb 0:8918a71cdbe9 386 //Process BOUND state
Sergunb 0:8918a71cdbe9 387 case DHCPV6_STATE_BOUND:
Sergunb 0:8918a71cdbe9 388 //The client has a valid lease and is in its normal operating state
Sergunb 0:8918a71cdbe9 389 dhcpv6ClientStateBound(context);
Sergunb 0:8918a71cdbe9 390 break;
Sergunb 0:8918a71cdbe9 391 //Process RENEW state
Sergunb 0:8918a71cdbe9 392 case DHCPV6_STATE_RENEW:
Sergunb 0:8918a71cdbe9 393 //The client sends a Renew message to the server that originally
Sergunb 0:8918a71cdbe9 394 //provided the client's addresses and configuration parameters to
Sergunb 0:8918a71cdbe9 395 //extend the lifetimes on the addresses assigned to the client
Sergunb 0:8918a71cdbe9 396 //and to update other configuration parameters
Sergunb 0:8918a71cdbe9 397 dhcpv6ClientStateRenew(context);
Sergunb 0:8918a71cdbe9 398 break;
Sergunb 0:8918a71cdbe9 399 //Process REBIND state
Sergunb 0:8918a71cdbe9 400 case DHCPV6_STATE_REBIND:
Sergunb 0:8918a71cdbe9 401 //The client sends a Rebind message to any available server to extend
Sergunb 0:8918a71cdbe9 402 //the lifetimes on the addresses assigned to the client and to update
Sergunb 0:8918a71cdbe9 403 //other configuration parameters. This message is sent after a client
Sergunb 0:8918a71cdbe9 404 //receives no response to a Renew message
Sergunb 0:8918a71cdbe9 405 dhcpv6ClientStateRebind(context);
Sergunb 0:8918a71cdbe9 406 break;
Sergunb 0:8918a71cdbe9 407 //Process RELEASE state
Sergunb 0:8918a71cdbe9 408 case DHCPV6_STATE_RELEASE:
Sergunb 0:8918a71cdbe9 409 //To release one or more addresses, a client sends a Release message
Sergunb 0:8918a71cdbe9 410 //to the server
Sergunb 0:8918a71cdbe9 411 dhcpv6ClientStateRelease(context);
Sergunb 0:8918a71cdbe9 412 break;
Sergunb 0:8918a71cdbe9 413 //Process DECLINE state
Sergunb 0:8918a71cdbe9 414 case DHCPV6_STATE_DECLINE:
Sergunb 0:8918a71cdbe9 415 //If a client detects that one or more addresses assigned to it by a
Sergunb 0:8918a71cdbe9 416 //server are already in use by another node, the client sends a Decline
Sergunb 0:8918a71cdbe9 417 //message to the server to inform it that the address is suspect
Sergunb 0:8918a71cdbe9 418 dhcpv6ClientStateDecline(context);
Sergunb 0:8918a71cdbe9 419 break;
Sergunb 0:8918a71cdbe9 420 //Invalid state...
Sergunb 0:8918a71cdbe9 421 default:
Sergunb 0:8918a71cdbe9 422 //Switch to the default state
Sergunb 0:8918a71cdbe9 423 context->state = DHCPV6_STATE_INIT;
Sergunb 0:8918a71cdbe9 424 break;
Sergunb 0:8918a71cdbe9 425 }
Sergunb 0:8918a71cdbe9 426 }
Sergunb 0:8918a71cdbe9 427
Sergunb 0:8918a71cdbe9 428
Sergunb 0:8918a71cdbe9 429 /**
Sergunb 0:8918a71cdbe9 430 * @brief Callback function for link change event
Sergunb 0:8918a71cdbe9 431 * @param[in] context Pointer to the DHCPv6 client context
Sergunb 0:8918a71cdbe9 432 **/
Sergunb 0:8918a71cdbe9 433
Sergunb 0:8918a71cdbe9 434 void dhcpv6ClientLinkChangeEvent(Dhcpv6ClientContext *context)
Sergunb 0:8918a71cdbe9 435 {
Sergunb 0:8918a71cdbe9 436 NetInterface *interface;
Sergunb 0:8918a71cdbe9 437
Sergunb 0:8918a71cdbe9 438 //Make sure the DHCPv6 client has been properly instantiated
Sergunb 0:8918a71cdbe9 439 if(context == NULL)
Sergunb 0:8918a71cdbe9 440 return;
Sergunb 0:8918a71cdbe9 441
Sergunb 0:8918a71cdbe9 442 //Point to the underlying network interface
Sergunb 0:8918a71cdbe9 443 interface = context->settings.interface;
Sergunb 0:8918a71cdbe9 444
Sergunb 0:8918a71cdbe9 445 //Check whether the DHCPv6 client is running
Sergunb 0:8918a71cdbe9 446 if(context->running)
Sergunb 0:8918a71cdbe9 447 {
Sergunb 0:8918a71cdbe9 448 //Automatic DNS server configuration?
Sergunb 0:8918a71cdbe9 449 if(!context->settings.manualDnsConfig)
Sergunb 0:8918a71cdbe9 450 {
Sergunb 0:8918a71cdbe9 451 //Clear the list of DNS servers
Sergunb 0:8918a71cdbe9 452 ipv6FlushDnsServerList(interface);
Sergunb 0:8918a71cdbe9 453 }
Sergunb 0:8918a71cdbe9 454
Sergunb 0:8918a71cdbe9 455 //Link-up event?
Sergunb 0:8918a71cdbe9 456 if(interface->linkState)
Sergunb 0:8918a71cdbe9 457 {
Sergunb 0:8918a71cdbe9 458 //A link-local address is formed by combining the well-known
Sergunb 0:8918a71cdbe9 459 //link-local prefix fe80::/10 with the interface identifier
Sergunb 0:8918a71cdbe9 460 dhcpv6ClientGenerateLinkLocalAddr(context);
Sergunb 0:8918a71cdbe9 461 }
Sergunb 0:8918a71cdbe9 462 }
Sergunb 0:8918a71cdbe9 463
Sergunb 0:8918a71cdbe9 464 //Check the state of the DHCPv6 client
Sergunb 0:8918a71cdbe9 465 switch(context->state)
Sergunb 0:8918a71cdbe9 466 {
Sergunb 0:8918a71cdbe9 467 case DHCPV6_STATE_INIT_CONFIRM:
Sergunb 0:8918a71cdbe9 468 case DHCPV6_STATE_CONFIRM :
Sergunb 0:8918a71cdbe9 469 case DHCPV6_STATE_DAD:
Sergunb 0:8918a71cdbe9 470 case DHCPV6_STATE_BOUND:
Sergunb 0:8918a71cdbe9 471 case DHCPV6_STATE_RENEW:
Sergunb 0:8918a71cdbe9 472 case DHCPV6_STATE_REBIND:
Sergunb 0:8918a71cdbe9 473 //The client already has a valid lease
Sergunb 0:8918a71cdbe9 474 context->state = DHCPV6_STATE_INIT_CONFIRM;
Sergunb 0:8918a71cdbe9 475 break;
Sergunb 0:8918a71cdbe9 476 case DHCPV6_STATE_RELEASE:
Sergunb 0:8918a71cdbe9 477 //Stop DHCPv6 client
Sergunb 0:8918a71cdbe9 478 context->running = FALSE;
Sergunb 0:8918a71cdbe9 479 //Reinitialize state machine
Sergunb 0:8918a71cdbe9 480 context->state = DHCPV6_STATE_INIT;
Sergunb 0:8918a71cdbe9 481 break;
Sergunb 0:8918a71cdbe9 482 default:
Sergunb 0:8918a71cdbe9 483 //Switch to the INIT state
Sergunb 0:8918a71cdbe9 484 context->state = DHCPV6_STATE_INIT;
Sergunb 0:8918a71cdbe9 485 break;
Sergunb 0:8918a71cdbe9 486 }
Sergunb 0:8918a71cdbe9 487
Sergunb 0:8918a71cdbe9 488 //Any registered callback?
Sergunb 0:8918a71cdbe9 489 if(context->settings.linkChangeEvent != NULL)
Sergunb 0:8918a71cdbe9 490 {
Sergunb 0:8918a71cdbe9 491 //Release exclusive access
Sergunb 0:8918a71cdbe9 492 osReleaseMutex(&netMutex);
Sergunb 0:8918a71cdbe9 493 //Invoke user callback function
Sergunb 0:8918a71cdbe9 494 context->settings.linkChangeEvent(context, interface, interface->linkState);
Sergunb 0:8918a71cdbe9 495 //Get exclusive access
Sergunb 0:8918a71cdbe9 496 osAcquireMutex(&netMutex);
Sergunb 0:8918a71cdbe9 497 }
Sergunb 0:8918a71cdbe9 498 }
Sergunb 0:8918a71cdbe9 499
Sergunb 0:8918a71cdbe9 500
Sergunb 0:8918a71cdbe9 501 /**
Sergunb 0:8918a71cdbe9 502 * @brief INIT state
Sergunb 0:8918a71cdbe9 503 *
Sergunb 0:8918a71cdbe9 504 * This is the initialization state, where a client begins the process of
Sergunb 0:8918a71cdbe9 505 * acquiring a lease. It also returns here when a lease ends, or when a
Sergunb 0:8918a71cdbe9 506 * lease negotiation fails
Sergunb 0:8918a71cdbe9 507 *
Sergunb 0:8918a71cdbe9 508 * @param[in] context Pointer to the DHCPv6 client context
Sergunb 0:8918a71cdbe9 509 **/
Sergunb 0:8918a71cdbe9 510
Sergunb 0:8918a71cdbe9 511 void dhcpv6ClientStateInit(Dhcpv6ClientContext *context)
Sergunb 0:8918a71cdbe9 512 {
Sergunb 0:8918a71cdbe9 513 systime_t delay;
Sergunb 0:8918a71cdbe9 514 NetInterface *interface;
Sergunb 0:8918a71cdbe9 515
Sergunb 0:8918a71cdbe9 516 //Point to the underlying network interface
Sergunb 0:8918a71cdbe9 517 interface = context->settings.interface;
Sergunb 0:8918a71cdbe9 518
Sergunb 0:8918a71cdbe9 519 //Check whether the DHCPv6 client is running
Sergunb 0:8918a71cdbe9 520 if(context->running)
Sergunb 0:8918a71cdbe9 521 {
Sergunb 0:8918a71cdbe9 522 //Wait for the link to be up before starting DHCPv6 configuration
Sergunb 0:8918a71cdbe9 523 if(interface->linkState)
Sergunb 0:8918a71cdbe9 524 {
Sergunb 0:8918a71cdbe9 525 //Make sure that a valid link-local address has been assigned to the interface
Sergunb 0:8918a71cdbe9 526 if(ipv6GetLinkLocalAddrState(interface) == IPV6_ADDR_STATE_PREFERRED)
Sergunb 0:8918a71cdbe9 527 {
Sergunb 0:8918a71cdbe9 528 //Flush the list of IPv6 addresses from the client's IA
Sergunb 0:8918a71cdbe9 529 dhcpv6ClientFlushAddrList(context);
Sergunb 0:8918a71cdbe9 530
Sergunb 0:8918a71cdbe9 531 //The first Solicit message from the client on the interface must be
Sergunb 0:8918a71cdbe9 532 //delayed by a random amount of time between 0 and SOL_MAX_DELAY
Sergunb 0:8918a71cdbe9 533 delay = dhcpv6RandRange(0, DHCPV6_CLIENT_SOL_MAX_DELAY);
Sergunb 0:8918a71cdbe9 534
Sergunb 0:8918a71cdbe9 535 //Record the time at which the client started
Sergunb 0:8918a71cdbe9 536 //the address acquisition process
Sergunb 0:8918a71cdbe9 537 context->configStartTime = osGetSystemTime();
Sergunb 0:8918a71cdbe9 538 //Clear flag
Sergunb 0:8918a71cdbe9 539 context->timeoutEventDone = FALSE;
Sergunb 0:8918a71cdbe9 540
Sergunb 0:8918a71cdbe9 541 //Switch to the SOLICIT state
Sergunb 0:8918a71cdbe9 542 dhcpv6ClientChangeState(context, DHCPV6_STATE_SOLICIT, delay);
Sergunb 0:8918a71cdbe9 543 }
Sergunb 0:8918a71cdbe9 544 }
Sergunb 0:8918a71cdbe9 545 }
Sergunb 0:8918a71cdbe9 546 }
Sergunb 0:8918a71cdbe9 547
Sergunb 0:8918a71cdbe9 548
Sergunb 0:8918a71cdbe9 549 /**
Sergunb 0:8918a71cdbe9 550 * @brief SOLICIT state
Sergunb 0:8918a71cdbe9 551 *
Sergunb 0:8918a71cdbe9 552 * A client uses the Solicit message to discover DHCPv6 servers
Sergunb 0:8918a71cdbe9 553 *
Sergunb 0:8918a71cdbe9 554 * @param[in] context Pointer to the DHCPv6 client context
Sergunb 0:8918a71cdbe9 555 **/
Sergunb 0:8918a71cdbe9 556
Sergunb 0:8918a71cdbe9 557 void dhcpv6ClientStateSolicit(Dhcpv6ClientContext *context)
Sergunb 0:8918a71cdbe9 558 {
Sergunb 0:8918a71cdbe9 559 systime_t time;
Sergunb 0:8918a71cdbe9 560
Sergunb 0:8918a71cdbe9 561 //Get current time
Sergunb 0:8918a71cdbe9 562 time = osGetSystemTime();
Sergunb 0:8918a71cdbe9 563
Sergunb 0:8918a71cdbe9 564 //Check current time
Sergunb 0:8918a71cdbe9 565 if(timeCompare(time, context->timestamp + context->timeout) >= 0)
Sergunb 0:8918a71cdbe9 566 {
Sergunb 0:8918a71cdbe9 567 //Check retransmission counter
Sergunb 0:8918a71cdbe9 568 if(context->retransmitCount == 0)
Sergunb 0:8918a71cdbe9 569 {
Sergunb 0:8918a71cdbe9 570 //Reset server preference value
Sergunb 0:8918a71cdbe9 571 context->serverPreference = -1;
Sergunb 0:8918a71cdbe9 572 //Generate a 24-bit transaction ID
Sergunb 0:8918a71cdbe9 573 context->transactionId = netGetRand() & 0x00FFFFFF;
Sergunb 0:8918a71cdbe9 574
Sergunb 0:8918a71cdbe9 575 //Send a Solicit message
Sergunb 0:8918a71cdbe9 576 dhcpv6ClientSendMessage(context, DHCPV6_MSG_TYPE_SOLICIT);
Sergunb 0:8918a71cdbe9 577
Sergunb 0:8918a71cdbe9 578 //Save the time at which the message was sent
Sergunb 0:8918a71cdbe9 579 context->exchangeStartTime = time;
Sergunb 0:8918a71cdbe9 580 context->timestamp = time;
Sergunb 0:8918a71cdbe9 581
Sergunb 0:8918a71cdbe9 582 //If the client is waiting for an Advertise message, the first RT
Sergunb 0:8918a71cdbe9 583 //must be selected to be strictly greater than IRT
Sergunb 0:8918a71cdbe9 584 context->timeout = DHCPV6_CLIENT_SOL_TIMEOUT +
Sergunb 0:8918a71cdbe9 585 abs(dhcpv6Rand(DHCPV6_CLIENT_SOL_TIMEOUT));
Sergunb 0:8918a71cdbe9 586
Sergunb 0:8918a71cdbe9 587 //Increment retransmission counter
Sergunb 0:8918a71cdbe9 588 context->retransmitCount++;
Sergunb 0:8918a71cdbe9 589 }
Sergunb 0:8918a71cdbe9 590 else
Sergunb 0:8918a71cdbe9 591 {
Sergunb 0:8918a71cdbe9 592 //Check whether a valid Advertise message has been received
Sergunb 0:8918a71cdbe9 593 if(context->serverPreference >= 0)
Sergunb 0:8918a71cdbe9 594 {
Sergunb 0:8918a71cdbe9 595 //Continue configuration procedure
Sergunb 0:8918a71cdbe9 596 dhcpv6ClientChangeState(context, DHCPV6_STATE_REQUEST, 0);
Sergunb 0:8918a71cdbe9 597 }
Sergunb 0:8918a71cdbe9 598 else
Sergunb 0:8918a71cdbe9 599 {
Sergunb 0:8918a71cdbe9 600 //Send a Solicit message
Sergunb 0:8918a71cdbe9 601 dhcpv6ClientSendMessage(context, DHCPV6_MSG_TYPE_SOLICIT);
Sergunb 0:8918a71cdbe9 602
Sergunb 0:8918a71cdbe9 603 //Save the time at which the message was sent
Sergunb 0:8918a71cdbe9 604 context->timestamp = time;
Sergunb 0:8918a71cdbe9 605
Sergunb 0:8918a71cdbe9 606 //The RT is doubled for each subsequent retransmission
Sergunb 0:8918a71cdbe9 607 context->timeout = context->timeout * 2 + dhcpv6Rand(context->timeout);
Sergunb 0:8918a71cdbe9 608
Sergunb 0:8918a71cdbe9 609 //MRT specifies an upper bound on the value of RT
Sergunb 0:8918a71cdbe9 610 if(context->timeout > DHCPV6_CLIENT_SOL_MAX_RT)
Sergunb 0:8918a71cdbe9 611 {
Sergunb 0:8918a71cdbe9 612 //Compute retransmission timeout
Sergunb 0:8918a71cdbe9 613 context->timeout = DHCPV6_CLIENT_SOL_MAX_RT +
Sergunb 0:8918a71cdbe9 614 dhcpv6Rand(DHCPV6_CLIENT_SOL_MAX_RT);
Sergunb 0:8918a71cdbe9 615 }
Sergunb 0:8918a71cdbe9 616
Sergunb 0:8918a71cdbe9 617 //Increment retransmission counter
Sergunb 0:8918a71cdbe9 618 context->retransmitCount++;
Sergunb 0:8918a71cdbe9 619 }
Sergunb 0:8918a71cdbe9 620 }
Sergunb 0:8918a71cdbe9 621 }
Sergunb 0:8918a71cdbe9 622
Sergunb 0:8918a71cdbe9 623 //Manage DHCPv6 configuration timeout
Sergunb 0:8918a71cdbe9 624 dhcpv6ClientCheckTimeout(context);
Sergunb 0:8918a71cdbe9 625 }
Sergunb 0:8918a71cdbe9 626
Sergunb 0:8918a71cdbe9 627
Sergunb 0:8918a71cdbe9 628 /**
Sergunb 0:8918a71cdbe9 629 * @brief REQUEST state
Sergunb 0:8918a71cdbe9 630 *
Sergunb 0:8918a71cdbe9 631 * The client uses a Request message to populate IAs with addresses and obtain
Sergunb 0:8918a71cdbe9 632 * other configuration information. The client includes one or more more IA
Sergunb 0:8918a71cdbe9 633 * options in the Request message. The server then returns addresses and other
Sergunb 0:8918a71cdbe9 634 * information about the IAs to the client in IA options in a Reply message
Sergunb 0:8918a71cdbe9 635 *
Sergunb 0:8918a71cdbe9 636 * @param[in] context Pointer to the DHCPv6 client context
Sergunb 0:8918a71cdbe9 637 **/
Sergunb 0:8918a71cdbe9 638
Sergunb 0:8918a71cdbe9 639 void dhcpv6ClientStateRequest(Dhcpv6ClientContext *context)
Sergunb 0:8918a71cdbe9 640 {
Sergunb 0:8918a71cdbe9 641 systime_t time;
Sergunb 0:8918a71cdbe9 642
Sergunb 0:8918a71cdbe9 643 //Get current time
Sergunb 0:8918a71cdbe9 644 time = osGetSystemTime();
Sergunb 0:8918a71cdbe9 645
Sergunb 0:8918a71cdbe9 646 //Check current time
Sergunb 0:8918a71cdbe9 647 if(timeCompare(time, context->timestamp + context->timeout) >= 0)
Sergunb 0:8918a71cdbe9 648 {
Sergunb 0:8918a71cdbe9 649 //Check retransmission counter
Sergunb 0:8918a71cdbe9 650 if(context->retransmitCount == 0)
Sergunb 0:8918a71cdbe9 651 {
Sergunb 0:8918a71cdbe9 652 //Generate a 24-bit transaction ID
Sergunb 0:8918a71cdbe9 653 context->transactionId = netGetRand() & 0x00FFFFFF;
Sergunb 0:8918a71cdbe9 654
Sergunb 0:8918a71cdbe9 655 //Send a Request message
Sergunb 0:8918a71cdbe9 656 dhcpv6ClientSendMessage(context, DHCPV6_MSG_TYPE_REQUEST);
Sergunb 0:8918a71cdbe9 657
Sergunb 0:8918a71cdbe9 658 //Save the time at which the message was sent
Sergunb 0:8918a71cdbe9 659 context->exchangeStartTime = time;
Sergunb 0:8918a71cdbe9 660 context->timestamp = time;
Sergunb 0:8918a71cdbe9 661
Sergunb 0:8918a71cdbe9 662 //Initial retransmission timeout
Sergunb 0:8918a71cdbe9 663 context->timeout = DHCPV6_CLIENT_REQ_TIMEOUT +
Sergunb 0:8918a71cdbe9 664 dhcpv6Rand(DHCPV6_CLIENT_REQ_TIMEOUT);
Sergunb 0:8918a71cdbe9 665
Sergunb 0:8918a71cdbe9 666 //Increment retransmission counter
Sergunb 0:8918a71cdbe9 667 context->retransmitCount++;
Sergunb 0:8918a71cdbe9 668 }
Sergunb 0:8918a71cdbe9 669 else if(context->retransmitCount < DHCPV6_CLIENT_REQ_MAX_RC)
Sergunb 0:8918a71cdbe9 670 {
Sergunb 0:8918a71cdbe9 671 //Send a Request message
Sergunb 0:8918a71cdbe9 672 dhcpv6ClientSendMessage(context, DHCPV6_MSG_TYPE_REQUEST);
Sergunb 0:8918a71cdbe9 673
Sergunb 0:8918a71cdbe9 674 //Save the time at which the message was sent
Sergunb 0:8918a71cdbe9 675 context->timestamp = time;
Sergunb 0:8918a71cdbe9 676
Sergunb 0:8918a71cdbe9 677 //The RT is doubled for each subsequent retransmission
Sergunb 0:8918a71cdbe9 678 context->timeout = context->timeout * 2 + dhcpv6Rand(context->timeout);
Sergunb 0:8918a71cdbe9 679
Sergunb 0:8918a71cdbe9 680 //MRT specifies an upper bound on the value of RT
Sergunb 0:8918a71cdbe9 681 if(context->timeout > DHCPV6_CLIENT_REQ_MAX_RT)
Sergunb 0:8918a71cdbe9 682 {
Sergunb 0:8918a71cdbe9 683 //Compute retransmission timeout
Sergunb 0:8918a71cdbe9 684 context->timeout = DHCPV6_CLIENT_REQ_MAX_RT +
Sergunb 0:8918a71cdbe9 685 dhcpv6Rand(DHCPV6_CLIENT_REQ_MAX_RT);
Sergunb 0:8918a71cdbe9 686 }
Sergunb 0:8918a71cdbe9 687
Sergunb 0:8918a71cdbe9 688 //Increment retransmission counter
Sergunb 0:8918a71cdbe9 689 context->retransmitCount++;
Sergunb 0:8918a71cdbe9 690 }
Sergunb 0:8918a71cdbe9 691 else
Sergunb 0:8918a71cdbe9 692 {
Sergunb 0:8918a71cdbe9 693 //If the client does not receive a response within a reasonable
Sergunb 0:8918a71cdbe9 694 //period of time, then it restarts the initialization procedure
Sergunb 0:8918a71cdbe9 695 dhcpv6ClientChangeState(context, DHCPV6_STATE_INIT, 0);
Sergunb 0:8918a71cdbe9 696 }
Sergunb 0:8918a71cdbe9 697 }
Sergunb 0:8918a71cdbe9 698
Sergunb 0:8918a71cdbe9 699 //Manage DHCPv6 configuration timeout
Sergunb 0:8918a71cdbe9 700 dhcpv6ClientCheckTimeout(context);
Sergunb 0:8918a71cdbe9 701 }
Sergunb 0:8918a71cdbe9 702
Sergunb 0:8918a71cdbe9 703
Sergunb 0:8918a71cdbe9 704 /**
Sergunb 0:8918a71cdbe9 705 * @brief INIT-CONFIRM state
Sergunb 0:8918a71cdbe9 706 *
Sergunb 0:8918a71cdbe9 707 * When a client that already has a valid lease starts up after a
Sergunb 0:8918a71cdbe9 708 * power-down or reboot, it starts here instead of the INIT state
Sergunb 0:8918a71cdbe9 709 *
Sergunb 0:8918a71cdbe9 710 * @param[in] context Pointer to the DHCPv6 client context
Sergunb 0:8918a71cdbe9 711 **/
Sergunb 0:8918a71cdbe9 712
Sergunb 0:8918a71cdbe9 713 void dhcpv6ClientStateInitConfirm(Dhcpv6ClientContext *context)
Sergunb 0:8918a71cdbe9 714 {
Sergunb 0:8918a71cdbe9 715 systime_t delay;
Sergunb 0:8918a71cdbe9 716 NetInterface *interface;
Sergunb 0:8918a71cdbe9 717
Sergunb 0:8918a71cdbe9 718 //Point to the underlying network interface
Sergunb 0:8918a71cdbe9 719 interface = context->settings.interface;
Sergunb 0:8918a71cdbe9 720
Sergunb 0:8918a71cdbe9 721 //Check whether the DHCPv6 client is running
Sergunb 0:8918a71cdbe9 722 if(context->running)
Sergunb 0:8918a71cdbe9 723 {
Sergunb 0:8918a71cdbe9 724 //Wait for the link to be up before starting DHCPv6 configuration
Sergunb 0:8918a71cdbe9 725 if(interface->linkState)
Sergunb 0:8918a71cdbe9 726 {
Sergunb 0:8918a71cdbe9 727 //Make sure that a valid link-local address has been assigned to the interface
Sergunb 0:8918a71cdbe9 728 if(ipv6GetLinkLocalAddrState(interface) == IPV6_ADDR_STATE_PREFERRED)
Sergunb 0:8918a71cdbe9 729 {
Sergunb 0:8918a71cdbe9 730 //The first Confirm message from the client on the interface must be
Sergunb 0:8918a71cdbe9 731 //delayed by a random amount of time between 0 and CNF_MAX_DELAY
Sergunb 0:8918a71cdbe9 732 delay = dhcpv6RandRange(0, DHCPV6_CLIENT_CNF_MAX_DELAY);
Sergunb 0:8918a71cdbe9 733
Sergunb 0:8918a71cdbe9 734 //Record the time at which the client started
Sergunb 0:8918a71cdbe9 735 //the address acquisition process
Sergunb 0:8918a71cdbe9 736 context->configStartTime = osGetSystemTime();
Sergunb 0:8918a71cdbe9 737 //Clear flag
Sergunb 0:8918a71cdbe9 738 context->timeoutEventDone = FALSE;
Sergunb 0:8918a71cdbe9 739
Sergunb 0:8918a71cdbe9 740 //Switch to the CONFIRM state
Sergunb 0:8918a71cdbe9 741 dhcpv6ClientChangeState(context, DHCPV6_STATE_CONFIRM, delay);
Sergunb 0:8918a71cdbe9 742 }
Sergunb 0:8918a71cdbe9 743 }
Sergunb 0:8918a71cdbe9 744 }
Sergunb 0:8918a71cdbe9 745 }
Sergunb 0:8918a71cdbe9 746
Sergunb 0:8918a71cdbe9 747
Sergunb 0:8918a71cdbe9 748 /**
Sergunb 0:8918a71cdbe9 749 * @brief CONFIRM state
Sergunb 0:8918a71cdbe9 750 *
Sergunb 0:8918a71cdbe9 751 * Whenever a client may have moved to a new link, the prefixes from
Sergunb 0:8918a71cdbe9 752 * the addresses assigned to the interfaces on that link may no longer
Sergunb 0:8918a71cdbe9 753 * be appropriate for the link to which the client is attached. In such
Sergunb 0:8918a71cdbe9 754 * the client must initiate a Confirm/Reply message exchange
Sergunb 0:8918a71cdbe9 755 *
Sergunb 0:8918a71cdbe9 756 * @param[in] context Pointer to the DHCPv6 client context
Sergunb 0:8918a71cdbe9 757 **/
Sergunb 0:8918a71cdbe9 758
Sergunb 0:8918a71cdbe9 759 void dhcpv6ClientStateConfirm(Dhcpv6ClientContext *context)
Sergunb 0:8918a71cdbe9 760 {
Sergunb 0:8918a71cdbe9 761 systime_t time;
Sergunb 0:8918a71cdbe9 762
Sergunb 0:8918a71cdbe9 763 //Get current time
Sergunb 0:8918a71cdbe9 764 time = osGetSystemTime();
Sergunb 0:8918a71cdbe9 765
Sergunb 0:8918a71cdbe9 766 //Check current time
Sergunb 0:8918a71cdbe9 767 if(timeCompare(time, context->timestamp + context->timeout) >= 0)
Sergunb 0:8918a71cdbe9 768 {
Sergunb 0:8918a71cdbe9 769 //Check retransmission counter
Sergunb 0:8918a71cdbe9 770 if(context->retransmitCount == 0)
Sergunb 0:8918a71cdbe9 771 {
Sergunb 0:8918a71cdbe9 772 //Generate a 24-bit transaction ID
Sergunb 0:8918a71cdbe9 773 context->transactionId = netGetRand() & 0x00FFFFFF;
Sergunb 0:8918a71cdbe9 774
Sergunb 0:8918a71cdbe9 775 //Send a Confirm message
Sergunb 0:8918a71cdbe9 776 dhcpv6ClientSendMessage(context, DHCPV6_MSG_TYPE_CONFIRM);
Sergunb 0:8918a71cdbe9 777
Sergunb 0:8918a71cdbe9 778 //Save the time at which the client sent the first message
Sergunb 0:8918a71cdbe9 779 context->exchangeStartTime = time;
Sergunb 0:8918a71cdbe9 780 context->timestamp = time;
Sergunb 0:8918a71cdbe9 781
Sergunb 0:8918a71cdbe9 782 //Initial retransmission timeout
Sergunb 0:8918a71cdbe9 783 context->timeout = DHCPV6_CLIENT_CNF_TIMEOUT +
Sergunb 0:8918a71cdbe9 784 dhcpv6Rand(DHCPV6_CLIENT_CNF_TIMEOUT);
Sergunb 0:8918a71cdbe9 785
Sergunb 0:8918a71cdbe9 786 //Increment retransmission counter
Sergunb 0:8918a71cdbe9 787 context->retransmitCount++;
Sergunb 0:8918a71cdbe9 788 }
Sergunb 0:8918a71cdbe9 789 else
Sergunb 0:8918a71cdbe9 790 {
Sergunb 0:8918a71cdbe9 791 //Send a Confirm message
Sergunb 0:8918a71cdbe9 792 dhcpv6ClientSendMessage(context, DHCPV6_MSG_TYPE_CONFIRM);
Sergunb 0:8918a71cdbe9 793
Sergunb 0:8918a71cdbe9 794 //Save the time at which the message was sent
Sergunb 0:8918a71cdbe9 795 context->timestamp = time;
Sergunb 0:8918a71cdbe9 796
Sergunb 0:8918a71cdbe9 797 //The RT is doubled for each subsequent retransmission
Sergunb 0:8918a71cdbe9 798 context->timeout = context->timeout * 2 + dhcpv6Rand(context->timeout);
Sergunb 0:8918a71cdbe9 799
Sergunb 0:8918a71cdbe9 800 //MRT specifies an upper bound on the value of RT
Sergunb 0:8918a71cdbe9 801 if(context->timeout > DHCPV6_CLIENT_CNF_MAX_RT)
Sergunb 0:8918a71cdbe9 802 {
Sergunb 0:8918a71cdbe9 803 //Compute retransmission timeout
Sergunb 0:8918a71cdbe9 804 context->timeout = DHCPV6_CLIENT_CNF_MAX_RT +
Sergunb 0:8918a71cdbe9 805 dhcpv6Rand(DHCPV6_CLIENT_CNF_MAX_RT);
Sergunb 0:8918a71cdbe9 806 }
Sergunb 0:8918a71cdbe9 807
Sergunb 0:8918a71cdbe9 808 //Increment retransmission counter
Sergunb 0:8918a71cdbe9 809 context->retransmitCount++;
Sergunb 0:8918a71cdbe9 810 }
Sergunb 0:8918a71cdbe9 811 }
Sergunb 0:8918a71cdbe9 812 else
Sergunb 0:8918a71cdbe9 813 {
Sergunb 0:8918a71cdbe9 814 //Check retransmission counter
Sergunb 0:8918a71cdbe9 815 if(context->retransmitCount > 0)
Sergunb 0:8918a71cdbe9 816 {
Sergunb 0:8918a71cdbe9 817 //The message exchange fails once MRD seconds have elapsed since
Sergunb 0:8918a71cdbe9 818 //the client first transmitted the message
Sergunb 0:8918a71cdbe9 819 if(timeCompare(time, context->exchangeStartTime + DHCPV6_CLIENT_CNF_MAX_RD) >= 0)
Sergunb 0:8918a71cdbe9 820 {
Sergunb 0:8918a71cdbe9 821 //If the client receives no responses before the message transmission
Sergunb 0:8918a71cdbe9 822 //process terminates, the client should continue to use any IP
Sergunb 0:8918a71cdbe9 823 //addresses using the last known lifetimes for those addresses
Sergunb 0:8918a71cdbe9 824 dhcpv6ClientChangeState(context, DHCPV6_STATE_INIT, 0);
Sergunb 0:8918a71cdbe9 825 }
Sergunb 0:8918a71cdbe9 826 }
Sergunb 0:8918a71cdbe9 827 }
Sergunb 0:8918a71cdbe9 828
Sergunb 0:8918a71cdbe9 829 //Manage DHCPv6 configuration timeout
Sergunb 0:8918a71cdbe9 830 dhcpv6ClientCheckTimeout(context);
Sergunb 0:8918a71cdbe9 831 }
Sergunb 0:8918a71cdbe9 832
Sergunb 0:8918a71cdbe9 833
Sergunb 0:8918a71cdbe9 834 /**
Sergunb 0:8918a71cdbe9 835 * @brief DAD state
Sergunb 0:8918a71cdbe9 836 *
Sergunb 0:8918a71cdbe9 837 * The client perform duplicate address detection on each
Sergunb 0:8918a71cdbe9 838 * of the addresses in any IAs it receives in the Reply message
Sergunb 0:8918a71cdbe9 839 * before using that address for traffic
Sergunb 0:8918a71cdbe9 840 *
Sergunb 0:8918a71cdbe9 841 * @param[in] context Pointer to the DHCPv6 client context
Sergunb 0:8918a71cdbe9 842 **/
Sergunb 0:8918a71cdbe9 843
Sergunb 0:8918a71cdbe9 844 void dhcpv6ClientStateDad(Dhcpv6ClientContext *context)
Sergunb 0:8918a71cdbe9 845 {
Sergunb 0:8918a71cdbe9 846 uint_t i;
Sergunb 0:8918a71cdbe9 847 NetInterface *interface;
Sergunb 0:8918a71cdbe9 848 Ipv6AddrState state;
Sergunb 0:8918a71cdbe9 849 Dhcpv6ClientAddrEntry *entry;
Sergunb 0:8918a71cdbe9 850
Sergunb 0:8918a71cdbe9 851 //Point to the underlying network interface
Sergunb 0:8918a71cdbe9 852 interface = context->settings.interface;
Sergunb 0:8918a71cdbe9 853
Sergunb 0:8918a71cdbe9 854 //Loop through the IPv6 addresses recorded by the DHCPv6 client
Sergunb 0:8918a71cdbe9 855 for(i = 0; i < DHCPV6_CLIENT_ADDR_LIST_SIZE; i++)
Sergunb 0:8918a71cdbe9 856 {
Sergunb 0:8918a71cdbe9 857 //Point to the current entry
Sergunb 0:8918a71cdbe9 858 entry = &context->ia.addrList[i];
Sergunb 0:8918a71cdbe9 859
Sergunb 0:8918a71cdbe9 860 //Check the IPv6 address is a tentative address?
Sergunb 0:8918a71cdbe9 861 if(entry->validLifetime > 0)
Sergunb 0:8918a71cdbe9 862 {
Sergunb 0:8918a71cdbe9 863 //Get the state of the current IPv6 address
Sergunb 0:8918a71cdbe9 864 state = ipv6GetAddrState(interface, &entry->addr);
Sergunb 0:8918a71cdbe9 865
Sergunb 0:8918a71cdbe9 866 //Duplicate Address Detection in progress?
Sergunb 0:8918a71cdbe9 867 if(state == IPV6_ADDR_STATE_TENTATIVE)
Sergunb 0:8918a71cdbe9 868 {
Sergunb 0:8918a71cdbe9 869 //Exit immediately
Sergunb 0:8918a71cdbe9 870 return;
Sergunb 0:8918a71cdbe9 871 }
Sergunb 0:8918a71cdbe9 872 //Duplicate Address Detection failed?
Sergunb 0:8918a71cdbe9 873 else if(state == IPV6_ADDR_STATE_INVALID)
Sergunb 0:8918a71cdbe9 874 {
Sergunb 0:8918a71cdbe9 875 //Switch to the DECLINE state
Sergunb 0:8918a71cdbe9 876 dhcpv6ClientChangeState(context, DHCPV6_STATE_DECLINE, 0);
Sergunb 0:8918a71cdbe9 877 //Exit immediately
Sergunb 0:8918a71cdbe9 878 return;
Sergunb 0:8918a71cdbe9 879 }
Sergunb 0:8918a71cdbe9 880 }
Sergunb 0:8918a71cdbe9 881 }
Sergunb 0:8918a71cdbe9 882
Sergunb 0:8918a71cdbe9 883 //Dump current DHCPv6 configuration for debugging purpose
Sergunb 0:8918a71cdbe9 884 dhcpv6ClientDumpConfig(context);
Sergunb 0:8918a71cdbe9 885 //Switch to the BOUND state
Sergunb 0:8918a71cdbe9 886 dhcpv6ClientChangeState(context, DHCPV6_STATE_BOUND, 0);
Sergunb 0:8918a71cdbe9 887 }
Sergunb 0:8918a71cdbe9 888
Sergunb 0:8918a71cdbe9 889
Sergunb 0:8918a71cdbe9 890 /**
Sergunb 0:8918a71cdbe9 891 * @brief BOUND state
Sergunb 0:8918a71cdbe9 892 *
Sergunb 0:8918a71cdbe9 893 * Client has a valid lease and is in its normal operating state
Sergunb 0:8918a71cdbe9 894 *
Sergunb 0:8918a71cdbe9 895 * @param[in] context Pointer to the DHCPv6 client context
Sergunb 0:8918a71cdbe9 896 **/
Sergunb 0:8918a71cdbe9 897
Sergunb 0:8918a71cdbe9 898 void dhcpv6ClientStateBound(Dhcpv6ClientContext *context)
Sergunb 0:8918a71cdbe9 899 {
Sergunb 0:8918a71cdbe9 900 systime_t t1;
Sergunb 0:8918a71cdbe9 901 systime_t time;
Sergunb 0:8918a71cdbe9 902
Sergunb 0:8918a71cdbe9 903 //Get current time
Sergunb 0:8918a71cdbe9 904 time = osGetSystemTime();
Sergunb 0:8918a71cdbe9 905
Sergunb 0:8918a71cdbe9 906 //A client will never attempt to extend the lifetime of any
Sergunb 0:8918a71cdbe9 907 //address in an IA with T1 set to 0xffffffff
Sergunb 0:8918a71cdbe9 908 if(context->ia.t1 != DHCPV6_INFINITE_TIME)
Sergunb 0:8918a71cdbe9 909 {
Sergunb 0:8918a71cdbe9 910 //Convert T1 to milliseconds
Sergunb 0:8918a71cdbe9 911 if(context->ia.t1 < (MAX_DELAY / 1000))
Sergunb 0:8918a71cdbe9 912 t1 = context->ia.t1 * 1000;
Sergunb 0:8918a71cdbe9 913 else
Sergunb 0:8918a71cdbe9 914 t1 = MAX_DELAY;
Sergunb 0:8918a71cdbe9 915
Sergunb 0:8918a71cdbe9 916 //Check the time elapsed since the lease was obtained
Sergunb 0:8918a71cdbe9 917 if(timeCompare(time, context->leaseStartTime + t1) >= 0)
Sergunb 0:8918a71cdbe9 918 {
Sergunb 0:8918a71cdbe9 919 //Record the time at which the client started the address renewal process
Sergunb 0:8918a71cdbe9 920 context->configStartTime = time;
Sergunb 0:8918a71cdbe9 921
Sergunb 0:8918a71cdbe9 922 //Enter the RENEW state
Sergunb 0:8918a71cdbe9 923 dhcpv6ClientChangeState(context, DHCPV6_STATE_RENEW, 0);
Sergunb 0:8918a71cdbe9 924 }
Sergunb 0:8918a71cdbe9 925 }
Sergunb 0:8918a71cdbe9 926 }
Sergunb 0:8918a71cdbe9 927
Sergunb 0:8918a71cdbe9 928
Sergunb 0:8918a71cdbe9 929 /**
Sergunb 0:8918a71cdbe9 930 * @brief RENEW state
Sergunb 0:8918a71cdbe9 931 *
Sergunb 0:8918a71cdbe9 932 * The client sends a Renew message to the server that originally
Sergunb 0:8918a71cdbe9 933 * provided the client's addresses and configuration parameters to
Sergunb 0:8918a71cdbe9 934 * extend the lifetimes on the addresses assigned to the client
Sergunb 0:8918a71cdbe9 935 * and to update other configuration parameters
Sergunb 0:8918a71cdbe9 936 *
Sergunb 0:8918a71cdbe9 937 * @param[in] context Pointer to the DHCPv6 client context
Sergunb 0:8918a71cdbe9 938 **/
Sergunb 0:8918a71cdbe9 939
Sergunb 0:8918a71cdbe9 940 void dhcpv6ClientStateRenew(Dhcpv6ClientContext *context)
Sergunb 0:8918a71cdbe9 941 {
Sergunb 0:8918a71cdbe9 942 systime_t t2;
Sergunb 0:8918a71cdbe9 943 systime_t time;
Sergunb 0:8918a71cdbe9 944
Sergunb 0:8918a71cdbe9 945 //Get current time
Sergunb 0:8918a71cdbe9 946 time = osGetSystemTime();
Sergunb 0:8918a71cdbe9 947
Sergunb 0:8918a71cdbe9 948 //Check current time
Sergunb 0:8918a71cdbe9 949 if(timeCompare(time, context->timestamp + context->timeout) >= 0)
Sergunb 0:8918a71cdbe9 950 {
Sergunb 0:8918a71cdbe9 951 //Check retransmission counter
Sergunb 0:8918a71cdbe9 952 if(context->retransmitCount == 0)
Sergunb 0:8918a71cdbe9 953 {
Sergunb 0:8918a71cdbe9 954 //Generate a 24-bit transaction ID
Sergunb 0:8918a71cdbe9 955 context->transactionId = netGetRand() & 0x00FFFFFF;
Sergunb 0:8918a71cdbe9 956
Sergunb 0:8918a71cdbe9 957 //Send a Renew message
Sergunb 0:8918a71cdbe9 958 dhcpv6ClientSendMessage(context, DHCPV6_MSG_TYPE_RENEW);
Sergunb 0:8918a71cdbe9 959
Sergunb 0:8918a71cdbe9 960 //Save the time at which the message was sent
Sergunb 0:8918a71cdbe9 961 context->exchangeStartTime = time;
Sergunb 0:8918a71cdbe9 962 context->timestamp = time;
Sergunb 0:8918a71cdbe9 963
Sergunb 0:8918a71cdbe9 964 //Initial retransmission timeout
Sergunb 0:8918a71cdbe9 965 context->timeout = DHCPV6_CLIENT_REN_TIMEOUT +
Sergunb 0:8918a71cdbe9 966 dhcpv6Rand(DHCPV6_CLIENT_REN_TIMEOUT);
Sergunb 0:8918a71cdbe9 967 }
Sergunb 0:8918a71cdbe9 968 else
Sergunb 0:8918a71cdbe9 969 {
Sergunb 0:8918a71cdbe9 970 //Send a Renew message
Sergunb 0:8918a71cdbe9 971 dhcpv6ClientSendMessage(context, DHCPV6_MSG_TYPE_RENEW);
Sergunb 0:8918a71cdbe9 972
Sergunb 0:8918a71cdbe9 973 //Save the time at which the message was sent
Sergunb 0:8918a71cdbe9 974 context->timestamp = time;
Sergunb 0:8918a71cdbe9 975
Sergunb 0:8918a71cdbe9 976 //The RT is doubled for each subsequent retransmission
Sergunb 0:8918a71cdbe9 977 context->timeout = context->timeout * 2 + dhcpv6Rand(context->timeout);
Sergunb 0:8918a71cdbe9 978
Sergunb 0:8918a71cdbe9 979 //MRT specifies an upper bound on the value of RT
Sergunb 0:8918a71cdbe9 980 if(context->timeout > DHCPV6_CLIENT_REN_MAX_RT)
Sergunb 0:8918a71cdbe9 981 {
Sergunb 0:8918a71cdbe9 982 //Compute retransmission timeout
Sergunb 0:8918a71cdbe9 983 context->timeout = DHCPV6_CLIENT_REN_MAX_RT +
Sergunb 0:8918a71cdbe9 984 dhcpv6Rand(DHCPV6_CLIENT_REN_MAX_RT);
Sergunb 0:8918a71cdbe9 985 }
Sergunb 0:8918a71cdbe9 986 }
Sergunb 0:8918a71cdbe9 987
Sergunb 0:8918a71cdbe9 988 //Increment retransmission counter
Sergunb 0:8918a71cdbe9 989 context->retransmitCount++;
Sergunb 0:8918a71cdbe9 990 }
Sergunb 0:8918a71cdbe9 991 else
Sergunb 0:8918a71cdbe9 992 {
Sergunb 0:8918a71cdbe9 993 //A client will never attempt to use a Rebind message to locate a
Sergunb 0:8918a71cdbe9 994 //different server to extend the lifetime of any address in an IA
Sergunb 0:8918a71cdbe9 995 //with T2 set to 0xffffffff
Sergunb 0:8918a71cdbe9 996 if(context->ia.t2 != DHCPV6_INFINITE_TIME)
Sergunb 0:8918a71cdbe9 997 {
Sergunb 0:8918a71cdbe9 998 //Convert T2 to milliseconds
Sergunb 0:8918a71cdbe9 999 if(context->ia.t2 < (MAX_DELAY / 1000))
Sergunb 0:8918a71cdbe9 1000 t2 = context->ia.t2 * 1000;
Sergunb 0:8918a71cdbe9 1001 else
Sergunb 0:8918a71cdbe9 1002 t2 = MAX_DELAY;
Sergunb 0:8918a71cdbe9 1003
Sergunb 0:8918a71cdbe9 1004 //Check whether T2 timer has expired
Sergunb 0:8918a71cdbe9 1005 if(timeCompare(time, context->leaseStartTime + t2) >= 0)
Sergunb 0:8918a71cdbe9 1006 {
Sergunb 0:8918a71cdbe9 1007 //Switch to the REBIND state
Sergunb 0:8918a71cdbe9 1008 dhcpv6ClientChangeState(context, DHCPV6_STATE_REBIND, 0);
Sergunb 0:8918a71cdbe9 1009 }
Sergunb 0:8918a71cdbe9 1010 }
Sergunb 0:8918a71cdbe9 1011 }
Sergunb 0:8918a71cdbe9 1012 }
Sergunb 0:8918a71cdbe9 1013
Sergunb 0:8918a71cdbe9 1014
Sergunb 0:8918a71cdbe9 1015 /**
Sergunb 0:8918a71cdbe9 1016 * @brief REBIND state
Sergunb 0:8918a71cdbe9 1017 *
Sergunb 0:8918a71cdbe9 1018 * The client sends a Rebind message to any available server to extend
Sergunb 0:8918a71cdbe9 1019 * the lifetimes on the addresses assigned to the client and to update
Sergunb 0:8918a71cdbe9 1020 * other configuration parameters. This message is sent after a client
Sergunb 0:8918a71cdbe9 1021 * receives no response to a Renew message
Sergunb 0:8918a71cdbe9 1022 *
Sergunb 0:8918a71cdbe9 1023 * @param[in] context Pointer to the DHCPv6 client context
Sergunb 0:8918a71cdbe9 1024 **/
Sergunb 0:8918a71cdbe9 1025
Sergunb 0:8918a71cdbe9 1026 void dhcpv6ClientStateRebind(Dhcpv6ClientContext *context)
Sergunb 0:8918a71cdbe9 1027 {
Sergunb 0:8918a71cdbe9 1028 uint_t i;
Sergunb 0:8918a71cdbe9 1029 systime_t time;
Sergunb 0:8918a71cdbe9 1030 NetInterface *interface;
Sergunb 0:8918a71cdbe9 1031 Dhcpv6ClientAddrEntry *entry;
Sergunb 0:8918a71cdbe9 1032
Sergunb 0:8918a71cdbe9 1033 //Point to the underlying network interface
Sergunb 0:8918a71cdbe9 1034 interface = context->settings.interface;
Sergunb 0:8918a71cdbe9 1035
Sergunb 0:8918a71cdbe9 1036 //Get current time
Sergunb 0:8918a71cdbe9 1037 time = osGetSystemTime();
Sergunb 0:8918a71cdbe9 1038
Sergunb 0:8918a71cdbe9 1039 //Check current time
Sergunb 0:8918a71cdbe9 1040 if(timeCompare(time, context->timestamp + context->timeout) >= 0)
Sergunb 0:8918a71cdbe9 1041 {
Sergunb 0:8918a71cdbe9 1042 //Check retransmission counter
Sergunb 0:8918a71cdbe9 1043 if(context->retransmitCount == 0)
Sergunb 0:8918a71cdbe9 1044 {
Sergunb 0:8918a71cdbe9 1045 //Generate a 24-bit transaction ID
Sergunb 0:8918a71cdbe9 1046 context->transactionId = netGetRand() & 0x00FFFFFF;
Sergunb 0:8918a71cdbe9 1047
Sergunb 0:8918a71cdbe9 1048 //Send a Rebind message
Sergunb 0:8918a71cdbe9 1049 dhcpv6ClientSendMessage(context, DHCPV6_MSG_TYPE_REBIND);
Sergunb 0:8918a71cdbe9 1050
Sergunb 0:8918a71cdbe9 1051 //Save the time at which the message was sent
Sergunb 0:8918a71cdbe9 1052 context->exchangeStartTime = time;
Sergunb 0:8918a71cdbe9 1053 context->timestamp = time;
Sergunb 0:8918a71cdbe9 1054
Sergunb 0:8918a71cdbe9 1055 //Initial retransmission timeout
Sergunb 0:8918a71cdbe9 1056 context->timeout = DHCPV6_CLIENT_REB_TIMEOUT +
Sergunb 0:8918a71cdbe9 1057 dhcpv6Rand(DHCPV6_CLIENT_REB_TIMEOUT);
Sergunb 0:8918a71cdbe9 1058 }
Sergunb 0:8918a71cdbe9 1059 else
Sergunb 0:8918a71cdbe9 1060 {
Sergunb 0:8918a71cdbe9 1061 //Send a Rebind message
Sergunb 0:8918a71cdbe9 1062 dhcpv6ClientSendMessage(context, DHCPV6_MSG_TYPE_REBIND);
Sergunb 0:8918a71cdbe9 1063
Sergunb 0:8918a71cdbe9 1064 //Save the time at which the message was sent
Sergunb 0:8918a71cdbe9 1065 context->timestamp = time;
Sergunb 0:8918a71cdbe9 1066
Sergunb 0:8918a71cdbe9 1067 //The RT is doubled for each subsequent retransmission
Sergunb 0:8918a71cdbe9 1068 context->timeout = context->timeout * 2 + dhcpv6Rand(context->timeout);
Sergunb 0:8918a71cdbe9 1069
Sergunb 0:8918a71cdbe9 1070 //MRT specifies an upper bound on the value of RT
Sergunb 0:8918a71cdbe9 1071 if(context->timeout > DHCPV6_CLIENT_REB_MAX_RT)
Sergunb 0:8918a71cdbe9 1072 {
Sergunb 0:8918a71cdbe9 1073 //Compute retransmission timeout
Sergunb 0:8918a71cdbe9 1074 context->timeout = DHCPV6_CLIENT_REB_MAX_RT +
Sergunb 0:8918a71cdbe9 1075 dhcpv6Rand(DHCPV6_CLIENT_REB_MAX_RT);
Sergunb 0:8918a71cdbe9 1076 }
Sergunb 0:8918a71cdbe9 1077 }
Sergunb 0:8918a71cdbe9 1078
Sergunb 0:8918a71cdbe9 1079 //Increment retransmission counter
Sergunb 0:8918a71cdbe9 1080 context->retransmitCount++;
Sergunb 0:8918a71cdbe9 1081 }
Sergunb 0:8918a71cdbe9 1082 else
Sergunb 0:8918a71cdbe9 1083 {
Sergunb 0:8918a71cdbe9 1084 //Loop through the IPv6 addresses recorded by the DHCPv6 client
Sergunb 0:8918a71cdbe9 1085 for(i = 0; i < DHCPV6_CLIENT_ADDR_LIST_SIZE; i++)
Sergunb 0:8918a71cdbe9 1086 {
Sergunb 0:8918a71cdbe9 1087 //Point to the current entry
Sergunb 0:8918a71cdbe9 1088 entry = &context->ia.addrList[i];
Sergunb 0:8918a71cdbe9 1089
Sergunb 0:8918a71cdbe9 1090 //Valid IPv6 address?
Sergunb 0:8918a71cdbe9 1091 if(entry->validLifetime > 0)
Sergunb 0:8918a71cdbe9 1092 {
Sergunb 0:8918a71cdbe9 1093 //Check whether the valid lifetime has expired
Sergunb 0:8918a71cdbe9 1094 if(ipv6GetAddrState(interface, &entry->addr) == IPV6_ADDR_STATE_INVALID)
Sergunb 0:8918a71cdbe9 1095 {
Sergunb 0:8918a71cdbe9 1096 //Restart DHCPv6 configuration
Sergunb 0:8918a71cdbe9 1097 dhcpv6ClientChangeState(context, DHCPV6_STATE_INIT, 0);
Sergunb 0:8918a71cdbe9 1098 }
Sergunb 0:8918a71cdbe9 1099 }
Sergunb 0:8918a71cdbe9 1100 }
Sergunb 0:8918a71cdbe9 1101 }
Sergunb 0:8918a71cdbe9 1102 }
Sergunb 0:8918a71cdbe9 1103
Sergunb 0:8918a71cdbe9 1104
Sergunb 0:8918a71cdbe9 1105 /**
Sergunb 0:8918a71cdbe9 1106 * @brief RELEASE state
Sergunb 0:8918a71cdbe9 1107 *
Sergunb 0:8918a71cdbe9 1108 * To release one or more addresses, a client sends a Release message
Sergunb 0:8918a71cdbe9 1109 * to the server
Sergunb 0:8918a71cdbe9 1110 *
Sergunb 0:8918a71cdbe9 1111 * @param[in] context Pointer to the DHCPv6 client context
Sergunb 0:8918a71cdbe9 1112 **/
Sergunb 0:8918a71cdbe9 1113
Sergunb 0:8918a71cdbe9 1114 void dhcpv6ClientStateRelease(Dhcpv6ClientContext *context)
Sergunb 0:8918a71cdbe9 1115 {
Sergunb 0:8918a71cdbe9 1116 systime_t time;
Sergunb 0:8918a71cdbe9 1117
Sergunb 0:8918a71cdbe9 1118 //Get current time
Sergunb 0:8918a71cdbe9 1119 time = osGetSystemTime();
Sergunb 0:8918a71cdbe9 1120
Sergunb 0:8918a71cdbe9 1121 //Check current time
Sergunb 0:8918a71cdbe9 1122 if(timeCompare(time, context->timestamp + context->timeout) >= 0)
Sergunb 0:8918a71cdbe9 1123 {
Sergunb 0:8918a71cdbe9 1124 //Check retransmission counter
Sergunb 0:8918a71cdbe9 1125 if(context->retransmitCount == 0)
Sergunb 0:8918a71cdbe9 1126 {
Sergunb 0:8918a71cdbe9 1127 //Generate a 24-bit transaction ID
Sergunb 0:8918a71cdbe9 1128 context->transactionId = netGetRand() & 0x00FFFFFF;
Sergunb 0:8918a71cdbe9 1129
Sergunb 0:8918a71cdbe9 1130 //Send a Release message
Sergunb 0:8918a71cdbe9 1131 dhcpv6ClientSendMessage(context, DHCPV6_MSG_TYPE_RELEASE);
Sergunb 0:8918a71cdbe9 1132
Sergunb 0:8918a71cdbe9 1133 //Save the time at which the message was sent
Sergunb 0:8918a71cdbe9 1134 context->exchangeStartTime = time;
Sergunb 0:8918a71cdbe9 1135 context->timestamp = time;
Sergunb 0:8918a71cdbe9 1136
Sergunb 0:8918a71cdbe9 1137 //Initial retransmission timeout
Sergunb 0:8918a71cdbe9 1138 context->timeout = DHCPV6_CLIENT_REL_TIMEOUT +
Sergunb 0:8918a71cdbe9 1139 dhcpv6Rand(DHCPV6_CLIENT_REL_TIMEOUT);
Sergunb 0:8918a71cdbe9 1140
Sergunb 0:8918a71cdbe9 1141 //Increment retransmission counter
Sergunb 0:8918a71cdbe9 1142 context->retransmitCount++;
Sergunb 0:8918a71cdbe9 1143 }
Sergunb 0:8918a71cdbe9 1144 else if(context->retransmitCount < DHCPV6_CLIENT_REL_MAX_RC)
Sergunb 0:8918a71cdbe9 1145 {
Sergunb 0:8918a71cdbe9 1146 //Send a Release message
Sergunb 0:8918a71cdbe9 1147 dhcpv6ClientSendMessage(context, DHCPV6_MSG_TYPE_RELEASE);
Sergunb 0:8918a71cdbe9 1148
Sergunb 0:8918a71cdbe9 1149 //Save the time at which the message was sent
Sergunb 0:8918a71cdbe9 1150 context->timestamp = time;
Sergunb 0:8918a71cdbe9 1151
Sergunb 0:8918a71cdbe9 1152 //The RT is doubled for each subsequent retransmission
Sergunb 0:8918a71cdbe9 1153 context->timeout = context->timeout * 2 + dhcpv6Rand(context->timeout);
Sergunb 0:8918a71cdbe9 1154
Sergunb 0:8918a71cdbe9 1155 //Increment retransmission counter
Sergunb 0:8918a71cdbe9 1156 context->retransmitCount++;
Sergunb 0:8918a71cdbe9 1157 }
Sergunb 0:8918a71cdbe9 1158 else
Sergunb 0:8918a71cdbe9 1159 {
Sergunb 0:8918a71cdbe9 1160 //Implementations should retransmit one or more times, but may
Sergunb 0:8918a71cdbe9 1161 //choose to terminate the retransmission procedure early
Sergunb 0:8918a71cdbe9 1162 context->running = FALSE;
Sergunb 0:8918a71cdbe9 1163
Sergunb 0:8918a71cdbe9 1164 //Reinitialize state machine
Sergunb 0:8918a71cdbe9 1165 dhcpv6ClientChangeState(context, DHCPV6_STATE_INIT, 0);
Sergunb 0:8918a71cdbe9 1166 }
Sergunb 0:8918a71cdbe9 1167 }
Sergunb 0:8918a71cdbe9 1168 }
Sergunb 0:8918a71cdbe9 1169
Sergunb 0:8918a71cdbe9 1170
Sergunb 0:8918a71cdbe9 1171 /**
Sergunb 0:8918a71cdbe9 1172 * @brief DECLINE state
Sergunb 0:8918a71cdbe9 1173 *
Sergunb 0:8918a71cdbe9 1174 * If a client detects that one or more addresses assigned to it by a
Sergunb 0:8918a71cdbe9 1175 * server are already in use by another node, the client sends a Decline
Sergunb 0:8918a71cdbe9 1176 * message to the server to inform it that the address is suspect
Sergunb 0:8918a71cdbe9 1177 *
Sergunb 0:8918a71cdbe9 1178 * @param[in] context Pointer to the DHCPv6 client context
Sergunb 0:8918a71cdbe9 1179 **/
Sergunb 0:8918a71cdbe9 1180
Sergunb 0:8918a71cdbe9 1181 void dhcpv6ClientStateDecline(Dhcpv6ClientContext *context)
Sergunb 0:8918a71cdbe9 1182 {
Sergunb 0:8918a71cdbe9 1183 systime_t time;
Sergunb 0:8918a71cdbe9 1184
Sergunb 0:8918a71cdbe9 1185 //Get current time
Sergunb 0:8918a71cdbe9 1186 time = osGetSystemTime();
Sergunb 0:8918a71cdbe9 1187
Sergunb 0:8918a71cdbe9 1188 //Check current time
Sergunb 0:8918a71cdbe9 1189 if(timeCompare(time, context->timestamp + context->timeout) >= 0)
Sergunb 0:8918a71cdbe9 1190 {
Sergunb 0:8918a71cdbe9 1191 //Check retransmission counter
Sergunb 0:8918a71cdbe9 1192 if(context->retransmitCount == 0)
Sergunb 0:8918a71cdbe9 1193 {
Sergunb 0:8918a71cdbe9 1194 //Generate a 24-bit transaction ID
Sergunb 0:8918a71cdbe9 1195 context->transactionId = netGetRand() & 0x00FFFFFF;
Sergunb 0:8918a71cdbe9 1196
Sergunb 0:8918a71cdbe9 1197 //Send a Decline message
Sergunb 0:8918a71cdbe9 1198 dhcpv6ClientSendMessage(context, DHCPV6_MSG_TYPE_DECLINE);
Sergunb 0:8918a71cdbe9 1199
Sergunb 0:8918a71cdbe9 1200 //Save the time at which the message was sent
Sergunb 0:8918a71cdbe9 1201 context->exchangeStartTime = time;
Sergunb 0:8918a71cdbe9 1202 context->timestamp = time;
Sergunb 0:8918a71cdbe9 1203
Sergunb 0:8918a71cdbe9 1204 //Initial retransmission timeout
Sergunb 0:8918a71cdbe9 1205 context->timeout = DHCPV6_CLIENT_DEC_TIMEOUT +
Sergunb 0:8918a71cdbe9 1206 dhcpv6Rand(DHCPV6_CLIENT_DEC_TIMEOUT);
Sergunb 0:8918a71cdbe9 1207
Sergunb 0:8918a71cdbe9 1208 //Increment retransmission counter
Sergunb 0:8918a71cdbe9 1209 context->retransmitCount++;
Sergunb 0:8918a71cdbe9 1210 }
Sergunb 0:8918a71cdbe9 1211 else if(context->retransmitCount < DHCPV6_CLIENT_DEC_MAX_RC)
Sergunb 0:8918a71cdbe9 1212 {
Sergunb 0:8918a71cdbe9 1213 //Send a Decline message
Sergunb 0:8918a71cdbe9 1214 dhcpv6ClientSendMessage(context, DHCPV6_MSG_TYPE_DECLINE);
Sergunb 0:8918a71cdbe9 1215
Sergunb 0:8918a71cdbe9 1216 //Save the time at which the message was sent
Sergunb 0:8918a71cdbe9 1217 context->timestamp = time;
Sergunb 0:8918a71cdbe9 1218
Sergunb 0:8918a71cdbe9 1219 //The RT is doubled for each subsequent retransmission
Sergunb 0:8918a71cdbe9 1220 context->timeout = context->timeout * 2 + dhcpv6Rand(context->timeout);
Sergunb 0:8918a71cdbe9 1221
Sergunb 0:8918a71cdbe9 1222 //Increment retransmission counter
Sergunb 0:8918a71cdbe9 1223 context->retransmitCount++;
Sergunb 0:8918a71cdbe9 1224 }
Sergunb 0:8918a71cdbe9 1225 else
Sergunb 0:8918a71cdbe9 1226 {
Sergunb 0:8918a71cdbe9 1227 //If the client does not receive a response within a reasonable
Sergunb 0:8918a71cdbe9 1228 //period of time, then it restarts the initialization procedure
Sergunb 0:8918a71cdbe9 1229 dhcpv6ClientChangeState(context, DHCPV6_STATE_INIT, 0);
Sergunb 0:8918a71cdbe9 1230 }
Sergunb 0:8918a71cdbe9 1231 }
Sergunb 0:8918a71cdbe9 1232 }
Sergunb 0:8918a71cdbe9 1233
Sergunb 0:8918a71cdbe9 1234
Sergunb 0:8918a71cdbe9 1235 /**
Sergunb 0:8918a71cdbe9 1236 * @brief Send Solicit message
Sergunb 0:8918a71cdbe9 1237 * @param[in] context Pointer to the DHCPv6 client context
Sergunb 0:8918a71cdbe9 1238 * @param[in] type DHCPv6 message type
Sergunb 0:8918a71cdbe9 1239 * @return Error code
Sergunb 0:8918a71cdbe9 1240 **/
Sergunb 0:8918a71cdbe9 1241
Sergunb 0:8918a71cdbe9 1242 error_t dhcpv6ClientSendMessage(Dhcpv6ClientContext *context,
Sergunb 0:8918a71cdbe9 1243 Dhcpv6MessageType type)
Sergunb 0:8918a71cdbe9 1244 {
Sergunb 0:8918a71cdbe9 1245 error_t error;
Sergunb 0:8918a71cdbe9 1246 uint_t i;
Sergunb 0:8918a71cdbe9 1247 size_t length;
Sergunb 0:8918a71cdbe9 1248 size_t offset;
Sergunb 0:8918a71cdbe9 1249 NetBuffer *buffer;
Sergunb 0:8918a71cdbe9 1250 NetInterface *interface;
Sergunb 0:8918a71cdbe9 1251 Dhcpv6Message *message;
Sergunb 0:8918a71cdbe9 1252 Dhcpv6Option *option;
Sergunb 0:8918a71cdbe9 1253 Dhcpv6IaNaOption iaNaOption;
Sergunb 0:8918a71cdbe9 1254 Dhcpv6IaAddrOption iaAddrOption;
Sergunb 0:8918a71cdbe9 1255 Dhcpv6FqdnOption *fqdnOption;
Sergunb 0:8918a71cdbe9 1256 Dhcpv6ElapsedTimeOption elapsedTimeOption;
Sergunb 0:8918a71cdbe9 1257 Dhcpv6ClientAddrEntry *entry;
Sergunb 0:8918a71cdbe9 1258 IpAddr destIpAddr;
Sergunb 0:8918a71cdbe9 1259
Sergunb 0:8918a71cdbe9 1260 //Point to the underlying network interface
Sergunb 0:8918a71cdbe9 1261 interface = context->settings.interface;
Sergunb 0:8918a71cdbe9 1262
Sergunb 0:8918a71cdbe9 1263 //Allocate a memory buffer to hold the DHCPv6 message
Sergunb 0:8918a71cdbe9 1264 buffer = udpAllocBuffer(DHCPV6_MAX_MSG_SIZE, &offset);
Sergunb 0:8918a71cdbe9 1265 //Failed to allocate buffer?
Sergunb 0:8918a71cdbe9 1266 if(buffer == NULL)
Sergunb 0:8918a71cdbe9 1267 return ERROR_OUT_OF_MEMORY;
Sergunb 0:8918a71cdbe9 1268
Sergunb 0:8918a71cdbe9 1269 //Point to the beginning of the DHCPv6 message
Sergunb 0:8918a71cdbe9 1270 message = netBufferAt(buffer, offset);
Sergunb 0:8918a71cdbe9 1271
Sergunb 0:8918a71cdbe9 1272 //Set DHCPv6 message type
Sergunb 0:8918a71cdbe9 1273 message->msgType = type;
Sergunb 0:8918a71cdbe9 1274
Sergunb 0:8918a71cdbe9 1275 //The transaction ID is chosen by the client
Sergunb 0:8918a71cdbe9 1276 STORE24BE(context->transactionId, message->transactionId);
Sergunb 0:8918a71cdbe9 1277
Sergunb 0:8918a71cdbe9 1278 //Size of the DHCPv6 message
Sergunb 0:8918a71cdbe9 1279 length = sizeof(Dhcpv6Message);
Sergunb 0:8918a71cdbe9 1280
Sergunb 0:8918a71cdbe9 1281 //The client must include a Client Identifier option
Sergunb 0:8918a71cdbe9 1282 //to identify itself to the server
Sergunb 0:8918a71cdbe9 1283 dhcpv6AddOption(message, &length, DHCPV6_OPTION_CLIENTID,
Sergunb 0:8918a71cdbe9 1284 context->clientId, context->clientIdLength);
Sergunb 0:8918a71cdbe9 1285
Sergunb 0:8918a71cdbe9 1286 //Request, Renew, Release or Decline message?
Sergunb 0:8918a71cdbe9 1287 if(type == DHCPV6_MSG_TYPE_REQUEST ||
Sergunb 0:8918a71cdbe9 1288 type == DHCPV6_MSG_TYPE_RENEW ||
Sergunb 0:8918a71cdbe9 1289 type == DHCPV6_MSG_TYPE_RELEASE ||
Sergunb 0:8918a71cdbe9 1290 type == DHCPV6_MSG_TYPE_DECLINE)
Sergunb 0:8918a71cdbe9 1291 {
Sergunb 0:8918a71cdbe9 1292 //The client places the identifier of the destination
Sergunb 0:8918a71cdbe9 1293 //server in a Server Identifier option
Sergunb 0:8918a71cdbe9 1294 dhcpv6AddOption(message, &length, DHCPV6_OPTION_SERVERID,
Sergunb 0:8918a71cdbe9 1295 context->serverId, context->serverIdLength);
Sergunb 0:8918a71cdbe9 1296 }
Sergunb 0:8918a71cdbe9 1297
Sergunb 0:8918a71cdbe9 1298 //Solicit message?
Sergunb 0:8918a71cdbe9 1299 if(type == DHCPV6_MSG_TYPE_SOLICIT)
Sergunb 0:8918a71cdbe9 1300 {
Sergunb 0:8918a71cdbe9 1301 //Check whether rapid commit is enabled
Sergunb 0:8918a71cdbe9 1302 if(context->settings.rapidCommit)
Sergunb 0:8918a71cdbe9 1303 {
Sergunb 0:8918a71cdbe9 1304 //Include the Rapid Commit option if the client is prepared
Sergunb 0:8918a71cdbe9 1305 //to perform the Solicit/Reply message exchange
Sergunb 0:8918a71cdbe9 1306 dhcpv6AddOption(message, &length, DHCPV6_OPTION_RAPID_COMMIT, NULL, 0);
Sergunb 0:8918a71cdbe9 1307 }
Sergunb 0:8918a71cdbe9 1308 }
Sergunb 0:8918a71cdbe9 1309
Sergunb 0:8918a71cdbe9 1310 //Solicit, Request, Confirm, Renew or Rebind message?
Sergunb 0:8918a71cdbe9 1311 if(type == DHCPV6_MSG_TYPE_SOLICIT ||
Sergunb 0:8918a71cdbe9 1312 type == DHCPV6_MSG_TYPE_REQUEST ||
Sergunb 0:8918a71cdbe9 1313 type == DHCPV6_MSG_TYPE_CONFIRM ||
Sergunb 0:8918a71cdbe9 1314 type == DHCPV6_MSG_TYPE_RENEW ||
Sergunb 0:8918a71cdbe9 1315 type == DHCPV6_MSG_TYPE_REBIND)
Sergunb 0:8918a71cdbe9 1316 {
Sergunb 0:8918a71cdbe9 1317 //Point to the client's fully qualified domain name
Sergunb 0:8918a71cdbe9 1318 fqdnOption = (Dhcpv6FqdnOption *) context->clientFqdn;
Sergunb 0:8918a71cdbe9 1319
Sergunb 0:8918a71cdbe9 1320 //The FQDN option can be used by the client to convey its
Sergunb 0:8918a71cdbe9 1321 //fully qualified domain name to the server
Sergunb 0:8918a71cdbe9 1322 dhcpv6AddOption(message, &length, DHCPV6_OPTION_FQDN,
Sergunb 0:8918a71cdbe9 1323 fqdnOption, sizeof(Dhcpv6FqdnOption) + context->clientFqdnLength);
Sergunb 0:8918a71cdbe9 1324
Sergunb 0:8918a71cdbe9 1325 //The client should include an Option Request option to indicate
Sergunb 0:8918a71cdbe9 1326 //the options the client is interested in receiving
Sergunb 0:8918a71cdbe9 1327 dhcpv6AddOption(message, &length, DHCPV6_OPTION_ORO,
Sergunb 0:8918a71cdbe9 1328 &dhcpv6OptionList, sizeof(dhcpv6OptionList));
Sergunb 0:8918a71cdbe9 1329 }
Sergunb 0:8918a71cdbe9 1330
Sergunb 0:8918a71cdbe9 1331 //Prepare an IA_NA option for a the current interface
Sergunb 0:8918a71cdbe9 1332 iaNaOption.iaId = htonl(interface->id);
Sergunb 0:8918a71cdbe9 1333
Sergunb 0:8918a71cdbe9 1334 //Solicit, Request or Confirm message?
Sergunb 0:8918a71cdbe9 1335 if(type == DHCPV6_MSG_TYPE_SOLICIT ||
Sergunb 0:8918a71cdbe9 1336 type == DHCPV6_MSG_TYPE_REQUEST ||
Sergunb 0:8918a71cdbe9 1337 type == DHCPV6_MSG_TYPE_CONFIRM)
Sergunb 0:8918a71cdbe9 1338 {
Sergunb 0:8918a71cdbe9 1339 //The client should set the T1 and T2 fields in any IA_NA options to 0
Sergunb 0:8918a71cdbe9 1340 iaNaOption.t1 = 0;
Sergunb 0:8918a71cdbe9 1341 iaNaOption.t2 = 0;
Sergunb 0:8918a71cdbe9 1342 }
Sergunb 0:8918a71cdbe9 1343 else
Sergunb 0:8918a71cdbe9 1344 {
Sergunb 0:8918a71cdbe9 1345 //T1 and T2 are provided as a hint
Sergunb 0:8918a71cdbe9 1346 iaNaOption.t1 = htonl(context->ia.t1);
Sergunb 0:8918a71cdbe9 1347 iaNaOption.t2 = htonl(context->ia.t2);
Sergunb 0:8918a71cdbe9 1348 }
Sergunb 0:8918a71cdbe9 1349
Sergunb 0:8918a71cdbe9 1350 //The client includes IA options for any IAs to which
Sergunb 0:8918a71cdbe9 1351 //it wants the server to assign addresses
Sergunb 0:8918a71cdbe9 1352 option = dhcpv6AddOption(message, &length, DHCPV6_OPTION_IA_NA,
Sergunb 0:8918a71cdbe9 1353 &iaNaOption, sizeof(Dhcpv6IaNaOption));
Sergunb 0:8918a71cdbe9 1354
Sergunb 0:8918a71cdbe9 1355 //Request, Confirm, Renew, Rebind, Release or Decline message?
Sergunb 0:8918a71cdbe9 1356 if(type == DHCPV6_MSG_TYPE_REQUEST ||
Sergunb 0:8918a71cdbe9 1357 type == DHCPV6_MSG_TYPE_CONFIRM ||
Sergunb 0:8918a71cdbe9 1358 type == DHCPV6_MSG_TYPE_RENEW ||
Sergunb 0:8918a71cdbe9 1359 type == DHCPV6_MSG_TYPE_REBIND ||
Sergunb 0:8918a71cdbe9 1360 type == DHCPV6_MSG_TYPE_RELEASE ||
Sergunb 0:8918a71cdbe9 1361 type == DHCPV6_MSG_TYPE_DECLINE)
Sergunb 0:8918a71cdbe9 1362 {
Sergunb 0:8918a71cdbe9 1363 //Loop through the IPv6 addresses recorded by the client
Sergunb 0:8918a71cdbe9 1364 for(i = 0; i < DHCPV6_CLIENT_ADDR_LIST_SIZE; i++)
Sergunb 0:8918a71cdbe9 1365 {
Sergunb 0:8918a71cdbe9 1366 //Point to the current entry
Sergunb 0:8918a71cdbe9 1367 entry = &context->ia.addrList[i];
Sergunb 0:8918a71cdbe9 1368
Sergunb 0:8918a71cdbe9 1369 //Valid IPv6 address?
Sergunb 0:8918a71cdbe9 1370 if(entry->validLifetime > 0)
Sergunb 0:8918a71cdbe9 1371 {
Sergunb 0:8918a71cdbe9 1372 //Prepare an IA Address option
Sergunb 0:8918a71cdbe9 1373 iaAddrOption.address = entry->addr;
Sergunb 0:8918a71cdbe9 1374
Sergunb 0:8918a71cdbe9 1375 //Confirm message?
Sergunb 0:8918a71cdbe9 1376 if(type == DHCPV6_MSG_TYPE_CONFIRM)
Sergunb 0:8918a71cdbe9 1377 {
Sergunb 0:8918a71cdbe9 1378 //The client should set the preferred and valid lifetimes to 0
Sergunb 0:8918a71cdbe9 1379 iaAddrOption.preferredLifetime = 0;
Sergunb 0:8918a71cdbe9 1380 iaAddrOption.validLifetime = 0;
Sergunb 0:8918a71cdbe9 1381 }
Sergunb 0:8918a71cdbe9 1382 else
Sergunb 0:8918a71cdbe9 1383 {
Sergunb 0:8918a71cdbe9 1384 //Preferred and valid lifetimes are provided as a hint
Sergunb 0:8918a71cdbe9 1385 iaAddrOption.preferredLifetime = htonl(entry->preferredLifetime);
Sergunb 0:8918a71cdbe9 1386 iaAddrOption.validLifetime = htonl(entry->validLifetime);
Sergunb 0:8918a71cdbe9 1387 }
Sergunb 0:8918a71cdbe9 1388
Sergunb 0:8918a71cdbe9 1389 //Add the IA Address option
Sergunb 0:8918a71cdbe9 1390 dhcpv6AddSubOption(option, &length, DHCPV6_OPTION_IAADDR,
Sergunb 0:8918a71cdbe9 1391 &iaAddrOption, sizeof(iaAddrOption));
Sergunb 0:8918a71cdbe9 1392 }
Sergunb 0:8918a71cdbe9 1393 }
Sergunb 0:8918a71cdbe9 1394 }
Sergunb 0:8918a71cdbe9 1395
Sergunb 0:8918a71cdbe9 1396 //Compute the time elapsed since the client sent the first message
Sergunb 0:8918a71cdbe9 1397 elapsedTimeOption.value = dhcpv6ClientComputeElapsedTime(context);
Sergunb 0:8918a71cdbe9 1398
Sergunb 0:8918a71cdbe9 1399 //The client must include an Elapsed Time option in messages to indicate
Sergunb 0:8918a71cdbe9 1400 //how long the client has been trying to complete a DHCP message exchange
Sergunb 0:8918a71cdbe9 1401 dhcpv6AddOption(message, &length, DHCPV6_OPTION_ELAPSED_TIME,
Sergunb 0:8918a71cdbe9 1402 &elapsedTimeOption, sizeof(Dhcpv6ElapsedTimeOption));
Sergunb 0:8918a71cdbe9 1403
Sergunb 0:8918a71cdbe9 1404 //Adjust the length of the multi-part buffer
Sergunb 0:8918a71cdbe9 1405 netBufferSetLength(buffer, offset + length);
Sergunb 0:8918a71cdbe9 1406
Sergunb 0:8918a71cdbe9 1407 //Destination address
Sergunb 0:8918a71cdbe9 1408 destIpAddr.length = sizeof(Ipv6Addr);
Sergunb 0:8918a71cdbe9 1409 destIpAddr.ipv6Addr = DHCPV6_ALL_RELAY_AGENTS_AND_SERVERS_ADDR;
Sergunb 0:8918a71cdbe9 1410
Sergunb 0:8918a71cdbe9 1411 //Debug message
Sergunb 0:8918a71cdbe9 1412 TRACE_DEBUG("\r\n%s: Sending DHCPv6 message (%" PRIuSIZE " bytes)...\r\n",
Sergunb 0:8918a71cdbe9 1413 formatSystemTime(osGetSystemTime(), NULL), length);
Sergunb 0:8918a71cdbe9 1414
Sergunb 0:8918a71cdbe9 1415 //Dump the contents of the message for debugging purpose
Sergunb 0:8918a71cdbe9 1416 dhcpv6DumpMessage(message, length);
Sergunb 0:8918a71cdbe9 1417
Sergunb 0:8918a71cdbe9 1418 //Send DHCPv6 message
Sergunb 0:8918a71cdbe9 1419 error = udpSendDatagramEx(interface, DHCPV6_CLIENT_PORT,
Sergunb 0:8918a71cdbe9 1420 &destIpAddr, DHCPV6_SERVER_PORT, buffer, offset, 0);
Sergunb 0:8918a71cdbe9 1421
Sergunb 0:8918a71cdbe9 1422 //Free previously allocated memory
Sergunb 0:8918a71cdbe9 1423 netBufferFree(buffer);
Sergunb 0:8918a71cdbe9 1424 //Return status code
Sergunb 0:8918a71cdbe9 1425 return error;
Sergunb 0:8918a71cdbe9 1426 }
Sergunb 0:8918a71cdbe9 1427
Sergunb 0:8918a71cdbe9 1428
Sergunb 0:8918a71cdbe9 1429 /**
Sergunb 0:8918a71cdbe9 1430 * @brief Process incoming DHCPv6 message
Sergunb 0:8918a71cdbe9 1431 * @param[in] interface Underlying network interface
Sergunb 0:8918a71cdbe9 1432 * @param[in] pseudoHeader UDP pseudo header
Sergunb 0:8918a71cdbe9 1433 * @param[in] udpHeader UDP header
Sergunb 0:8918a71cdbe9 1434 * @param[in] buffer Multi-part buffer containing the incoming DHCPv6 message
Sergunb 0:8918a71cdbe9 1435 * @param[in] offset Offset to the first byte of the DHCPv6 message
Sergunb 0:8918a71cdbe9 1436 * @param[in] params Pointer to the DHCPv6 client context
Sergunb 0:8918a71cdbe9 1437 **/
Sergunb 0:8918a71cdbe9 1438
Sergunb 0:8918a71cdbe9 1439 void dhcpv6ClientProcessMessage(NetInterface *interface,
Sergunb 0:8918a71cdbe9 1440 const IpPseudoHeader *pseudoHeader, const UdpHeader *udpHeader,
Sergunb 0:8918a71cdbe9 1441 const NetBuffer *buffer, size_t offset, void *params)
Sergunb 0:8918a71cdbe9 1442 {
Sergunb 0:8918a71cdbe9 1443 size_t length;
Sergunb 0:8918a71cdbe9 1444 Dhcpv6ClientContext *context;
Sergunb 0:8918a71cdbe9 1445 Dhcpv6Message *message;
Sergunb 0:8918a71cdbe9 1446
Sergunb 0:8918a71cdbe9 1447 //Point to the DHCPv6 client context
Sergunb 0:8918a71cdbe9 1448 context = (Dhcpv6ClientContext *) params;
Sergunb 0:8918a71cdbe9 1449
Sergunb 0:8918a71cdbe9 1450 //Retrieve the length of the DHCPv6 message
Sergunb 0:8918a71cdbe9 1451 length = netBufferGetLength(buffer) - offset;
Sergunb 0:8918a71cdbe9 1452
Sergunb 0:8918a71cdbe9 1453 //Make sure the DHCPv6 message is valid
Sergunb 0:8918a71cdbe9 1454 if(length < sizeof(Dhcpv6Message))
Sergunb 0:8918a71cdbe9 1455 return;
Sergunb 0:8918a71cdbe9 1456
Sergunb 0:8918a71cdbe9 1457 //Point to the beginning of the DHCPv6 message
Sergunb 0:8918a71cdbe9 1458 message = netBufferAt(buffer, offset);
Sergunb 0:8918a71cdbe9 1459 //Sanity check
Sergunb 0:8918a71cdbe9 1460 if(message == NULL)
Sergunb 0:8918a71cdbe9 1461 return;
Sergunb 0:8918a71cdbe9 1462
Sergunb 0:8918a71cdbe9 1463 //Debug message
Sergunb 0:8918a71cdbe9 1464 TRACE_DEBUG("\r\n%s: DHCPv6 message received (%" PRIuSIZE " bytes)...\r\n",
Sergunb 0:8918a71cdbe9 1465 formatSystemTime(osGetSystemTime(), NULL), length);
Sergunb 0:8918a71cdbe9 1466
Sergunb 0:8918a71cdbe9 1467 //Dump the contents of the message for debugging purpose
Sergunb 0:8918a71cdbe9 1468 dhcpv6DumpMessage(message, length);
Sergunb 0:8918a71cdbe9 1469
Sergunb 0:8918a71cdbe9 1470 //Check message type
Sergunb 0:8918a71cdbe9 1471 switch(message->msgType)
Sergunb 0:8918a71cdbe9 1472 {
Sergunb 0:8918a71cdbe9 1473 case DHCPV6_MSG_TYPE_ADVERTISE:
Sergunb 0:8918a71cdbe9 1474 //Parse Advertise message
Sergunb 0:8918a71cdbe9 1475 dhcpv6ClientParseAdvertise(context, message, length);
Sergunb 0:8918a71cdbe9 1476 break;
Sergunb 0:8918a71cdbe9 1477 case DHCPV6_MSG_TYPE_REPLY:
Sergunb 0:8918a71cdbe9 1478 //Parse Reply message
Sergunb 0:8918a71cdbe9 1479 dhcpv6ClientParseReply(context, message, length);
Sergunb 0:8918a71cdbe9 1480 break;
Sergunb 0:8918a71cdbe9 1481 default:
Sergunb 0:8918a71cdbe9 1482 //Silently drop incoming message
Sergunb 0:8918a71cdbe9 1483 break;
Sergunb 0:8918a71cdbe9 1484 }
Sergunb 0:8918a71cdbe9 1485 }
Sergunb 0:8918a71cdbe9 1486
Sergunb 0:8918a71cdbe9 1487
Sergunb 0:8918a71cdbe9 1488 /**
Sergunb 0:8918a71cdbe9 1489 * @brief Parse Advertise message
Sergunb 0:8918a71cdbe9 1490 * @param[in] context Pointer to the DHCPv6 client context
Sergunb 0:8918a71cdbe9 1491 * @param[in] message Pointer to the incoming message to parse
Sergunb 0:8918a71cdbe9 1492 * @param[in] length Length of the incoming message
Sergunb 0:8918a71cdbe9 1493 **/
Sergunb 0:8918a71cdbe9 1494
Sergunb 0:8918a71cdbe9 1495 void dhcpv6ClientParseAdvertise(Dhcpv6ClientContext *context,
Sergunb 0:8918a71cdbe9 1496 const Dhcpv6Message *message, size_t length)
Sergunb 0:8918a71cdbe9 1497 {
Sergunb 0:8918a71cdbe9 1498 uint_t i;
Sergunb 0:8918a71cdbe9 1499 int_t serverPreference;
Sergunb 0:8918a71cdbe9 1500 NetInterface *interface;
Sergunb 0:8918a71cdbe9 1501 Dhcpv6StatusCode status;
Sergunb 0:8918a71cdbe9 1502 Dhcpv6Option *option;
Sergunb 0:8918a71cdbe9 1503 Dhcpv6Option *serverIdOption;
Sergunb 0:8918a71cdbe9 1504 Dhcpv6IaNaOption *iaNaOption;
Sergunb 0:8918a71cdbe9 1505
Sergunb 0:8918a71cdbe9 1506 //Point to the underlying network interface
Sergunb 0:8918a71cdbe9 1507 interface = context->settings.interface;
Sergunb 0:8918a71cdbe9 1508
Sergunb 0:8918a71cdbe9 1509 //Make sure that the Advertise message is received in response to
Sergunb 0:8918a71cdbe9 1510 //a Solicit message
Sergunb 0:8918a71cdbe9 1511 if(context->state != DHCPV6_STATE_SOLICIT)
Sergunb 0:8918a71cdbe9 1512 return;
Sergunb 0:8918a71cdbe9 1513
Sergunb 0:8918a71cdbe9 1514 //Discard any received packet that does not match the transaction ID
Sergunb 0:8918a71cdbe9 1515 if(LOAD24BE(message->transactionId) != context->transactionId)
Sergunb 0:8918a71cdbe9 1516 return;
Sergunb 0:8918a71cdbe9 1517
Sergunb 0:8918a71cdbe9 1518 //Get the length of the Options field
Sergunb 0:8918a71cdbe9 1519 length -= sizeof(Dhcpv6Message);
Sergunb 0:8918a71cdbe9 1520
Sergunb 0:8918a71cdbe9 1521 //Search for the Client Identifier option
Sergunb 0:8918a71cdbe9 1522 option = dhcpv6GetOption(message->options, length, DHCPV6_OPTION_CLIENTID);
Sergunb 0:8918a71cdbe9 1523
Sergunb 0:8918a71cdbe9 1524 //Discard any received packet that does not include a Client Identifier option
Sergunb 0:8918a71cdbe9 1525 if(option == NULL)
Sergunb 0:8918a71cdbe9 1526 return;
Sergunb 0:8918a71cdbe9 1527 //Check the length of the option
Sergunb 0:8918a71cdbe9 1528 if(ntohs(option->length) != context->clientIdLength)
Sergunb 0:8918a71cdbe9 1529 return;
Sergunb 0:8918a71cdbe9 1530 //Check whether the Client Identifier matches our identifier
Sergunb 0:8918a71cdbe9 1531 if(memcmp(option->value, context->clientId, context->clientIdLength))
Sergunb 0:8918a71cdbe9 1532 return;
Sergunb 0:8918a71cdbe9 1533
Sergunb 0:8918a71cdbe9 1534 //Search for the Server Identifier option
Sergunb 0:8918a71cdbe9 1535 serverIdOption = dhcpv6GetOption(message->options, length, DHCPV6_OPTION_SERVERID);
Sergunb 0:8918a71cdbe9 1536
Sergunb 0:8918a71cdbe9 1537 //Discard any received packet that does not include a Server Identifier option
Sergunb 0:8918a71cdbe9 1538 if(serverIdOption == NULL)
Sergunb 0:8918a71cdbe9 1539 return;
Sergunb 0:8918a71cdbe9 1540 //Check the length of the server DUID
Sergunb 0:8918a71cdbe9 1541 if(ntohs(serverIdOption->length) == 0)
Sergunb 0:8918a71cdbe9 1542 return;
Sergunb 0:8918a71cdbe9 1543 if(ntohs(serverIdOption->length) > DHCPV6_MAX_DUID_SIZE)
Sergunb 0:8918a71cdbe9 1544 return;
Sergunb 0:8918a71cdbe9 1545
Sergunb 0:8918a71cdbe9 1546 //Get the status code returned by the server
Sergunb 0:8918a71cdbe9 1547 status = dhcpv6GetStatusCode(message->options, length);
Sergunb 0:8918a71cdbe9 1548
Sergunb 0:8918a71cdbe9 1549 //If the message contains a Status Code option indicating a failure,
Sergunb 0:8918a71cdbe9 1550 //then the Advertise message is discarded by the client
Sergunb 0:8918a71cdbe9 1551 if(status != DHCPV6_STATUS_SUCCESS)
Sergunb 0:8918a71cdbe9 1552 return;
Sergunb 0:8918a71cdbe9 1553
Sergunb 0:8918a71cdbe9 1554 //Search for the Preference option
Sergunb 0:8918a71cdbe9 1555 option = dhcpv6GetOption(message->options, length, DHCPV6_OPTION_PREFERENCE);
Sergunb 0:8918a71cdbe9 1556
Sergunb 0:8918a71cdbe9 1557 //Check whether the option has been found
Sergunb 0:8918a71cdbe9 1558 if(option != NULL && ntohs(option->length) == sizeof(Dhcpv6PreferenceOption))
Sergunb 0:8918a71cdbe9 1559 {
Sergunb 0:8918a71cdbe9 1560 //Server server preference value
Sergunb 0:8918a71cdbe9 1561 serverPreference = option->value[0];
Sergunb 0:8918a71cdbe9 1562 }
Sergunb 0:8918a71cdbe9 1563 else
Sergunb 0:8918a71cdbe9 1564 {
Sergunb 0:8918a71cdbe9 1565 //Any Advertise that does not include a Preference option
Sergunb 0:8918a71cdbe9 1566 //is considered to have a preference value of 0
Sergunb 0:8918a71cdbe9 1567 serverPreference = 0;
Sergunb 0:8918a71cdbe9 1568 }
Sergunb 0:8918a71cdbe9 1569
Sergunb 0:8918a71cdbe9 1570 //Select the Advertise message that offers the highest server preference value
Sergunb 0:8918a71cdbe9 1571 if(serverPreference > context->serverPreference)
Sergunb 0:8918a71cdbe9 1572 {
Sergunb 0:8918a71cdbe9 1573 //Save the length of the DUID
Sergunb 0:8918a71cdbe9 1574 context->serverIdLength = ntohs(serverIdOption->length);
Sergunb 0:8918a71cdbe9 1575 //Record the server DUID
Sergunb 0:8918a71cdbe9 1576 memcpy(context->serverId, serverIdOption->value, context->serverIdLength);
Sergunb 0:8918a71cdbe9 1577
Sergunb 0:8918a71cdbe9 1578 //Flush the list of IPv6 addresses from the client's IA
Sergunb 0:8918a71cdbe9 1579 dhcpv6ClientFlushAddrList(context);
Sergunb 0:8918a71cdbe9 1580 }
Sergunb 0:8918a71cdbe9 1581
Sergunb 0:8918a71cdbe9 1582 //Point to the first option
Sergunb 0:8918a71cdbe9 1583 i = 0;
Sergunb 0:8918a71cdbe9 1584
Sergunb 0:8918a71cdbe9 1585 //Loop through DHCPv6 options
Sergunb 0:8918a71cdbe9 1586 while(i < length)
Sergunb 0:8918a71cdbe9 1587 {
Sergunb 0:8918a71cdbe9 1588 //Search for an IA_NA option
Sergunb 0:8918a71cdbe9 1589 option = dhcpv6GetOption(message->options + i, length - i, DHCPV6_OPTION_IA_NA);
Sergunb 0:8918a71cdbe9 1590
Sergunb 0:8918a71cdbe9 1591 //Unable to find the specified option?
Sergunb 0:8918a71cdbe9 1592 if(option == NULL)
Sergunb 0:8918a71cdbe9 1593 break;
Sergunb 0:8918a71cdbe9 1594
Sergunb 0:8918a71cdbe9 1595 //Make sure the IA_NA option is valid
Sergunb 0:8918a71cdbe9 1596 if(ntohs(option->length) >= sizeof(Dhcpv6IaNaOption))
Sergunb 0:8918a71cdbe9 1597 {
Sergunb 0:8918a71cdbe9 1598 //Get the parameters associated with the IA_NA
Sergunb 0:8918a71cdbe9 1599 iaNaOption = (Dhcpv6IaNaOption *) option->value;
Sergunb 0:8918a71cdbe9 1600
Sergunb 0:8918a71cdbe9 1601 //Check the IA identifier
Sergunb 0:8918a71cdbe9 1602 if(ntohl(iaNaOption->iaId) == interface->id)
Sergunb 0:8918a71cdbe9 1603 {
Sergunb 0:8918a71cdbe9 1604 //The client examines the status code in each IA individually
Sergunb 0:8918a71cdbe9 1605 status = dhcpv6GetStatusCode(iaNaOption->options,
Sergunb 0:8918a71cdbe9 1606 ntohs(option->length) - sizeof(Dhcpv6IaNaOption));
Sergunb 0:8918a71cdbe9 1607
Sergunb 0:8918a71cdbe9 1608 //The client must ignore any Advertise message that includes a Status
Sergunb 0:8918a71cdbe9 1609 //Code option containing the value NoAddrsAvail
Sergunb 0:8918a71cdbe9 1610 if(status == DHCPV6_STATUS_NO_ADDRS_AVAILABLE)
Sergunb 0:8918a71cdbe9 1611 return;
Sergunb 0:8918a71cdbe9 1612 }
Sergunb 0:8918a71cdbe9 1613
Sergunb 0:8918a71cdbe9 1614 //Check the server preference value
Sergunb 0:8918a71cdbe9 1615 if(serverPreference > context->serverPreference)
Sergunb 0:8918a71cdbe9 1616 {
Sergunb 0:8918a71cdbe9 1617 //Parse the contents of the IA_NA option
Sergunb 0:8918a71cdbe9 1618 dhcpv6ClientParseIaNaOption(context, option);
Sergunb 0:8918a71cdbe9 1619 }
Sergunb 0:8918a71cdbe9 1620 }
Sergunb 0:8918a71cdbe9 1621
Sergunb 0:8918a71cdbe9 1622 //Jump to the next option
Sergunb 0:8918a71cdbe9 1623 i += sizeof(Dhcpv6Option) + ntohs(option->length);
Sergunb 0:8918a71cdbe9 1624 }
Sergunb 0:8918a71cdbe9 1625
Sergunb 0:8918a71cdbe9 1626 //Record the highest server preference value
Sergunb 0:8918a71cdbe9 1627 if(serverPreference > context->serverPreference)
Sergunb 0:8918a71cdbe9 1628 context->serverPreference = serverPreference;
Sergunb 0:8918a71cdbe9 1629
Sergunb 0:8918a71cdbe9 1630 //If the client receives an Advertise message that includes a
Sergunb 0:8918a71cdbe9 1631 //Preference option with a preference value of 255, the client
Sergunb 0:8918a71cdbe9 1632 //immediately completes the message exchange
Sergunb 0:8918a71cdbe9 1633 if(serverPreference == DHCPV6_MAX_SERVER_PREFERENCE)
Sergunb 0:8918a71cdbe9 1634 {
Sergunb 0:8918a71cdbe9 1635 //Continue configuration procedure
Sergunb 0:8918a71cdbe9 1636 dhcpv6ClientChangeState(context, DHCPV6_STATE_REQUEST, 0);
Sergunb 0:8918a71cdbe9 1637 }
Sergunb 0:8918a71cdbe9 1638 //The message exchange is not terminated before the first RT has elapsed
Sergunb 0:8918a71cdbe9 1639 else if(context->retransmitCount > 1)
Sergunb 0:8918a71cdbe9 1640 {
Sergunb 0:8918a71cdbe9 1641 //Continue configuration procedure
Sergunb 0:8918a71cdbe9 1642 dhcpv6ClientChangeState(context, DHCPV6_STATE_REQUEST, 0);
Sergunb 0:8918a71cdbe9 1643 }
Sergunb 0:8918a71cdbe9 1644 }
Sergunb 0:8918a71cdbe9 1645
Sergunb 0:8918a71cdbe9 1646
Sergunb 0:8918a71cdbe9 1647 /**
Sergunb 0:8918a71cdbe9 1648 * @brief Parse Reply message
Sergunb 0:8918a71cdbe9 1649 * @param[in] context Pointer to the DHCPv6 client context
Sergunb 0:8918a71cdbe9 1650 * @param[in] message Pointer to the incoming message to parse
Sergunb 0:8918a71cdbe9 1651 * @param[in] length Length of the incoming message
Sergunb 0:8918a71cdbe9 1652 **/
Sergunb 0:8918a71cdbe9 1653
Sergunb 0:8918a71cdbe9 1654 void dhcpv6ClientParseReply(Dhcpv6ClientContext *context,
Sergunb 0:8918a71cdbe9 1655 const Dhcpv6Message *message, size_t length)
Sergunb 0:8918a71cdbe9 1656 {
Sergunb 0:8918a71cdbe9 1657 error_t error;
Sergunb 0:8918a71cdbe9 1658 uint_t i;
Sergunb 0:8918a71cdbe9 1659 uint_t k;
Sergunb 0:8918a71cdbe9 1660 uint_t n;
Sergunb 0:8918a71cdbe9 1661 bool_t iaNaOptionFound;
Sergunb 0:8918a71cdbe9 1662 systime_t minPreferredLifetime;
Sergunb 0:8918a71cdbe9 1663 NetInterface *interface;
Sergunb 0:8918a71cdbe9 1664 Dhcpv6StatusCode status;
Sergunb 0:8918a71cdbe9 1665 Dhcpv6Option *option;
Sergunb 0:8918a71cdbe9 1666 Dhcpv6Option *serverIdOption;
Sergunb 0:8918a71cdbe9 1667 Dhcpv6ClientAddrEntry *entry;
Sergunb 0:8918a71cdbe9 1668
Sergunb 0:8918a71cdbe9 1669 //Point to the underlying network interface
Sergunb 0:8918a71cdbe9 1670 interface = context->settings.interface;
Sergunb 0:8918a71cdbe9 1671
Sergunb 0:8918a71cdbe9 1672 //Discard any received packet that does not match the transaction ID
Sergunb 0:8918a71cdbe9 1673 if(LOAD24BE(message->transactionId) != context->transactionId)
Sergunb 0:8918a71cdbe9 1674 return;
Sergunb 0:8918a71cdbe9 1675
Sergunb 0:8918a71cdbe9 1676 //Get the length of the Options field
Sergunb 0:8918a71cdbe9 1677 length -= sizeof(Dhcpv6Message);
Sergunb 0:8918a71cdbe9 1678
Sergunb 0:8918a71cdbe9 1679 //Search for the Client Identifier option
Sergunb 0:8918a71cdbe9 1680 option = dhcpv6GetOption(message->options, length, DHCPV6_OPTION_CLIENTID);
Sergunb 0:8918a71cdbe9 1681
Sergunb 0:8918a71cdbe9 1682 //Discard any received packet that does not include a Client Identifier option
Sergunb 0:8918a71cdbe9 1683 if(option == NULL)
Sergunb 0:8918a71cdbe9 1684 return;
Sergunb 0:8918a71cdbe9 1685 //Check the length of the option
Sergunb 0:8918a71cdbe9 1686 if(ntohs(option->length) != context->clientIdLength)
Sergunb 0:8918a71cdbe9 1687 return;
Sergunb 0:8918a71cdbe9 1688 //Check whether the Client Identifier matches our identifier
Sergunb 0:8918a71cdbe9 1689 if(memcmp(option->value, context->clientId, context->clientIdLength))
Sergunb 0:8918a71cdbe9 1690 return;
Sergunb 0:8918a71cdbe9 1691
Sergunb 0:8918a71cdbe9 1692 //Search for the Server Identifier option
Sergunb 0:8918a71cdbe9 1693 serverIdOption = dhcpv6GetOption(message->options, length, DHCPV6_OPTION_SERVERID);
Sergunb 0:8918a71cdbe9 1694
Sergunb 0:8918a71cdbe9 1695 //Discard any received packet that does not include a Server Identifier option
Sergunb 0:8918a71cdbe9 1696 if(serverIdOption == NULL)
Sergunb 0:8918a71cdbe9 1697 return;
Sergunb 0:8918a71cdbe9 1698 //Check the length of the server DUID
Sergunb 0:8918a71cdbe9 1699 if(ntohs(serverIdOption->length) == 0)
Sergunb 0:8918a71cdbe9 1700 return;
Sergunb 0:8918a71cdbe9 1701 if(ntohs(serverIdOption->length) > DHCPV6_MAX_DUID_SIZE)
Sergunb 0:8918a71cdbe9 1702 return;
Sergunb 0:8918a71cdbe9 1703
Sergunb 0:8918a71cdbe9 1704 //Get the status code returned by the server
Sergunb 0:8918a71cdbe9 1705 status = dhcpv6GetStatusCode(message->options, length);
Sergunb 0:8918a71cdbe9 1706
Sergunb 0:8918a71cdbe9 1707 //Check current state
Sergunb 0:8918a71cdbe9 1708 if(context->state == DHCPV6_STATE_SOLICIT)
Sergunb 0:8918a71cdbe9 1709 {
Sergunb 0:8918a71cdbe9 1710 //A Reply message is not acceptable when rapid commit is disallowed
Sergunb 0:8918a71cdbe9 1711 if(!context->settings.rapidCommit)
Sergunb 0:8918a71cdbe9 1712 return;
Sergunb 0:8918a71cdbe9 1713
Sergunb 0:8918a71cdbe9 1714 //Search for the Rapid Commit option
Sergunb 0:8918a71cdbe9 1715 option = dhcpv6GetOption(message->options, length, DHCPV6_OPTION_RAPID_COMMIT);
Sergunb 0:8918a71cdbe9 1716
Sergunb 0:8918a71cdbe9 1717 //The client discards any message that does not include a Rapid Commit option
Sergunb 0:8918a71cdbe9 1718 if(option == NULL || ntohs(option->length) != 0)
Sergunb 0:8918a71cdbe9 1719 return;
Sergunb 0:8918a71cdbe9 1720 }
Sergunb 0:8918a71cdbe9 1721 else if(context->state == DHCPV6_STATE_REQUEST)
Sergunb 0:8918a71cdbe9 1722 {
Sergunb 0:8918a71cdbe9 1723 //The client must discard the Reply message if the contents of the
Sergunb 0:8918a71cdbe9 1724 //Server Identifier option do not match the server’s DUID
Sergunb 0:8918a71cdbe9 1725 if(!dhcpv6ClientCheckServerId(context, serverIdOption))
Sergunb 0:8918a71cdbe9 1726 return;
Sergunb 0:8918a71cdbe9 1727 }
Sergunb 0:8918a71cdbe9 1728 else if(context->state == DHCPV6_STATE_CONFIRM)
Sergunb 0:8918a71cdbe9 1729 {
Sergunb 0:8918a71cdbe9 1730 //When the client receives a NotOnLink status from the server in response
Sergunb 0:8918a71cdbe9 1731 //to a Confirm message, the client performs DHCP server solicitation
Sergunb 0:8918a71cdbe9 1732 if(status == DHCPV6_STATUS_NOT_ON_LINK)
Sergunb 0:8918a71cdbe9 1733 {
Sergunb 0:8918a71cdbe9 1734 //Restart the DHCP server discovery process
Sergunb 0:8918a71cdbe9 1735 dhcpv6ClientChangeState(context, DHCPV6_STATE_INIT, 0);
Sergunb 0:8918a71cdbe9 1736
Sergunb 0:8918a71cdbe9 1737 //Exit immediately
Sergunb 0:8918a71cdbe9 1738 return;
Sergunb 0:8918a71cdbe9 1739 }
Sergunb 0:8918a71cdbe9 1740 }
Sergunb 0:8918a71cdbe9 1741 else if(context->state == DHCPV6_STATE_RENEW)
Sergunb 0:8918a71cdbe9 1742 {
Sergunb 0:8918a71cdbe9 1743 //The client must discard the Reply message if the contents of the
Sergunb 0:8918a71cdbe9 1744 //Server Identifier option do not match the server’s DUID
Sergunb 0:8918a71cdbe9 1745 if(!dhcpv6ClientCheckServerId(context, serverIdOption))
Sergunb 0:8918a71cdbe9 1746 return;
Sergunb 0:8918a71cdbe9 1747 }
Sergunb 0:8918a71cdbe9 1748 else if(context->state == DHCPV6_STATE_REBIND)
Sergunb 0:8918a71cdbe9 1749 {
Sergunb 0:8918a71cdbe9 1750 //Do not check the server's DUID when the Reply message is
Sergunb 0:8918a71cdbe9 1751 //received in response to a Rebind message
Sergunb 0:8918a71cdbe9 1752 }
Sergunb 0:8918a71cdbe9 1753 else if(context->state == DHCPV6_STATE_RELEASE)
Sergunb 0:8918a71cdbe9 1754 {
Sergunb 0:8918a71cdbe9 1755 //The client must discard the Reply message if the contents of the
Sergunb 0:8918a71cdbe9 1756 //Server Identifier option do not match the server’s DUID
Sergunb 0:8918a71cdbe9 1757 if(!dhcpv6ClientCheckServerId(context, serverIdOption))
Sergunb 0:8918a71cdbe9 1758 return;
Sergunb 0:8918a71cdbe9 1759
Sergunb 0:8918a71cdbe9 1760 //When the client receives a valid Reply message in response to a
Sergunb 0:8918a71cdbe9 1761 //Release message, the client considers the Release event completed,
Sergunb 0:8918a71cdbe9 1762 //regardless of the Status Code option(s) returned by the server
Sergunb 0:8918a71cdbe9 1763 context->running = FALSE;
Sergunb 0:8918a71cdbe9 1764
Sergunb 0:8918a71cdbe9 1765 //Reinitialize state machine
Sergunb 0:8918a71cdbe9 1766 dhcpv6ClientChangeState(context, DHCPV6_STATE_INIT, 0);
Sergunb 0:8918a71cdbe9 1767
Sergunb 0:8918a71cdbe9 1768 //Exit immediately
Sergunb 0:8918a71cdbe9 1769 return;
Sergunb 0:8918a71cdbe9 1770 }
Sergunb 0:8918a71cdbe9 1771 else if(context->state == DHCPV6_STATE_DECLINE)
Sergunb 0:8918a71cdbe9 1772 {
Sergunb 0:8918a71cdbe9 1773 //The client must discard the Reply message if the contents of the
Sergunb 0:8918a71cdbe9 1774 //Server Identifier option do not match the server’s DUID
Sergunb 0:8918a71cdbe9 1775 if(!dhcpv6ClientCheckServerId(context, serverIdOption))
Sergunb 0:8918a71cdbe9 1776 return;
Sergunb 0:8918a71cdbe9 1777
Sergunb 0:8918a71cdbe9 1778 //When the client receives a valid Reply message in response to a
Sergunb 0:8918a71cdbe9 1779 //Decline message, the client considers the Decline event completed,
Sergunb 0:8918a71cdbe9 1780 //regardless of the Status Code option returned by the server
Sergunb 0:8918a71cdbe9 1781 dhcpv6ClientChangeState(context, DHCPV6_STATE_INIT, 0);
Sergunb 0:8918a71cdbe9 1782
Sergunb 0:8918a71cdbe9 1783 //Exit immediately
Sergunb 0:8918a71cdbe9 1784 return;
Sergunb 0:8918a71cdbe9 1785 }
Sergunb 0:8918a71cdbe9 1786 else
Sergunb 0:8918a71cdbe9 1787 {
Sergunb 0:8918a71cdbe9 1788 //Silently discard the Reply message
Sergunb 0:8918a71cdbe9 1789 return;
Sergunb 0:8918a71cdbe9 1790 }
Sergunb 0:8918a71cdbe9 1791
Sergunb 0:8918a71cdbe9 1792 //Check status code
Sergunb 0:8918a71cdbe9 1793 if(status == DHCPV6_STATUS_USE_MULTICAST)
Sergunb 0:8918a71cdbe9 1794 {
Sergunb 0:8918a71cdbe9 1795 //When the client receives a Reply message with a Status Code option
Sergunb 0:8918a71cdbe9 1796 //with the value UseMulticast, the client records the receipt of the
Sergunb 0:8918a71cdbe9 1797 //message and sends subsequent messages to the server through the
Sergunb 0:8918a71cdbe9 1798 //interface on which the message was received using multicast
Sergunb 0:8918a71cdbe9 1799 return;
Sergunb 0:8918a71cdbe9 1800 }
Sergunb 0:8918a71cdbe9 1801 else if(status == DHCPV6_STATUS_UNSPEC_FAILURE)
Sergunb 0:8918a71cdbe9 1802 {
Sergunb 0:8918a71cdbe9 1803 //If the client receives a Reply message with a Status Code containing
Sergunb 0:8918a71cdbe9 1804 //UnspecFail, the server is indicating that it was unable to process
Sergunb 0:8918a71cdbe9 1805 //the message due to an unspecified failure condition
Sergunb 0:8918a71cdbe9 1806 return;
Sergunb 0:8918a71cdbe9 1807 }
Sergunb 0:8918a71cdbe9 1808
Sergunb 0:8918a71cdbe9 1809 //This flag will be set if a valid IA_NA option is found
Sergunb 0:8918a71cdbe9 1810 iaNaOptionFound = FALSE;
Sergunb 0:8918a71cdbe9 1811 //Point to the first option
Sergunb 0:8918a71cdbe9 1812 i = 0;
Sergunb 0:8918a71cdbe9 1813
Sergunb 0:8918a71cdbe9 1814 //Loop through DHCPv6 options
Sergunb 0:8918a71cdbe9 1815 while(i < length)
Sergunb 0:8918a71cdbe9 1816 {
Sergunb 0:8918a71cdbe9 1817 //Search for an IA_NA option
Sergunb 0:8918a71cdbe9 1818 option = dhcpv6GetOption(message->options + i, length - i, DHCPV6_OPTION_IA_NA);
Sergunb 0:8918a71cdbe9 1819
Sergunb 0:8918a71cdbe9 1820 //Unable to find the specified option?
Sergunb 0:8918a71cdbe9 1821 if(option == NULL)
Sergunb 0:8918a71cdbe9 1822 break;
Sergunb 0:8918a71cdbe9 1823
Sergunb 0:8918a71cdbe9 1824 //Parse the contents of the IA_NA option
Sergunb 0:8918a71cdbe9 1825 error = dhcpv6ClientParseIaNaOption(context, option);
Sergunb 0:8918a71cdbe9 1826
Sergunb 0:8918a71cdbe9 1827 //Check error code
Sergunb 0:8918a71cdbe9 1828 if(error == NO_ERROR)
Sergunb 0:8918a71cdbe9 1829 {
Sergunb 0:8918a71cdbe9 1830 //A valid IA_NA option has been found
Sergunb 0:8918a71cdbe9 1831 iaNaOptionFound = TRUE;
Sergunb 0:8918a71cdbe9 1832 }
Sergunb 0:8918a71cdbe9 1833 else if(error == ERROR_NOT_ON_LINK)
Sergunb 0:8918a71cdbe9 1834 {
Sergunb 0:8918a71cdbe9 1835 //When the client receives a NotOnLink status from the server
Sergunb 0:8918a71cdbe9 1836 //in response to a Request, the client can either re-issue the
Sergunb 0:8918a71cdbe9 1837 //Request without specifying any addresses or restart the DHCP
Sergunb 0:8918a71cdbe9 1838 //server discovery process
Sergunb 0:8918a71cdbe9 1839 dhcpv6ClientChangeState(context, DHCPV6_STATE_INIT, 0);
Sergunb 0:8918a71cdbe9 1840
Sergunb 0:8918a71cdbe9 1841 //Exit immediately
Sergunb 0:8918a71cdbe9 1842 return;
Sergunb 0:8918a71cdbe9 1843 }
Sergunb 0:8918a71cdbe9 1844 else if(error == ERROR_NO_BINDING)
Sergunb 0:8918a71cdbe9 1845 {
Sergunb 0:8918a71cdbe9 1846 //When the client receives a Reply message in response to a Renew
Sergunb 0:8918a71cdbe9 1847 //or Rebind message, the client sends a Request message if any of
Sergunb 0:8918a71cdbe9 1848 //the IAs in the Reply message contains the NoBinding status code
Sergunb 0:8918a71cdbe9 1849 dhcpv6ClientChangeState(context, DHCPV6_STATE_REQUEST, 0);
Sergunb 0:8918a71cdbe9 1850
Sergunb 0:8918a71cdbe9 1851 //Exit immediately
Sergunb 0:8918a71cdbe9 1852 return;
Sergunb 0:8918a71cdbe9 1853 }
Sergunb 0:8918a71cdbe9 1854 else
Sergunb 0:8918a71cdbe9 1855 {
Sergunb 0:8918a71cdbe9 1856 //If an invalid option is received, the client discards
Sergunb 0:8918a71cdbe9 1857 //the option and process the rest of the message...
Sergunb 0:8918a71cdbe9 1858 }
Sergunb 0:8918a71cdbe9 1859
Sergunb 0:8918a71cdbe9 1860 //Jump to the next option
Sergunb 0:8918a71cdbe9 1861 i += sizeof(Dhcpv6Option) + ntohs(option->length);
Sergunb 0:8918a71cdbe9 1862 }
Sergunb 0:8918a71cdbe9 1863
Sergunb 0:8918a71cdbe9 1864 //No usable addresses in any of the IAs?
Sergunb 0:8918a71cdbe9 1865 if(!iaNaOptionFound)
Sergunb 0:8918a71cdbe9 1866 {
Sergunb 0:8918a71cdbe9 1867 //Check whether the client receives a Reply message in response
Sergunb 0:8918a71cdbe9 1868 //to a Renew or Rebind message
Sergunb 0:8918a71cdbe9 1869 if(context->state == DHCPV6_STATE_RENEW ||
Sergunb 0:8918a71cdbe9 1870 context->state == DHCPV6_STATE_REBIND)
Sergunb 0:8918a71cdbe9 1871 {
Sergunb 0:8918a71cdbe9 1872 //The client sends a Renew/Rebind if the IA is not in the Reply message
Sergunb 0:8918a71cdbe9 1873 }
Sergunb 0:8918a71cdbe9 1874 else
Sergunb 0:8918a71cdbe9 1875 {
Sergunb 0:8918a71cdbe9 1876 //If the client finds no usable addresses in any of the IAs, it may try
Sergunb 0:8918a71cdbe9 1877 //another server (perhaps restarting the DHCP server discovery process)
Sergunb 0:8918a71cdbe9 1878 dhcpv6ClientChangeState(context, DHCPV6_STATE_INIT, 0);
Sergunb 0:8918a71cdbe9 1879 }
Sergunb 0:8918a71cdbe9 1880
Sergunb 0:8918a71cdbe9 1881 //Exit immediately
Sergunb 0:8918a71cdbe9 1882 return;
Sergunb 0:8918a71cdbe9 1883 }
Sergunb 0:8918a71cdbe9 1884
Sergunb 0:8918a71cdbe9 1885 //Total number of valid IPv6 in the IA
Sergunb 0:8918a71cdbe9 1886 n = 0;
Sergunb 0:8918a71cdbe9 1887 //Number of new IPv6 addresses in the IA
Sergunb 0:8918a71cdbe9 1888 k = 0;
Sergunb 0:8918a71cdbe9 1889 //Minimum preferred lifetime observed in the IA
Sergunb 0:8918a71cdbe9 1890 minPreferredLifetime = 0;
Sergunb 0:8918a71cdbe9 1891
Sergunb 0:8918a71cdbe9 1892 //Loop through the IPv6 addresses recorded by the DHCPv6 client
Sergunb 0:8918a71cdbe9 1893 for(i = 0; i < DHCPV6_CLIENT_ADDR_LIST_SIZE; i++)
Sergunb 0:8918a71cdbe9 1894 {
Sergunb 0:8918a71cdbe9 1895 //Point to the current entry
Sergunb 0:8918a71cdbe9 1896 entry = &context->ia.addrList[i];
Sergunb 0:8918a71cdbe9 1897
Sergunb 0:8918a71cdbe9 1898 //Valid IPv6 address?
Sergunb 0:8918a71cdbe9 1899 if(entry->validLifetime > 0)
Sergunb 0:8918a71cdbe9 1900 {
Sergunb 0:8918a71cdbe9 1901 //Total number of valid IPv6 in the IA
Sergunb 0:8918a71cdbe9 1902 n++;
Sergunb 0:8918a71cdbe9 1903
Sergunb 0:8918a71cdbe9 1904 //Save the minimum preferred lifetime that has been observed so far
Sergunb 0:8918a71cdbe9 1905 if(minPreferredLifetime < entry->preferredLifetime)
Sergunb 0:8918a71cdbe9 1906 minPreferredLifetime = entry->preferredLifetime;
Sergunb 0:8918a71cdbe9 1907
Sergunb 0:8918a71cdbe9 1908 //Update lifetimes of the current IPv6 address
Sergunb 0:8918a71cdbe9 1909 ipv6AddAddr(interface, &entry->addr, entry->validLifetime,
Sergunb 0:8918a71cdbe9 1910 entry->preferredLifetime);
Sergunb 0:8918a71cdbe9 1911
Sergunb 0:8918a71cdbe9 1912 //New IPv6 address added?
Sergunb 0:8918a71cdbe9 1913 if(ipv6GetAddrState(interface, &entry->addr) == IPV6_ADDR_STATE_TENTATIVE)
Sergunb 0:8918a71cdbe9 1914 k++;
Sergunb 0:8918a71cdbe9 1915 }
Sergunb 0:8918a71cdbe9 1916 }
Sergunb 0:8918a71cdbe9 1917
Sergunb 0:8918a71cdbe9 1918 //Make sure that the IA contains at least one IPv6 address
Sergunb 0:8918a71cdbe9 1919 if(n > 0)
Sergunb 0:8918a71cdbe9 1920 {
Sergunb 0:8918a71cdbe9 1921 //Save the length of the DUID
Sergunb 0:8918a71cdbe9 1922 context->serverIdLength = ntohs(serverIdOption->length);
Sergunb 0:8918a71cdbe9 1923 //Record the server DUID
Sergunb 0:8918a71cdbe9 1924 memcpy(context->serverId, serverIdOption->value, context->serverIdLength);
Sergunb 0:8918a71cdbe9 1925
Sergunb 0:8918a71cdbe9 1926 //Save the time a which the lease was obtained
Sergunb 0:8918a71cdbe9 1927 context->leaseStartTime = osGetSystemTime();
Sergunb 0:8918a71cdbe9 1928
Sergunb 0:8918a71cdbe9 1929 //Check the value of T1
Sergunb 0:8918a71cdbe9 1930 if(context->ia.t1 == 0)
Sergunb 0:8918a71cdbe9 1931 {
Sergunb 0:8918a71cdbe9 1932 //If T1 is set to 0 by the server, the client may send
Sergunb 0:8918a71cdbe9 1933 //a Renew message at the client's discretion
Sergunb 0:8918a71cdbe9 1934 if(minPreferredLifetime == DHCPV6_INFINITE_TIME)
Sergunb 0:8918a71cdbe9 1935 context->ia.t1 = DHCPV6_INFINITE_TIME;
Sergunb 0:8918a71cdbe9 1936 else
Sergunb 0:8918a71cdbe9 1937 context->ia.t1 = minPreferredLifetime / 2;
Sergunb 0:8918a71cdbe9 1938 }
Sergunb 0:8918a71cdbe9 1939
Sergunb 0:8918a71cdbe9 1940 //Check the value of T2
Sergunb 0:8918a71cdbe9 1941 if(context->ia.t2 == 0)
Sergunb 0:8918a71cdbe9 1942 {
Sergunb 0:8918a71cdbe9 1943 //If T2 is set to 0 by the server, the client may send
Sergunb 0:8918a71cdbe9 1944 //a Rebind message at the client's discretion
Sergunb 0:8918a71cdbe9 1945 if(context->ia.t1 == DHCPV6_INFINITE_TIME)
Sergunb 0:8918a71cdbe9 1946 context->ia.t2 = DHCPV6_INFINITE_TIME;
Sergunb 0:8918a71cdbe9 1947 else
Sergunb 0:8918a71cdbe9 1948 context->ia.t2 = context->ia.t1 + context->ia.t1 / 2;
Sergunb 0:8918a71cdbe9 1949 }
Sergunb 0:8918a71cdbe9 1950
Sergunb 0:8918a71cdbe9 1951 //Any addresses added in the IA?
Sergunb 0:8918a71cdbe9 1952 if(k > 0)
Sergunb 0:8918a71cdbe9 1953 {
Sergunb 0:8918a71cdbe9 1954 //Perform Duplicate Address Detection for the new IPv6 addresses
Sergunb 0:8918a71cdbe9 1955 dhcpv6ClientChangeState(context, DHCPV6_STATE_DAD, 0);
Sergunb 0:8918a71cdbe9 1956 }
Sergunb 0:8918a71cdbe9 1957 else
Sergunb 0:8918a71cdbe9 1958 {
Sergunb 0:8918a71cdbe9 1959 //Switch to the BOUND state
Sergunb 0:8918a71cdbe9 1960 dhcpv6ClientChangeState(context, DHCPV6_STATE_BOUND, 0);
Sergunb 0:8918a71cdbe9 1961 }
Sergunb 0:8918a71cdbe9 1962 }
Sergunb 0:8918a71cdbe9 1963 else
Sergunb 0:8918a71cdbe9 1964 {
Sergunb 0:8918a71cdbe9 1965 //If the client finds no usable addresses in any of the IAs, it may try
Sergunb 0:8918a71cdbe9 1966 //another server (perhaps restarting the DHCP server discovery process)
Sergunb 0:8918a71cdbe9 1967 dhcpv6ClientChangeState(context, DHCPV6_STATE_INIT, 0);
Sergunb 0:8918a71cdbe9 1968 }
Sergunb 0:8918a71cdbe9 1969 }
Sergunb 0:8918a71cdbe9 1970
Sergunb 0:8918a71cdbe9 1971
Sergunb 0:8918a71cdbe9 1972 /**
Sergunb 0:8918a71cdbe9 1973 * @brief Parse IA_NA option
Sergunb 0:8918a71cdbe9 1974 * @param[in] context Pointer to the DHCPv6 client context
Sergunb 0:8918a71cdbe9 1975 * @param[in] option Pointer to the IA_NA option to parse
Sergunb 0:8918a71cdbe9 1976 * @return Error code
Sergunb 0:8918a71cdbe9 1977 **/
Sergunb 0:8918a71cdbe9 1978
Sergunb 0:8918a71cdbe9 1979 error_t dhcpv6ClientParseIaNaOption(Dhcpv6ClientContext *context,
Sergunb 0:8918a71cdbe9 1980 const Dhcpv6Option *option)
Sergunb 0:8918a71cdbe9 1981 {
Sergunb 0:8918a71cdbe9 1982 error_t error;
Sergunb 0:8918a71cdbe9 1983 uint_t n;
Sergunb 0:8918a71cdbe9 1984 size_t i;
Sergunb 0:8918a71cdbe9 1985 size_t length;
Sergunb 0:8918a71cdbe9 1986 NetInterface *interface;
Sergunb 0:8918a71cdbe9 1987 Dhcpv6StatusCode status;
Sergunb 0:8918a71cdbe9 1988 Dhcpv6IaNaOption *iaNaOption;
Sergunb 0:8918a71cdbe9 1989
Sergunb 0:8918a71cdbe9 1990 //Point to the underlying network interface
Sergunb 0:8918a71cdbe9 1991 interface = context->settings.interface;
Sergunb 0:8918a71cdbe9 1992
Sergunb 0:8918a71cdbe9 1993 //Number of addresses found in the IA_NA option
Sergunb 0:8918a71cdbe9 1994 n = 0;
Sergunb 0:8918a71cdbe9 1995
Sergunb 0:8918a71cdbe9 1996 //Make sure the IA_NA option is valid
Sergunb 0:8918a71cdbe9 1997 if(ntohs(option->length) < sizeof(Dhcpv6IaNaOption))
Sergunb 0:8918a71cdbe9 1998 return ERROR_INVALID_LENGTH;
Sergunb 0:8918a71cdbe9 1999
Sergunb 0:8918a71cdbe9 2000 //Get the parameters associated with the IA_NA
Sergunb 0:8918a71cdbe9 2001 iaNaOption = (Dhcpv6IaNaOption *) option->value;
Sergunb 0:8918a71cdbe9 2002 //Compute the length of IA_NA Options field
Sergunb 0:8918a71cdbe9 2003 length = ntohs(option->length) - sizeof(Dhcpv6IaNaOption);
Sergunb 0:8918a71cdbe9 2004
Sergunb 0:8918a71cdbe9 2005 //Check the IA identifier
Sergunb 0:8918a71cdbe9 2006 if(ntohl(iaNaOption->iaId) != interface->id)
Sergunb 0:8918a71cdbe9 2007 return ERROR_WRONG_IDENTIFIER;
Sergunb 0:8918a71cdbe9 2008
Sergunb 0:8918a71cdbe9 2009 //If a client receives an IA_NA with T1 greater than T2, and both T1
Sergunb 0:8918a71cdbe9 2010 //and T2 are greater than 0, the client discards the IA_NA option and
Sergunb 0:8918a71cdbe9 2011 //processes the remainder of the message as though the server had not
Sergunb 0:8918a71cdbe9 2012 //included the invalid IA_NA option
Sergunb 0:8918a71cdbe9 2013 if(ntohl(iaNaOption->t1) > ntohl(iaNaOption->t2) && ntohl(iaNaOption->t2) > 0)
Sergunb 0:8918a71cdbe9 2014 return ERROR_INVALID_PARAMETER;
Sergunb 0:8918a71cdbe9 2015
Sergunb 0:8918a71cdbe9 2016 //The client examines the status code in each IA individually
Sergunb 0:8918a71cdbe9 2017 status = dhcpv6GetStatusCode(iaNaOption->options, length);
Sergunb 0:8918a71cdbe9 2018
Sergunb 0:8918a71cdbe9 2019 //Check error code
Sergunb 0:8918a71cdbe9 2020 if(status == DHCPV6_STATUS_NO_ADDRS_AVAILABLE)
Sergunb 0:8918a71cdbe9 2021 {
Sergunb 0:8918a71cdbe9 2022 //The client has received no usable address in the IA
Sergunb 0:8918a71cdbe9 2023 return ERROR_NO_ADDRESS;
Sergunb 0:8918a71cdbe9 2024 }
Sergunb 0:8918a71cdbe9 2025 else if(status == DHCPV6_STATUS_NO_BINDING)
Sergunb 0:8918a71cdbe9 2026 {
Sergunb 0:8918a71cdbe9 2027 //Client record (binding) unavailable
Sergunb 0:8918a71cdbe9 2028 return ERROR_NO_BINDING;
Sergunb 0:8918a71cdbe9 2029 }
Sergunb 0:8918a71cdbe9 2030 else if(status == DHCPV6_STATUS_NOT_ON_LINK)
Sergunb 0:8918a71cdbe9 2031 {
Sergunb 0:8918a71cdbe9 2032 //The prefix for the address is not appropriate for the
Sergunb 0:8918a71cdbe9 2033 //link to which the client is attached
Sergunb 0:8918a71cdbe9 2034 return ERROR_NOT_ON_LINK;
Sergunb 0:8918a71cdbe9 2035 }
Sergunb 0:8918a71cdbe9 2036 else if(status != DHCPV6_STATUS_SUCCESS)
Sergunb 0:8918a71cdbe9 2037 {
Sergunb 0:8918a71cdbe9 2038 //Failure, reason unspecified
Sergunb 0:8918a71cdbe9 2039 return ERROR_FAILURE;
Sergunb 0:8918a71cdbe9 2040 }
Sergunb 0:8918a71cdbe9 2041
Sergunb 0:8918a71cdbe9 2042 //Record T1 and T2 times
Sergunb 0:8918a71cdbe9 2043 context->ia.t1 = ntohl(iaNaOption->t1);
Sergunb 0:8918a71cdbe9 2044 context->ia.t2 = ntohl(iaNaOption->t2);
Sergunb 0:8918a71cdbe9 2045
Sergunb 0:8918a71cdbe9 2046 //Point to the first option
Sergunb 0:8918a71cdbe9 2047 i = 0;
Sergunb 0:8918a71cdbe9 2048
Sergunb 0:8918a71cdbe9 2049 //Loop through IA_NA options
Sergunb 0:8918a71cdbe9 2050 while(i < length)
Sergunb 0:8918a71cdbe9 2051 {
Sergunb 0:8918a71cdbe9 2052 //Search for an IA Address option
Sergunb 0:8918a71cdbe9 2053 option = dhcpv6GetOption(iaNaOption->options + i, length - i, DHCPV6_OPTION_IAADDR);
Sergunb 0:8918a71cdbe9 2054
Sergunb 0:8918a71cdbe9 2055 //Unable to find the specified option?
Sergunb 0:8918a71cdbe9 2056 if(option == NULL)
Sergunb 0:8918a71cdbe9 2057 break;
Sergunb 0:8918a71cdbe9 2058
Sergunb 0:8918a71cdbe9 2059 //Parse the contents of the IA Address option
Sergunb 0:8918a71cdbe9 2060 error = dhcpv6ClientParseIaAddrOption(context, option);
Sergunb 0:8918a71cdbe9 2061
Sergunb 0:8918a71cdbe9 2062 //Check status code
Sergunb 0:8918a71cdbe9 2063 if(!error)
Sergunb 0:8918a71cdbe9 2064 {
Sergunb 0:8918a71cdbe9 2065 //Increment the number of addresses found in the IA_NA option
Sergunb 0:8918a71cdbe9 2066 n++;
Sergunb 0:8918a71cdbe9 2067 }
Sergunb 0:8918a71cdbe9 2068
Sergunb 0:8918a71cdbe9 2069 //Jump to the next option
Sergunb 0:8918a71cdbe9 2070 i += sizeof(Dhcpv6Option) + ntohs(option->length);
Sergunb 0:8918a71cdbe9 2071 }
Sergunb 0:8918a71cdbe9 2072
Sergunb 0:8918a71cdbe9 2073 //No usable addresses in the IA_NA option?
Sergunb 0:8918a71cdbe9 2074 if(n == 0)
Sergunb 0:8918a71cdbe9 2075 {
Sergunb 0:8918a71cdbe9 2076 //Report an error
Sergunb 0:8918a71cdbe9 2077 return ERROR_NO_ADDRESS;
Sergunb 0:8918a71cdbe9 2078 }
Sergunb 0:8918a71cdbe9 2079
Sergunb 0:8918a71cdbe9 2080 //Successful processing
Sergunb 0:8918a71cdbe9 2081 return NO_ERROR;
Sergunb 0:8918a71cdbe9 2082 }
Sergunb 0:8918a71cdbe9 2083
Sergunb 0:8918a71cdbe9 2084
Sergunb 0:8918a71cdbe9 2085 /**
Sergunb 0:8918a71cdbe9 2086 * @brief Parse IA Address option
Sergunb 0:8918a71cdbe9 2087 * @param[in] context Pointer to the DHCPv6 client context
Sergunb 0:8918a71cdbe9 2088 * @param[in] option Pointer to the IA Address option to parse
Sergunb 0:8918a71cdbe9 2089 * @return Error code
Sergunb 0:8918a71cdbe9 2090 **/
Sergunb 0:8918a71cdbe9 2091
Sergunb 0:8918a71cdbe9 2092 error_t dhcpv6ClientParseIaAddrOption(Dhcpv6ClientContext *context,
Sergunb 0:8918a71cdbe9 2093 const Dhcpv6Option *option)
Sergunb 0:8918a71cdbe9 2094 {
Sergunb 0:8918a71cdbe9 2095 size_t length;
Sergunb 0:8918a71cdbe9 2096 uint32_t validLifetime;
Sergunb 0:8918a71cdbe9 2097 uint32_t preferredLifetime;
Sergunb 0:8918a71cdbe9 2098 Dhcpv6StatusCode status;
Sergunb 0:8918a71cdbe9 2099 Dhcpv6IaAddrOption *iaAddrOption;
Sergunb 0:8918a71cdbe9 2100
Sergunb 0:8918a71cdbe9 2101 //Make sure the IA Address option is valid
Sergunb 0:8918a71cdbe9 2102 if(ntohs(option->length) < sizeof(Dhcpv6IaAddrOption))
Sergunb 0:8918a71cdbe9 2103 return ERROR_INVALID_LENGTH;
Sergunb 0:8918a71cdbe9 2104
Sergunb 0:8918a71cdbe9 2105 //Point to the contents of the IA Address option
Sergunb 0:8918a71cdbe9 2106 iaAddrOption = (Dhcpv6IaAddrOption *) option->value;
Sergunb 0:8918a71cdbe9 2107 //Compute the length of IA Address Options field
Sergunb 0:8918a71cdbe9 2108 length = ntohs(option->length) - sizeof(Dhcpv6IaAddrOption);
Sergunb 0:8918a71cdbe9 2109
Sergunb 0:8918a71cdbe9 2110 //Convert lifetimes to host byte order
Sergunb 0:8918a71cdbe9 2111 validLifetime = ntohl(iaAddrOption->validLifetime);
Sergunb 0:8918a71cdbe9 2112 preferredLifetime = ntohl(iaAddrOption->preferredLifetime);
Sergunb 0:8918a71cdbe9 2113
Sergunb 0:8918a71cdbe9 2114 //A client discards any addresses for which the preferred lifetime
Sergunb 0:8918a71cdbe9 2115 //is greater than the valid lifetime
Sergunb 0:8918a71cdbe9 2116 if(preferredLifetime > validLifetime)
Sergunb 0:8918a71cdbe9 2117 return ERROR_INVALID_PARAMETER;
Sergunb 0:8918a71cdbe9 2118
Sergunb 0:8918a71cdbe9 2119 //The client examines the status code in each IA Address
Sergunb 0:8918a71cdbe9 2120 status = dhcpv6GetStatusCode(iaAddrOption->options, length);
Sergunb 0:8918a71cdbe9 2121
Sergunb 0:8918a71cdbe9 2122 //Any error to report?
Sergunb 0:8918a71cdbe9 2123 if(status != DHCPV6_STATUS_SUCCESS)
Sergunb 0:8918a71cdbe9 2124 return ERROR_FAILURE;
Sergunb 0:8918a71cdbe9 2125
Sergunb 0:8918a71cdbe9 2126 //Check the value of the Valid Lifetime
Sergunb 0:8918a71cdbe9 2127 if(iaAddrOption->validLifetime > 0)
Sergunb 0:8918a71cdbe9 2128 {
Sergunb 0:8918a71cdbe9 2129 //Add any new addresses in the IA option to the IA as recorded
Sergunb 0:8918a71cdbe9 2130 //by the client
Sergunb 0:8918a71cdbe9 2131 dhcpv6ClientAddAddr(context, &iaAddrOption->address,
Sergunb 0:8918a71cdbe9 2132 validLifetime, preferredLifetime);
Sergunb 0:8918a71cdbe9 2133 }
Sergunb 0:8918a71cdbe9 2134 else
Sergunb 0:8918a71cdbe9 2135 {
Sergunb 0:8918a71cdbe9 2136 //Discard any addresses from the IA, as recorded by the client,
Sergunb 0:8918a71cdbe9 2137 //that have a valid lifetime of 0 in the IA Address option
Sergunb 0:8918a71cdbe9 2138 dhcpv6ClientRemoveAddr(context, &iaAddrOption->address);
Sergunb 0:8918a71cdbe9 2139 }
Sergunb 0:8918a71cdbe9 2140
Sergunb 0:8918a71cdbe9 2141 //Successful processing
Sergunb 0:8918a71cdbe9 2142 return NO_ERROR;
Sergunb 0:8918a71cdbe9 2143 }
Sergunb 0:8918a71cdbe9 2144
Sergunb 0:8918a71cdbe9 2145
Sergunb 0:8918a71cdbe9 2146 /**
Sergunb 0:8918a71cdbe9 2147 * @brief Add an IPv6 address to the IA
Sergunb 0:8918a71cdbe9 2148 * @param[in] context Pointer to the DHCPv6 client context
Sergunb 0:8918a71cdbe9 2149 * @param[in] addr IPv6 address to be added
Sergunb 0:8918a71cdbe9 2150 * @param[in] validLifetime Valid lifetime, in seconds
Sergunb 0:8918a71cdbe9 2151 * @param[in] preferredLifetime Preferred lifetime, in seconds
Sergunb 0:8918a71cdbe9 2152 **/
Sergunb 0:8918a71cdbe9 2153
Sergunb 0:8918a71cdbe9 2154 void dhcpv6ClientAddAddr(Dhcpv6ClientContext *context, const Ipv6Addr *addr,
Sergunb 0:8918a71cdbe9 2155 uint32_t validLifetime, uint32_t preferredLifetime)
Sergunb 0:8918a71cdbe9 2156 {
Sergunb 0:8918a71cdbe9 2157 uint_t i;
Sergunb 0:8918a71cdbe9 2158 Dhcpv6ClientAddrEntry *entry;
Sergunb 0:8918a71cdbe9 2159 Dhcpv6ClientAddrEntry *firstFreeEntry;
Sergunb 0:8918a71cdbe9 2160
Sergunb 0:8918a71cdbe9 2161 //Keep track of the first free entry
Sergunb 0:8918a71cdbe9 2162 firstFreeEntry = NULL;
Sergunb 0:8918a71cdbe9 2163
Sergunb 0:8918a71cdbe9 2164 //Loop through the IPv6 addresses recorded by the DHCPv6 client
Sergunb 0:8918a71cdbe9 2165 for(i = 0; i < DHCPV6_CLIENT_ADDR_LIST_SIZE; i++)
Sergunb 0:8918a71cdbe9 2166 {
Sergunb 0:8918a71cdbe9 2167 //Point to the current entry
Sergunb 0:8918a71cdbe9 2168 entry = &context->ia.addrList[i];
Sergunb 0:8918a71cdbe9 2169
Sergunb 0:8918a71cdbe9 2170 //Valid IPv6 address?
Sergunb 0:8918a71cdbe9 2171 if(entry->validLifetime > 0)
Sergunb 0:8918a71cdbe9 2172 {
Sergunb 0:8918a71cdbe9 2173 //Check whether the current entry matches the specified address
Sergunb 0:8918a71cdbe9 2174 if(ipv6CompAddr(&entry->addr, addr))
Sergunb 0:8918a71cdbe9 2175 break;
Sergunb 0:8918a71cdbe9 2176 }
Sergunb 0:8918a71cdbe9 2177 else
Sergunb 0:8918a71cdbe9 2178 {
Sergunb 0:8918a71cdbe9 2179 //Keep track of the first free entry
Sergunb 0:8918a71cdbe9 2180 if(firstFreeEntry == NULL)
Sergunb 0:8918a71cdbe9 2181 firstFreeEntry = entry;
Sergunb 0:8918a71cdbe9 2182 }
Sergunb 0:8918a71cdbe9 2183 }
Sergunb 0:8918a71cdbe9 2184
Sergunb 0:8918a71cdbe9 2185 //No matching entry found?
Sergunb 0:8918a71cdbe9 2186 if(i >= IPV6_PREFIX_LIST_SIZE)
Sergunb 0:8918a71cdbe9 2187 entry = firstFreeEntry;
Sergunb 0:8918a71cdbe9 2188
Sergunb 0:8918a71cdbe9 2189 //Update the entry if necessary
Sergunb 0:8918a71cdbe9 2190 if(entry != NULL)
Sergunb 0:8918a71cdbe9 2191 {
Sergunb 0:8918a71cdbe9 2192 //Save IPv6 address
Sergunb 0:8918a71cdbe9 2193 entry->addr = *addr;
Sergunb 0:8918a71cdbe9 2194
Sergunb 0:8918a71cdbe9 2195 //Save lifetimes
Sergunb 0:8918a71cdbe9 2196 entry->validLifetime = validLifetime;
Sergunb 0:8918a71cdbe9 2197 entry->preferredLifetime = preferredLifetime;
Sergunb 0:8918a71cdbe9 2198 }
Sergunb 0:8918a71cdbe9 2199 }
Sergunb 0:8918a71cdbe9 2200
Sergunb 0:8918a71cdbe9 2201
Sergunb 0:8918a71cdbe9 2202 /**
Sergunb 0:8918a71cdbe9 2203 * @brief Remove an IPv6 address from the IA
Sergunb 0:8918a71cdbe9 2204 * @param[in] context Pointer to the DHCPv6 client context
Sergunb 0:8918a71cdbe9 2205 * @param[in] addr IPv6 address to be removed
Sergunb 0:8918a71cdbe9 2206 **/
Sergunb 0:8918a71cdbe9 2207
Sergunb 0:8918a71cdbe9 2208 void dhcpv6ClientRemoveAddr(Dhcpv6ClientContext *context, const Ipv6Addr *addr)
Sergunb 0:8918a71cdbe9 2209 {
Sergunb 0:8918a71cdbe9 2210 uint_t i;
Sergunb 0:8918a71cdbe9 2211 NetInterface *interface;
Sergunb 0:8918a71cdbe9 2212 Dhcpv6ClientAddrEntry *entry;
Sergunb 0:8918a71cdbe9 2213
Sergunb 0:8918a71cdbe9 2214 //Point to the underlying network interface
Sergunb 0:8918a71cdbe9 2215 interface = context->settings.interface;
Sergunb 0:8918a71cdbe9 2216
Sergunb 0:8918a71cdbe9 2217 //Loop through the IPv6 addresses recorded by the DHCPv6 client
Sergunb 0:8918a71cdbe9 2218 for(i = 0; i < DHCPV6_CLIENT_ADDR_LIST_SIZE; i++)
Sergunb 0:8918a71cdbe9 2219 {
Sergunb 0:8918a71cdbe9 2220 //Point to the current entry
Sergunb 0:8918a71cdbe9 2221 entry = &context->ia.addrList[i];
Sergunb 0:8918a71cdbe9 2222
Sergunb 0:8918a71cdbe9 2223 //Valid IPv6 address?
Sergunb 0:8918a71cdbe9 2224 if(entry->validLifetime > 0)
Sergunb 0:8918a71cdbe9 2225 {
Sergunb 0:8918a71cdbe9 2226 //Check whether the current entry matches the specified address
Sergunb 0:8918a71cdbe9 2227 if(ipv6CompAddr(&entry->addr, addr))
Sergunb 0:8918a71cdbe9 2228 {
Sergunb 0:8918a71cdbe9 2229 //The IPv6 address is no more valid and should be removed from
Sergunb 0:8918a71cdbe9 2230 //the list of IPv6 addresses assigned to the interface
Sergunb 0:8918a71cdbe9 2231 ipv6RemoveAddr(interface, addr);
Sergunb 0:8918a71cdbe9 2232
Sergunb 0:8918a71cdbe9 2233 //Remove the IPv6 address from the IA
Sergunb 0:8918a71cdbe9 2234 entry->validLifetime = 0;
Sergunb 0:8918a71cdbe9 2235 }
Sergunb 0:8918a71cdbe9 2236 }
Sergunb 0:8918a71cdbe9 2237 }
Sergunb 0:8918a71cdbe9 2238 }
Sergunb 0:8918a71cdbe9 2239
Sergunb 0:8918a71cdbe9 2240
Sergunb 0:8918a71cdbe9 2241 /**
Sergunb 0:8918a71cdbe9 2242 * @brief Flush the list of IPv6 addresses from the IA
Sergunb 0:8918a71cdbe9 2243 * @param[in] context Pointer to the DHCPv6 client context
Sergunb 0:8918a71cdbe9 2244 **/
Sergunb 0:8918a71cdbe9 2245
Sergunb 0:8918a71cdbe9 2246 void dhcpv6ClientFlushAddrList(Dhcpv6ClientContext *context)
Sergunb 0:8918a71cdbe9 2247 {
Sergunb 0:8918a71cdbe9 2248 uint_t i;
Sergunb 0:8918a71cdbe9 2249 NetInterface *interface;
Sergunb 0:8918a71cdbe9 2250 Dhcpv6ClientAddrEntry *entry;
Sergunb 0:8918a71cdbe9 2251
Sergunb 0:8918a71cdbe9 2252 //Point to the underlying network interface
Sergunb 0:8918a71cdbe9 2253 interface = context->settings.interface;
Sergunb 0:8918a71cdbe9 2254
Sergunb 0:8918a71cdbe9 2255 //Loop through the IPv6 addresses recorded by the DHCPv6 client
Sergunb 0:8918a71cdbe9 2256 for(i = 0; i < DHCPV6_CLIENT_ADDR_LIST_SIZE; i++)
Sergunb 0:8918a71cdbe9 2257 {
Sergunb 0:8918a71cdbe9 2258 //Point to the current entry
Sergunb 0:8918a71cdbe9 2259 entry = &context->ia.addrList[i];
Sergunb 0:8918a71cdbe9 2260
Sergunb 0:8918a71cdbe9 2261 //Valid IPv6 address?
Sergunb 0:8918a71cdbe9 2262 if(entry->validLifetime > 0)
Sergunb 0:8918a71cdbe9 2263 {
Sergunb 0:8918a71cdbe9 2264 //The IPv6 address is no more valid and should be removed from
Sergunb 0:8918a71cdbe9 2265 //the list of IPv6 addresses assigned to the interface
Sergunb 0:8918a71cdbe9 2266 ipv6RemoveAddr(interface, &entry->addr);
Sergunb 0:8918a71cdbe9 2267
Sergunb 0:8918a71cdbe9 2268 //Remove the IPv6 address from the IA
Sergunb 0:8918a71cdbe9 2269 entry->validLifetime = 0;
Sergunb 0:8918a71cdbe9 2270 }
Sergunb 0:8918a71cdbe9 2271 }
Sergunb 0:8918a71cdbe9 2272 }
Sergunb 0:8918a71cdbe9 2273
Sergunb 0:8918a71cdbe9 2274
Sergunb 0:8918a71cdbe9 2275 /**
Sergunb 0:8918a71cdbe9 2276 * @brief Generate client's DUID
Sergunb 0:8918a71cdbe9 2277 * @param[in] context Pointer to the DHCPv6 client context
Sergunb 0:8918a71cdbe9 2278 * @return Error code
Sergunb 0:8918a71cdbe9 2279 **/
Sergunb 0:8918a71cdbe9 2280
Sergunb 0:8918a71cdbe9 2281 error_t dhcpv6ClientGenerateDuid(Dhcpv6ClientContext *context)
Sergunb 0:8918a71cdbe9 2282 {
Sergunb 0:8918a71cdbe9 2283 NetInterface *interface;
Sergunb 0:8918a71cdbe9 2284 Dhcpv6DuidLl *duid;
Sergunb 0:8918a71cdbe9 2285
Sergunb 0:8918a71cdbe9 2286 //Point to the underlying network interface
Sergunb 0:8918a71cdbe9 2287 interface = context->settings.interface;
Sergunb 0:8918a71cdbe9 2288
Sergunb 0:8918a71cdbe9 2289 //Point to the buffer where to format the client's DUID
Sergunb 0:8918a71cdbe9 2290 duid = (Dhcpv6DuidLl *) context->clientId;
Sergunb 0:8918a71cdbe9 2291
Sergunb 0:8918a71cdbe9 2292 #if (ETH_SUPPORT == ENABLED)
Sergunb 0:8918a71cdbe9 2293 //Generate a DUID-LL from the MAC address
Sergunb 0:8918a71cdbe9 2294 duid->type = HTONS(DHCPV6_DUID_LL);
Sergunb 0:8918a71cdbe9 2295 duid->hardwareType = HTONS(DHCPV6_HARDWARE_TYPE_ETH);
Sergunb 0:8918a71cdbe9 2296 duid->linkLayerAddr = interface->macAddr;
Sergunb 0:8918a71cdbe9 2297 #else
Sergunb 0:8918a71cdbe9 2298 //Generate a DUID-LL from the EUI-64 identifier
Sergunb 0:8918a71cdbe9 2299 duid->type = HTONS(DHCPV6_DUID_LL);
Sergunb 0:8918a71cdbe9 2300 duid->hardwareType = HTONS(DHCPV6_HARDWARE_TYPE_EUI64);
Sergunb 0:8918a71cdbe9 2301 duid->linkLayerAddr = interface->eui64;
Sergunb 0:8918a71cdbe9 2302 #endif
Sergunb 0:8918a71cdbe9 2303
Sergunb 0:8918a71cdbe9 2304 //Length of the newly generated DUID
Sergunb 0:8918a71cdbe9 2305 context->clientIdLength = sizeof(Dhcpv6DuidLl);
Sergunb 0:8918a71cdbe9 2306
Sergunb 0:8918a71cdbe9 2307 //Successful processing
Sergunb 0:8918a71cdbe9 2308 return NO_ERROR;
Sergunb 0:8918a71cdbe9 2309 }
Sergunb 0:8918a71cdbe9 2310
Sergunb 0:8918a71cdbe9 2311
Sergunb 0:8918a71cdbe9 2312 /**
Sergunb 0:8918a71cdbe9 2313 * @brief Generate client's fully qualified domain name
Sergunb 0:8918a71cdbe9 2314 * @param[in] context Pointer to the DHCPv6 client context
Sergunb 0:8918a71cdbe9 2315 * @return Error code
Sergunb 0:8918a71cdbe9 2316 **/
Sergunb 0:8918a71cdbe9 2317
Sergunb 0:8918a71cdbe9 2318 error_t dhcpv6ClientGenerateFqdn(Dhcpv6ClientContext *context)
Sergunb 0:8918a71cdbe9 2319 {
Sergunb 0:8918a71cdbe9 2320 NetInterface *interface;
Sergunb 0:8918a71cdbe9 2321 Dhcpv6FqdnOption *fqdnOption;
Sergunb 0:8918a71cdbe9 2322
Sergunb 0:8918a71cdbe9 2323 //Point to the underlying network interface
Sergunb 0:8918a71cdbe9 2324 interface = context->settings.interface;
Sergunb 0:8918a71cdbe9 2325
Sergunb 0:8918a71cdbe9 2326 //Point to the buffer where to format the client's FQDN
Sergunb 0:8918a71cdbe9 2327 fqdnOption = (Dhcpv6FqdnOption *) context->clientFqdn;
Sergunb 0:8918a71cdbe9 2328
Sergunb 0:8918a71cdbe9 2329 //Set flags
Sergunb 0:8918a71cdbe9 2330 fqdnOption->mbz = 0;
Sergunb 0:8918a71cdbe9 2331 fqdnOption->n = FALSE;
Sergunb 0:8918a71cdbe9 2332 fqdnOption->o = FALSE;
Sergunb 0:8918a71cdbe9 2333 fqdnOption->s = FALSE;
Sergunb 0:8918a71cdbe9 2334
Sergunb 0:8918a71cdbe9 2335 //Encode client's FQDN
Sergunb 0:8918a71cdbe9 2336 context->clientFqdnLength = dnsEncodeName(interface->hostname,
Sergunb 0:8918a71cdbe9 2337 fqdnOption->domainName);
Sergunb 0:8918a71cdbe9 2338
Sergunb 0:8918a71cdbe9 2339 //Successful processing
Sergunb 0:8918a71cdbe9 2340 return NO_ERROR;
Sergunb 0:8918a71cdbe9 2341 }
Sergunb 0:8918a71cdbe9 2342
Sergunb 0:8918a71cdbe9 2343
Sergunb 0:8918a71cdbe9 2344 /**
Sergunb 0:8918a71cdbe9 2345 * @brief Generate a link-local address
Sergunb 0:8918a71cdbe9 2346 * @param[in] context Pointer to the DHCPv6 client context
Sergunb 0:8918a71cdbe9 2347 * @return Error code
Sergunb 0:8918a71cdbe9 2348 **/
Sergunb 0:8918a71cdbe9 2349
Sergunb 0:8918a71cdbe9 2350 error_t dhcpv6ClientGenerateLinkLocalAddr(Dhcpv6ClientContext *context)
Sergunb 0:8918a71cdbe9 2351 {
Sergunb 0:8918a71cdbe9 2352 error_t error;
Sergunb 0:8918a71cdbe9 2353 NetInterface *interface;
Sergunb 0:8918a71cdbe9 2354 Ipv6Addr addr;
Sergunb 0:8918a71cdbe9 2355
Sergunb 0:8918a71cdbe9 2356 //Point to the underlying network interface
Sergunb 0:8918a71cdbe9 2357 interface = context->settings.interface;
Sergunb 0:8918a71cdbe9 2358
Sergunb 0:8918a71cdbe9 2359 //Check whether a link-local address has been manually assigned
Sergunb 0:8918a71cdbe9 2360 if(interface->ipv6Context.addrList[0].state != IPV6_ADDR_STATE_INVALID &&
Sergunb 0:8918a71cdbe9 2361 interface->ipv6Context.addrList[0].permanent)
Sergunb 0:8918a71cdbe9 2362 {
Sergunb 0:8918a71cdbe9 2363 //Keep using the current link-local address
Sergunb 0:8918a71cdbe9 2364 error = NO_ERROR;
Sergunb 0:8918a71cdbe9 2365 }
Sergunb 0:8918a71cdbe9 2366 else
Sergunb 0:8918a71cdbe9 2367 {
Sergunb 0:8918a71cdbe9 2368 //A link-local address is formed by combining the well-known
Sergunb 0:8918a71cdbe9 2369 //link-local prefix fe80::/10 with the interface identifier
Sergunb 0:8918a71cdbe9 2370 ipv6GenerateLinkLocalAddr(&interface->eui64, &addr);
Sergunb 0:8918a71cdbe9 2371
Sergunb 0:8918a71cdbe9 2372 #if (NDP_SUPPORT == ENABLED)
Sergunb 0:8918a71cdbe9 2373 //Check whether Duplicate Address Detection should be performed
Sergunb 0:8918a71cdbe9 2374 if(interface->ndpContext.dupAddrDetectTransmits > 0)
Sergunb 0:8918a71cdbe9 2375 {
Sergunb 0:8918a71cdbe9 2376 //Use the link-local address as a tentative address
Sergunb 0:8918a71cdbe9 2377 error = ipv6SetAddr(interface, 0, &addr, IPV6_ADDR_STATE_TENTATIVE,
Sergunb 0:8918a71cdbe9 2378 NDP_INFINITE_LIFETIME, NDP_INFINITE_LIFETIME, FALSE);
Sergunb 0:8918a71cdbe9 2379 }
Sergunb 0:8918a71cdbe9 2380 else
Sergunb 0:8918a71cdbe9 2381 #endif
Sergunb 0:8918a71cdbe9 2382 {
Sergunb 0:8918a71cdbe9 2383 //The use of the link-local address is now unrestricted
Sergunb 0:8918a71cdbe9 2384 error = ipv6SetAddr(interface, 0, &addr, IPV6_ADDR_STATE_PREFERRED,
Sergunb 0:8918a71cdbe9 2385 NDP_INFINITE_LIFETIME, NDP_INFINITE_LIFETIME, FALSE);
Sergunb 0:8918a71cdbe9 2386 }
Sergunb 0:8918a71cdbe9 2387 }
Sergunb 0:8918a71cdbe9 2388
Sergunb 0:8918a71cdbe9 2389 //Return status code
Sergunb 0:8918a71cdbe9 2390 return error;
Sergunb 0:8918a71cdbe9 2391 }
Sergunb 0:8918a71cdbe9 2392
Sergunb 0:8918a71cdbe9 2393
Sergunb 0:8918a71cdbe9 2394 /**
Sergunb 0:8918a71cdbe9 2395 * @brief Check the Server Identifier option
Sergunb 0:8918a71cdbe9 2396 * @param[in] context Pointer to the DHCPv6 client context
Sergunb 0:8918a71cdbe9 2397 * @param[in] serverIdOption Pointer to the Server Identifier option
Sergunb 0:8918a71cdbe9 2398 * @return TRUE if the option matches the server’s DUID, else FALSE
Sergunb 0:8918a71cdbe9 2399 **/
Sergunb 0:8918a71cdbe9 2400
Sergunb 0:8918a71cdbe9 2401 bool_t dhcpv6ClientCheckServerId(Dhcpv6ClientContext *context,
Sergunb 0:8918a71cdbe9 2402 Dhcpv6Option *serverIdOption)
Sergunb 0:8918a71cdbe9 2403 {
Sergunb 0:8918a71cdbe9 2404 bool_t valid = FALSE;
Sergunb 0:8918a71cdbe9 2405
Sergunb 0:8918a71cdbe9 2406 //Check the length of the Server Identifier option
Sergunb 0:8918a71cdbe9 2407 if(ntohs(serverIdOption->length) == context->serverIdLength)
Sergunb 0:8918a71cdbe9 2408 {
Sergunb 0:8918a71cdbe9 2409 //Check whether the Server Identifier option matches the server’s DUID
Sergunb 0:8918a71cdbe9 2410 if(!memcmp(serverIdOption->value, context->serverId, context->serverIdLength))
Sergunb 0:8918a71cdbe9 2411 valid = TRUE;
Sergunb 0:8918a71cdbe9 2412 }
Sergunb 0:8918a71cdbe9 2413
Sergunb 0:8918a71cdbe9 2414 //Return TRUE if the option matches the server’s DUID
Sergunb 0:8918a71cdbe9 2415 return valid;
Sergunb 0:8918a71cdbe9 2416 }
Sergunb 0:8918a71cdbe9 2417
Sergunb 0:8918a71cdbe9 2418
Sergunb 0:8918a71cdbe9 2419 /**
Sergunb 0:8918a71cdbe9 2420 * @brief Manage DHCPv6 configuration timeout
Sergunb 0:8918a71cdbe9 2421 * @param[in] context Pointer to the DHCPv6 client context
Sergunb 0:8918a71cdbe9 2422 **/
Sergunb 0:8918a71cdbe9 2423
Sergunb 0:8918a71cdbe9 2424 void dhcpv6ClientCheckTimeout(Dhcpv6ClientContext *context)
Sergunb 0:8918a71cdbe9 2425 {
Sergunb 0:8918a71cdbe9 2426 systime_t time;
Sergunb 0:8918a71cdbe9 2427 NetInterface *interface;
Sergunb 0:8918a71cdbe9 2428
Sergunb 0:8918a71cdbe9 2429 //Point to the underlying network interface
Sergunb 0:8918a71cdbe9 2430 interface = context->settings.interface;
Sergunb 0:8918a71cdbe9 2431
Sergunb 0:8918a71cdbe9 2432 //Get current time
Sergunb 0:8918a71cdbe9 2433 time = osGetSystemTime();
Sergunb 0:8918a71cdbe9 2434
Sergunb 0:8918a71cdbe9 2435 //Any registered callback?
Sergunb 0:8918a71cdbe9 2436 if(context->settings.timeoutEvent != NULL)
Sergunb 0:8918a71cdbe9 2437 {
Sergunb 0:8918a71cdbe9 2438 //DHCPv6 configuration timeout?
Sergunb 0:8918a71cdbe9 2439 if(timeCompare(time, context->configStartTime + context->settings.timeout) >= 0)
Sergunb 0:8918a71cdbe9 2440 {
Sergunb 0:8918a71cdbe9 2441 //Ensure the callback function is only called once
Sergunb 0:8918a71cdbe9 2442 if(!context->timeoutEventDone)
Sergunb 0:8918a71cdbe9 2443 {
Sergunb 0:8918a71cdbe9 2444 //Release exclusive access
Sergunb 0:8918a71cdbe9 2445 osReleaseMutex(&netMutex);
Sergunb 0:8918a71cdbe9 2446 //Invoke user callback function
Sergunb 0:8918a71cdbe9 2447 context->settings.timeoutEvent(context, interface);
Sergunb 0:8918a71cdbe9 2448 //Get exclusive access
Sergunb 0:8918a71cdbe9 2449 osAcquireMutex(&netMutex);
Sergunb 0:8918a71cdbe9 2450
Sergunb 0:8918a71cdbe9 2451 //Set flag
Sergunb 0:8918a71cdbe9 2452 context->timeoutEventDone = TRUE;
Sergunb 0:8918a71cdbe9 2453 }
Sergunb 0:8918a71cdbe9 2454 }
Sergunb 0:8918a71cdbe9 2455 }
Sergunb 0:8918a71cdbe9 2456 }
Sergunb 0:8918a71cdbe9 2457
Sergunb 0:8918a71cdbe9 2458
Sergunb 0:8918a71cdbe9 2459 /**
Sergunb 0:8918a71cdbe9 2460 * @brief Compute the time elapsed since the client sent the first message
Sergunb 0:8918a71cdbe9 2461 * @param[in] context Pointer to the DHCPv6 client context
Sergunb 0:8918a71cdbe9 2462 * @return The elapsed time expressed in hundredths of a second
Sergunb 0:8918a71cdbe9 2463 **/
Sergunb 0:8918a71cdbe9 2464
Sergunb 0:8918a71cdbe9 2465 uint16_t dhcpv6ClientComputeElapsedTime(Dhcpv6ClientContext *context)
Sergunb 0:8918a71cdbe9 2466 {
Sergunb 0:8918a71cdbe9 2467 systime_t time;
Sergunb 0:8918a71cdbe9 2468
Sergunb 0:8918a71cdbe9 2469 //Check retransmission counter
Sergunb 0:8918a71cdbe9 2470 if(context->retransmitCount == 0)
Sergunb 0:8918a71cdbe9 2471 {
Sergunb 0:8918a71cdbe9 2472 //The elapsed time must be 0 for the first message
Sergunb 0:8918a71cdbe9 2473 time = 0;
Sergunb 0:8918a71cdbe9 2474 }
Sergunb 0:8918a71cdbe9 2475 else
Sergunb 0:8918a71cdbe9 2476 {
Sergunb 0:8918a71cdbe9 2477 //Compute the time elapsed since the client sent the
Sergunb 0:8918a71cdbe9 2478 //first message (in hundredths of a second)
Sergunb 0:8918a71cdbe9 2479 time = (osGetSystemTime() - context->exchangeStartTime) / 10;
Sergunb 0:8918a71cdbe9 2480
Sergunb 0:8918a71cdbe9 2481 //The value 0xFFFF is used to represent any elapsed time values
Sergunb 0:8918a71cdbe9 2482 //greater than the largest time value that can be represented
Sergunb 0:8918a71cdbe9 2483 time = MIN(time, 0xFFFF);
Sergunb 0:8918a71cdbe9 2484 }
Sergunb 0:8918a71cdbe9 2485
Sergunb 0:8918a71cdbe9 2486 //Convert the 16-bit value to network byte order
Sergunb 0:8918a71cdbe9 2487 return htons(time);
Sergunb 0:8918a71cdbe9 2488 }
Sergunb 0:8918a71cdbe9 2489
Sergunb 0:8918a71cdbe9 2490
Sergunb 0:8918a71cdbe9 2491 /**
Sergunb 0:8918a71cdbe9 2492 * @brief Update DHCPv6 FSM state
Sergunb 0:8918a71cdbe9 2493 * @param[in] context Pointer to the DHCPv6 client context
Sergunb 0:8918a71cdbe9 2494 * @param[in] newState New DHCPv6 state to switch to
Sergunb 0:8918a71cdbe9 2495 * @param[in] delay Initial delay
Sergunb 0:8918a71cdbe9 2496 **/
Sergunb 0:8918a71cdbe9 2497
Sergunb 0:8918a71cdbe9 2498 void dhcpv6ClientChangeState(Dhcpv6ClientContext *context,
Sergunb 0:8918a71cdbe9 2499 Dhcpv6State newState, systime_t delay)
Sergunb 0:8918a71cdbe9 2500 {
Sergunb 0:8918a71cdbe9 2501 systime_t time;
Sergunb 0:8918a71cdbe9 2502
Sergunb 0:8918a71cdbe9 2503 //Get current time
Sergunb 0:8918a71cdbe9 2504 time = osGetSystemTime();
Sergunb 0:8918a71cdbe9 2505
Sergunb 0:8918a71cdbe9 2506 #if (DHCPV6_TRACE_LEVEL >= TRACE_LEVEL_INFO)
Sergunb 0:8918a71cdbe9 2507 //Sanity check
Sergunb 0:8918a71cdbe9 2508 if(newState <= DHCPV6_STATE_DECLINE)
Sergunb 0:8918a71cdbe9 2509 {
Sergunb 0:8918a71cdbe9 2510 //DHCPv6 FSM states
Sergunb 0:8918a71cdbe9 2511 static const char_t *stateLabel[] =
Sergunb 0:8918a71cdbe9 2512 {
Sergunb 0:8918a71cdbe9 2513 "INIT",
Sergunb 0:8918a71cdbe9 2514 "SOLICIT",
Sergunb 0:8918a71cdbe9 2515 "REQUEST",
Sergunb 0:8918a71cdbe9 2516 "INIT-CONFIRM",
Sergunb 0:8918a71cdbe9 2517 "CONFIRM",
Sergunb 0:8918a71cdbe9 2518 "DAD",
Sergunb 0:8918a71cdbe9 2519 "BOUND",
Sergunb 0:8918a71cdbe9 2520 "RENEW",
Sergunb 0:8918a71cdbe9 2521 "REBIND",
Sergunb 0:8918a71cdbe9 2522 "RELEASE",
Sergunb 0:8918a71cdbe9 2523 "DECLINE"
Sergunb 0:8918a71cdbe9 2524 };
Sergunb 0:8918a71cdbe9 2525
Sergunb 0:8918a71cdbe9 2526 //Debug message
Sergunb 0:8918a71cdbe9 2527 TRACE_INFO("%s: DHCPv6 client %s state\r\n",
Sergunb 0:8918a71cdbe9 2528 formatSystemTime(time, NULL), stateLabel[newState]);
Sergunb 0:8918a71cdbe9 2529 }
Sergunb 0:8918a71cdbe9 2530 #endif
Sergunb 0:8918a71cdbe9 2531
Sergunb 0:8918a71cdbe9 2532 //Set time stamp
Sergunb 0:8918a71cdbe9 2533 context->timestamp = time;
Sergunb 0:8918a71cdbe9 2534 //Set initial delay
Sergunb 0:8918a71cdbe9 2535 context->timeout = delay;
Sergunb 0:8918a71cdbe9 2536 //Reset retransmission counter
Sergunb 0:8918a71cdbe9 2537 context->retransmitCount = 0;
Sergunb 0:8918a71cdbe9 2538 //Switch to the new state
Sergunb 0:8918a71cdbe9 2539 context->state = newState;
Sergunb 0:8918a71cdbe9 2540
Sergunb 0:8918a71cdbe9 2541 //Any registered callback?
Sergunb 0:8918a71cdbe9 2542 if(context->settings.stateChangeEvent != NULL)
Sergunb 0:8918a71cdbe9 2543 {
Sergunb 0:8918a71cdbe9 2544 NetInterface *interface;
Sergunb 0:8918a71cdbe9 2545
Sergunb 0:8918a71cdbe9 2546 //Point to the underlying network interface
Sergunb 0:8918a71cdbe9 2547 interface = context->settings.interface;
Sergunb 0:8918a71cdbe9 2548
Sergunb 0:8918a71cdbe9 2549 //Release exclusive access
Sergunb 0:8918a71cdbe9 2550 osReleaseMutex(&netMutex);
Sergunb 0:8918a71cdbe9 2551 //Invoke user callback function
Sergunb 0:8918a71cdbe9 2552 context->settings.stateChangeEvent(context, interface, newState);
Sergunb 0:8918a71cdbe9 2553 //Get exclusive access
Sergunb 0:8918a71cdbe9 2554 osAcquireMutex(&netMutex);
Sergunb 0:8918a71cdbe9 2555 }
Sergunb 0:8918a71cdbe9 2556 }
Sergunb 0:8918a71cdbe9 2557
Sergunb 0:8918a71cdbe9 2558
Sergunb 0:8918a71cdbe9 2559 /**
Sergunb 0:8918a71cdbe9 2560 * @brief Dump DHCPv6 configuration for debugging purpose
Sergunb 0:8918a71cdbe9 2561 * @param[in] context Pointer to the DHCPv6 client context
Sergunb 0:8918a71cdbe9 2562 **/
Sergunb 0:8918a71cdbe9 2563
Sergunb 0:8918a71cdbe9 2564 void dhcpv6ClientDumpConfig(Dhcpv6ClientContext *context)
Sergunb 0:8918a71cdbe9 2565 {
Sergunb 0:8918a71cdbe9 2566 #if (DHCPV6_TRACE_LEVEL >= TRACE_LEVEL_INFO)
Sergunb 0:8918a71cdbe9 2567 uint_t i;
Sergunb 0:8918a71cdbe9 2568 NetInterface *interface;
Sergunb 0:8918a71cdbe9 2569 Ipv6Context *ipv6Context;
Sergunb 0:8918a71cdbe9 2570
Sergunb 0:8918a71cdbe9 2571 //Point to the underlying network interface
Sergunb 0:8918a71cdbe9 2572 interface = context->settings.interface;
Sergunb 0:8918a71cdbe9 2573 //Point to the IPv6 context
Sergunb 0:8918a71cdbe9 2574 ipv6Context = &interface->ipv6Context;
Sergunb 0:8918a71cdbe9 2575
Sergunb 0:8918a71cdbe9 2576 //Debug message
Sergunb 0:8918a71cdbe9 2577 TRACE_INFO("\r\n");
Sergunb 0:8918a71cdbe9 2578 TRACE_INFO("DHCPv6 configuration:\r\n");
Sergunb 0:8918a71cdbe9 2579
Sergunb 0:8918a71cdbe9 2580 //Lease start time
Sergunb 0:8918a71cdbe9 2581 TRACE_INFO(" Lease Start Time = %s\r\n",
Sergunb 0:8918a71cdbe9 2582 formatSystemTime(context->leaseStartTime, NULL));
Sergunb 0:8918a71cdbe9 2583
Sergunb 0:8918a71cdbe9 2584 //T1 parameter
Sergunb 0:8918a71cdbe9 2585 TRACE_INFO(" T1 = %" PRIu32 "s\r\n", context->ia.t1);
Sergunb 0:8918a71cdbe9 2586 //T2 parameter
Sergunb 0:8918a71cdbe9 2587 TRACE_INFO(" T2 = %" PRIu32 "s\r\n", context->ia.t2);
Sergunb 0:8918a71cdbe9 2588
Sergunb 0:8918a71cdbe9 2589 //Global addresses
Sergunb 0:8918a71cdbe9 2590 for(i = 1; i < IPV6_ADDR_LIST_SIZE; i++)
Sergunb 0:8918a71cdbe9 2591 {
Sergunb 0:8918a71cdbe9 2592 TRACE_INFO(" Global Address %u = %s\r\n", i,
Sergunb 0:8918a71cdbe9 2593 ipv6AddrToString(&ipv6Context->addrList[i].addr, NULL));
Sergunb 0:8918a71cdbe9 2594 }
Sergunb 0:8918a71cdbe9 2595
Sergunb 0:8918a71cdbe9 2596 //DNS servers
Sergunb 0:8918a71cdbe9 2597 for(i = 0; i < IPV6_DNS_SERVER_LIST_SIZE; i++)
Sergunb 0:8918a71cdbe9 2598 {
Sergunb 0:8918a71cdbe9 2599 TRACE_INFO(" DNS Server %u = %s\r\n", i + 1,
Sergunb 0:8918a71cdbe9 2600 ipv6AddrToString(&ipv6Context->dnsServerList[i], NULL));
Sergunb 0:8918a71cdbe9 2601 }
Sergunb 0:8918a71cdbe9 2602
Sergunb 0:8918a71cdbe9 2603 //Debug message
Sergunb 0:8918a71cdbe9 2604 TRACE_INFO("\r\n");
Sergunb 0:8918a71cdbe9 2605 #endif
Sergunb 0:8918a71cdbe9 2606 }
Sergunb 0:8918a71cdbe9 2607
Sergunb 0:8918a71cdbe9 2608 #endif
Sergunb 0:8918a71cdbe9 2609