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 dhcp_client.c
Sergunb 0:8918a71cdbe9 3 * @brief DHCP client (Dynamic Host Configuration Protocol)
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 is used to provide configuration
Sergunb 0:8918a71cdbe9 28 * parameters to hosts. Refer to the following RFCs for complete details:
Sergunb 0:8918a71cdbe9 29 * - RFC 2131: Dynamic Host Configuration Protocol
Sergunb 0:8918a71cdbe9 30 * - RFC 2132: DHCP Options and BOOTP Vendor Extensions
Sergunb 0:8918a71cdbe9 31 * - RFC 4039: Rapid Commit Option for the DHCP version 4
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 DHCP_TRACE_LEVEL
Sergunb 0:8918a71cdbe9 39
Sergunb 0:8918a71cdbe9 40 //Dependencies
Sergunb 0:8918a71cdbe9 41 #include "core/net.h"
Sergunb 0:8918a71cdbe9 42 #include "dhcp/dhcp_client.h"
Sergunb 0:8918a71cdbe9 43 #include "dhcp/dhcp_common.h"
Sergunb 0:8918a71cdbe9 44 #include "dhcp/dhcp_debug.h"
Sergunb 0:8918a71cdbe9 45 #include "mdns/mdns_responder.h"
Sergunb 0:8918a71cdbe9 46 #include "date_time.h"
Sergunb 0:8918a71cdbe9 47 #include "debug.h"
Sergunb 0:8918a71cdbe9 48
Sergunb 0:8918a71cdbe9 49 //Check TCP/IP stack configuration
Sergunb 0:8918a71cdbe9 50 #if (IPV4_SUPPORT == ENABLED && DHCP_CLIENT_SUPPORT == ENABLED)
Sergunb 0:8918a71cdbe9 51
Sergunb 0:8918a71cdbe9 52 //Tick counter to handle periodic operations
Sergunb 0:8918a71cdbe9 53 systime_t dhcpClientTickCounter;
Sergunb 0:8918a71cdbe9 54
Sergunb 0:8918a71cdbe9 55 //Requested DHCP options
Sergunb 0:8918a71cdbe9 56 const uint8_t dhcpOptionList[] =
Sergunb 0:8918a71cdbe9 57 {
Sergunb 0:8918a71cdbe9 58 DHCP_OPT_SUBNET_MASK,
Sergunb 0:8918a71cdbe9 59 DHCP_OPT_ROUTER,
Sergunb 0:8918a71cdbe9 60 DHCP_OPT_DNS_SERVER,
Sergunb 0:8918a71cdbe9 61 DHCP_OPT_INTERFACE_MTU,
Sergunb 0:8918a71cdbe9 62 DHCP_OPT_IP_ADDRESS_LEASE_TIME,
Sergunb 0:8918a71cdbe9 63 DHCP_OPT_RENEWAL_TIME_VALUE,
Sergunb 0:8918a71cdbe9 64 DHCP_OPT_REBINDING_TIME_VALUE
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 DHCP client settings
Sergunb 0:8918a71cdbe9 71 **/
Sergunb 0:8918a71cdbe9 72
Sergunb 0:8918a71cdbe9 73 void dhcpClientGetDefaultSettings(DhcpClientSettings *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 //Use default host name
Sergunb 0:8918a71cdbe9 79 strcpy(settings->hostname, "");
Sergunb 0:8918a71cdbe9 80
Sergunb 0:8918a71cdbe9 81 //Support for quick configuration using rapid commit
Sergunb 0:8918a71cdbe9 82 settings->rapidCommit = FALSE;
Sergunb 0:8918a71cdbe9 83 //Use the DNS servers provided by the DHCP server
Sergunb 0:8918a71cdbe9 84 settings->manualDnsConfig = FALSE;
Sergunb 0:8918a71cdbe9 85 //DHCP configuration timeout
Sergunb 0:8918a71cdbe9 86 settings->timeout = 0;
Sergunb 0:8918a71cdbe9 87 //DHCP configuration timeout event
Sergunb 0:8918a71cdbe9 88 settings->timeoutEvent = NULL;
Sergunb 0:8918a71cdbe9 89 //Link state change event
Sergunb 0:8918a71cdbe9 90 settings->linkChangeEvent = NULL;
Sergunb 0:8918a71cdbe9 91 //FSM state change event
Sergunb 0:8918a71cdbe9 92 settings->stateChangeEvent = NULL;
Sergunb 0:8918a71cdbe9 93 }
Sergunb 0:8918a71cdbe9 94
Sergunb 0:8918a71cdbe9 95
Sergunb 0:8918a71cdbe9 96 /**
Sergunb 0:8918a71cdbe9 97 * @brief DHCP client initialization
Sergunb 0:8918a71cdbe9 98 * @param[in] context Pointer to the DHCP client context
Sergunb 0:8918a71cdbe9 99 * @param[in] settings DHCP client specific settings
Sergunb 0:8918a71cdbe9 100 * @return Error code
Sergunb 0:8918a71cdbe9 101 **/
Sergunb 0:8918a71cdbe9 102
Sergunb 0:8918a71cdbe9 103 error_t dhcpClientInit(DhcpClientContext *context, const DhcpClientSettings *settings)
Sergunb 0:8918a71cdbe9 104 {
Sergunb 0:8918a71cdbe9 105 error_t error;
Sergunb 0:8918a71cdbe9 106 size_t n;
Sergunb 0:8918a71cdbe9 107 NetInterface *interface;
Sergunb 0:8918a71cdbe9 108
Sergunb 0:8918a71cdbe9 109 //Debug message
Sergunb 0:8918a71cdbe9 110 TRACE_INFO("Initializing DHCP client...\r\n");
Sergunb 0:8918a71cdbe9 111
Sergunb 0:8918a71cdbe9 112 //Ensure the parameters are valid
Sergunb 0:8918a71cdbe9 113 if(context == NULL || settings == NULL)
Sergunb 0:8918a71cdbe9 114 return ERROR_INVALID_PARAMETER;
Sergunb 0:8918a71cdbe9 115
Sergunb 0:8918a71cdbe9 116 //A valid pointer to the interface being configured is required
Sergunb 0:8918a71cdbe9 117 if(settings->interface == NULL)
Sergunb 0:8918a71cdbe9 118 return ERROR_INVALID_PARAMETER;
Sergunb 0:8918a71cdbe9 119
Sergunb 0:8918a71cdbe9 120 //Point to the underlying network interface
Sergunb 0:8918a71cdbe9 121 interface = settings->interface;
Sergunb 0:8918a71cdbe9 122
Sergunb 0:8918a71cdbe9 123 //Clear the DHCP client context
Sergunb 0:8918a71cdbe9 124 memset(context, 0, sizeof(DhcpClientContext));
Sergunb 0:8918a71cdbe9 125 //Save user settings
Sergunb 0:8918a71cdbe9 126 context->settings = *settings;
Sergunb 0:8918a71cdbe9 127
Sergunb 0:8918a71cdbe9 128 //No DHCP host name defined?
Sergunb 0:8918a71cdbe9 129 if(settings->hostname[0] == '\0')
Sergunb 0:8918a71cdbe9 130 {
Sergunb 0:8918a71cdbe9 131 //Use default host name
Sergunb 0:8918a71cdbe9 132 n = strlen(interface->hostname);
Sergunb 0:8918a71cdbe9 133 //Limit the length of the string
Sergunb 0:8918a71cdbe9 134 n = MIN(n, DHCP_CLIENT_MAX_HOSTNAME_LEN);
Sergunb 0:8918a71cdbe9 135
Sergunb 0:8918a71cdbe9 136 //Copy host name
Sergunb 0:8918a71cdbe9 137 strncpy(context->settings.hostname, interface->hostname, n);
Sergunb 0:8918a71cdbe9 138 //Properly terminate the string with a NULL character
Sergunb 0:8918a71cdbe9 139 context->settings.hostname[n] = '\0';
Sergunb 0:8918a71cdbe9 140 }
Sergunb 0:8918a71cdbe9 141
Sergunb 0:8918a71cdbe9 142 //Callback function to be called when a DHCP message is received
Sergunb 0:8918a71cdbe9 143 error = udpAttachRxCallback(interface, DHCP_CLIENT_PORT,
Sergunb 0:8918a71cdbe9 144 dhcpClientProcessMessage, context);
Sergunb 0:8918a71cdbe9 145 //Failed to register callback function?
Sergunb 0:8918a71cdbe9 146 if(error)
Sergunb 0:8918a71cdbe9 147 return error;
Sergunb 0:8918a71cdbe9 148
Sergunb 0:8918a71cdbe9 149 //DHCP client is currently suspended
Sergunb 0:8918a71cdbe9 150 context->running = FALSE;
Sergunb 0:8918a71cdbe9 151 //Initialize state machine
Sergunb 0:8918a71cdbe9 152 context->state = DHCP_STATE_INIT;
Sergunb 0:8918a71cdbe9 153
Sergunb 0:8918a71cdbe9 154 //Attach the DHCP client context to the network interface
Sergunb 0:8918a71cdbe9 155 interface->dhcpClientContext = context;
Sergunb 0:8918a71cdbe9 156
Sergunb 0:8918a71cdbe9 157 //Successful initialization
Sergunb 0:8918a71cdbe9 158 return NO_ERROR;
Sergunb 0:8918a71cdbe9 159 }
Sergunb 0:8918a71cdbe9 160
Sergunb 0:8918a71cdbe9 161
Sergunb 0:8918a71cdbe9 162 /**
Sergunb 0:8918a71cdbe9 163 * @brief Start DHCP client
Sergunb 0:8918a71cdbe9 164 * @param[in] context Pointer to the DHCP client context
Sergunb 0:8918a71cdbe9 165 * @return Error code
Sergunb 0:8918a71cdbe9 166 **/
Sergunb 0:8918a71cdbe9 167
Sergunb 0:8918a71cdbe9 168 error_t dhcpClientStart(DhcpClientContext *context)
Sergunb 0:8918a71cdbe9 169 {
Sergunb 0:8918a71cdbe9 170 //Check parameter
Sergunb 0:8918a71cdbe9 171 if(context == NULL)
Sergunb 0:8918a71cdbe9 172 return ERROR_INVALID_PARAMETER;
Sergunb 0:8918a71cdbe9 173
Sergunb 0:8918a71cdbe9 174 //Debug message
Sergunb 0:8918a71cdbe9 175 TRACE_INFO("Starting DHCP client...\r\n");
Sergunb 0:8918a71cdbe9 176
Sergunb 0:8918a71cdbe9 177 //Get exclusive access
Sergunb 0:8918a71cdbe9 178 osAcquireMutex(&netMutex);
Sergunb 0:8918a71cdbe9 179
Sergunb 0:8918a71cdbe9 180 //Start DHCP client
Sergunb 0:8918a71cdbe9 181 context->running = TRUE;
Sergunb 0:8918a71cdbe9 182 //Initialize state machine
Sergunb 0:8918a71cdbe9 183 context->state = DHCP_STATE_INIT;
Sergunb 0:8918a71cdbe9 184
Sergunb 0:8918a71cdbe9 185 //Release exclusive access
Sergunb 0:8918a71cdbe9 186 osReleaseMutex(&netMutex);
Sergunb 0:8918a71cdbe9 187
Sergunb 0:8918a71cdbe9 188 //Successful processing
Sergunb 0:8918a71cdbe9 189 return NO_ERROR;
Sergunb 0:8918a71cdbe9 190 }
Sergunb 0:8918a71cdbe9 191
Sergunb 0:8918a71cdbe9 192
Sergunb 0:8918a71cdbe9 193 /**
Sergunb 0:8918a71cdbe9 194 * @brief Stop DHCP client
Sergunb 0:8918a71cdbe9 195 * @param[in] context Pointer to the DHCP client context
Sergunb 0:8918a71cdbe9 196 * @return Error code
Sergunb 0:8918a71cdbe9 197 **/
Sergunb 0:8918a71cdbe9 198
Sergunb 0:8918a71cdbe9 199 error_t dhcpClientStop(DhcpClientContext *context)
Sergunb 0:8918a71cdbe9 200 {
Sergunb 0:8918a71cdbe9 201 //Check parameter
Sergunb 0:8918a71cdbe9 202 if(context == NULL)
Sergunb 0:8918a71cdbe9 203 return ERROR_INVALID_PARAMETER;
Sergunb 0:8918a71cdbe9 204
Sergunb 0:8918a71cdbe9 205 //Debug message
Sergunb 0:8918a71cdbe9 206 TRACE_INFO("Stopping DHCP client...\r\n");
Sergunb 0:8918a71cdbe9 207
Sergunb 0:8918a71cdbe9 208 //Get exclusive access
Sergunb 0:8918a71cdbe9 209 osAcquireMutex(&netMutex);
Sergunb 0:8918a71cdbe9 210
Sergunb 0:8918a71cdbe9 211 //Stop DHCP client
Sergunb 0:8918a71cdbe9 212 context->running = FALSE;
Sergunb 0:8918a71cdbe9 213 //Reinitialize state machine
Sergunb 0:8918a71cdbe9 214 context->state = DHCP_STATE_INIT;
Sergunb 0:8918a71cdbe9 215
Sergunb 0:8918a71cdbe9 216 //Release exclusive access
Sergunb 0:8918a71cdbe9 217 osReleaseMutex(&netMutex);
Sergunb 0:8918a71cdbe9 218
Sergunb 0:8918a71cdbe9 219 //Successful processing
Sergunb 0:8918a71cdbe9 220 return NO_ERROR;
Sergunb 0:8918a71cdbe9 221 }
Sergunb 0:8918a71cdbe9 222
Sergunb 0:8918a71cdbe9 223
Sergunb 0:8918a71cdbe9 224 /**
Sergunb 0:8918a71cdbe9 225 * @brief Retrieve current state
Sergunb 0:8918a71cdbe9 226 * @param[in] context Pointer to the DHCP client context
Sergunb 0:8918a71cdbe9 227 * @return Current DHCP client state
Sergunb 0:8918a71cdbe9 228 **/
Sergunb 0:8918a71cdbe9 229
Sergunb 0:8918a71cdbe9 230 DhcpState dhcpClientGetState(DhcpClientContext *context)
Sergunb 0:8918a71cdbe9 231 {
Sergunb 0:8918a71cdbe9 232 DhcpState state;
Sergunb 0:8918a71cdbe9 233
Sergunb 0:8918a71cdbe9 234 //Get exclusive access
Sergunb 0:8918a71cdbe9 235 osAcquireMutex(&netMutex);
Sergunb 0:8918a71cdbe9 236 //Get current state
Sergunb 0:8918a71cdbe9 237 state = context->state;
Sergunb 0:8918a71cdbe9 238 //Release exclusive access
Sergunb 0:8918a71cdbe9 239 osReleaseMutex(&netMutex);
Sergunb 0:8918a71cdbe9 240
Sergunb 0:8918a71cdbe9 241 //Return current state
Sergunb 0:8918a71cdbe9 242 return state;
Sergunb 0:8918a71cdbe9 243 }
Sergunb 0:8918a71cdbe9 244
Sergunb 0:8918a71cdbe9 245
Sergunb 0:8918a71cdbe9 246 /**
Sergunb 0:8918a71cdbe9 247 * @brief DHCP client timer handler
Sergunb 0:8918a71cdbe9 248 *
Sergunb 0:8918a71cdbe9 249 * This routine must be periodically called by the TCP/IP stack to
Sergunb 0:8918a71cdbe9 250 * manage DHCP client operation
Sergunb 0:8918a71cdbe9 251 *
Sergunb 0:8918a71cdbe9 252 * @param[in] context Pointer to the DHCP client context
Sergunb 0:8918a71cdbe9 253 **/
Sergunb 0:8918a71cdbe9 254
Sergunb 0:8918a71cdbe9 255
Sergunb 0:8918a71cdbe9 256 void dhcpClientTick(DhcpClientContext *context)
Sergunb 0:8918a71cdbe9 257 {
Sergunb 0:8918a71cdbe9 258 //Make sure the DHCP client has been properly instantiated
Sergunb 0:8918a71cdbe9 259 if(context == NULL)
Sergunb 0:8918a71cdbe9 260 return;
Sergunb 0:8918a71cdbe9 261
Sergunb 0:8918a71cdbe9 262 //DHCP client finite state machine
Sergunb 0:8918a71cdbe9 263 switch(context->state)
Sergunb 0:8918a71cdbe9 264 {
Sergunb 0:8918a71cdbe9 265 //Process INIT state
Sergunb 0:8918a71cdbe9 266 case DHCP_STATE_INIT:
Sergunb 0:8918a71cdbe9 267 //This is the initialization state, where a client begins the process of
Sergunb 0:8918a71cdbe9 268 //acquiring a lease. It also returns here when a lease ends, or when a
Sergunb 0:8918a71cdbe9 269 //lease negotiation fails
Sergunb 0:8918a71cdbe9 270 dhcpClientStateInit(context);
Sergunb 0:8918a71cdbe9 271 break;
Sergunb 0:8918a71cdbe9 272 //Process SELECTING state
Sergunb 0:8918a71cdbe9 273 case DHCP_STATE_SELECTING:
Sergunb 0:8918a71cdbe9 274 //The client is waiting to receive DHCPOFFER messages from one or more
Sergunb 0:8918a71cdbe9 275 //DHCP servers, so it can choose one
Sergunb 0:8918a71cdbe9 276 dhcpClientStateSelecting(context);
Sergunb 0:8918a71cdbe9 277 break;
Sergunb 0:8918a71cdbe9 278 //Process REQUESTING state
Sergunb 0:8918a71cdbe9 279 case DHCP_STATE_REQUESTING:
Sergunb 0:8918a71cdbe9 280 //The client is waiting to hear back from the server to which
Sergunb 0:8918a71cdbe9 281 //it sent its request
Sergunb 0:8918a71cdbe9 282 dhcpClientStateRequesting(context);
Sergunb 0:8918a71cdbe9 283 break;
Sergunb 0:8918a71cdbe9 284 //Process INIT REBOOT state
Sergunb 0:8918a71cdbe9 285 case DHCP_STATE_INIT_REBOOT:
Sergunb 0:8918a71cdbe9 286 //When a client that already has a valid lease starts up after a
Sergunb 0:8918a71cdbe9 287 //power-down or reboot, it starts here instead of the INIT state
Sergunb 0:8918a71cdbe9 288 dhcpClientStateInitReboot(context);
Sergunb 0:8918a71cdbe9 289 break;
Sergunb 0:8918a71cdbe9 290 //Process REBOOTING state
Sergunb 0:8918a71cdbe9 291 case DHCP_STATE_REBOOTING:
Sergunb 0:8918a71cdbe9 292 //A client that has rebooted with an assigned address is waiting for
Sergunb 0:8918a71cdbe9 293 //a confirming reply from a server
Sergunb 0:8918a71cdbe9 294 dhcpClientStateRebooting(context);
Sergunb 0:8918a71cdbe9 295 break;
Sergunb 0:8918a71cdbe9 296 //Process PROBING state
Sergunb 0:8918a71cdbe9 297 case DHCP_STATE_PROBING:
Sergunb 0:8918a71cdbe9 298 //The client probes the newly received address
Sergunb 0:8918a71cdbe9 299 dhcpClientStateProbing(context);
Sergunb 0:8918a71cdbe9 300 break;
Sergunb 0:8918a71cdbe9 301 //Process BOUND state
Sergunb 0:8918a71cdbe9 302 case DHCP_STATE_BOUND:
Sergunb 0:8918a71cdbe9 303 //Client has a valid lease and is in its normal operating state
Sergunb 0:8918a71cdbe9 304 dhcpClientStateBound(context);
Sergunb 0:8918a71cdbe9 305 break;
Sergunb 0:8918a71cdbe9 306 //Process RENEWING state
Sergunb 0:8918a71cdbe9 307 case DHCP_STATE_RENEWING:
Sergunb 0:8918a71cdbe9 308 //Client is trying to renew its lease. It regularly sends DHCPREQUEST messages with
Sergunb 0:8918a71cdbe9 309 //the server that gave it its current lease specified, and waits for a reply
Sergunb 0:8918a71cdbe9 310 dhcpClientStateRenewing(context);
Sergunb 0:8918a71cdbe9 311 break;
Sergunb 0:8918a71cdbe9 312 //Process REBINDING state
Sergunb 0:8918a71cdbe9 313 case DHCP_STATE_REBINDING:
Sergunb 0:8918a71cdbe9 314 //The client has failed to renew its lease with the server that originally granted it,
Sergunb 0:8918a71cdbe9 315 //and now seeks a lease extension with any server that can hear it. It periodically sends
Sergunb 0:8918a71cdbe9 316 //DHCPREQUEST messages with no server specified until it gets a reply or the lease ends
Sergunb 0:8918a71cdbe9 317 dhcpClientStateRebinding(context);
Sergunb 0:8918a71cdbe9 318 break;
Sergunb 0:8918a71cdbe9 319 //Invalid state...
Sergunb 0:8918a71cdbe9 320 default:
Sergunb 0:8918a71cdbe9 321 //Switch to the INIT state
Sergunb 0:8918a71cdbe9 322 context->state = DHCP_STATE_INIT;
Sergunb 0:8918a71cdbe9 323 break;
Sergunb 0:8918a71cdbe9 324 }
Sergunb 0:8918a71cdbe9 325 }
Sergunb 0:8918a71cdbe9 326
Sergunb 0:8918a71cdbe9 327
Sergunb 0:8918a71cdbe9 328 /**
Sergunb 0:8918a71cdbe9 329 * @brief Callback function for link change event
Sergunb 0:8918a71cdbe9 330 * @param[in] context Pointer to the DHCP client context
Sergunb 0:8918a71cdbe9 331 **/
Sergunb 0:8918a71cdbe9 332
Sergunb 0:8918a71cdbe9 333 void dhcpClientLinkChangeEvent(DhcpClientContext *context)
Sergunb 0:8918a71cdbe9 334 {
Sergunb 0:8918a71cdbe9 335 NetInterface *interface;
Sergunb 0:8918a71cdbe9 336
Sergunb 0:8918a71cdbe9 337 //Make sure the DHCP client has been properly instantiated
Sergunb 0:8918a71cdbe9 338 if(context == NULL)
Sergunb 0:8918a71cdbe9 339 return;
Sergunb 0:8918a71cdbe9 340
Sergunb 0:8918a71cdbe9 341 //Point to the underlying network interface
Sergunb 0:8918a71cdbe9 342 interface = context->settings.interface;
Sergunb 0:8918a71cdbe9 343
Sergunb 0:8918a71cdbe9 344 //Check whether the DHCP client is running
Sergunb 0:8918a71cdbe9 345 if(context->running)
Sergunb 0:8918a71cdbe9 346 {
Sergunb 0:8918a71cdbe9 347 //The host address is no longer valid
Sergunb 0:8918a71cdbe9 348 interface->ipv4Context.addr = IPV4_UNSPECIFIED_ADDR;
Sergunb 0:8918a71cdbe9 349 interface->ipv4Context.addrState = IPV4_ADDR_STATE_INVALID;
Sergunb 0:8918a71cdbe9 350
Sergunb 0:8918a71cdbe9 351 #if (MDNS_RESPONDER_SUPPORT == ENABLED)
Sergunb 0:8918a71cdbe9 352 //Restart mDNS probing process
Sergunb 0:8918a71cdbe9 353 mdnsResponderStartProbing(interface->mdnsResponderContext);
Sergunb 0:8918a71cdbe9 354 #endif
Sergunb 0:8918a71cdbe9 355
Sergunb 0:8918a71cdbe9 356 //Clear subnet mask
Sergunb 0:8918a71cdbe9 357 interface->ipv4Context.subnetMask = IPV4_UNSPECIFIED_ADDR;
Sergunb 0:8918a71cdbe9 358 }
Sergunb 0:8918a71cdbe9 359
Sergunb 0:8918a71cdbe9 360 //Check whether the client already has a valid lease
Sergunb 0:8918a71cdbe9 361 if(context->state >= DHCP_STATE_INIT_REBOOT)
Sergunb 0:8918a71cdbe9 362 {
Sergunb 0:8918a71cdbe9 363 //Switch to the INIT-REBOOT state
Sergunb 0:8918a71cdbe9 364 context->state = DHCP_STATE_INIT_REBOOT;
Sergunb 0:8918a71cdbe9 365 }
Sergunb 0:8918a71cdbe9 366 else
Sergunb 0:8918a71cdbe9 367 {
Sergunb 0:8918a71cdbe9 368 //Switch to the INIT state
Sergunb 0:8918a71cdbe9 369 context->state = DHCP_STATE_INIT;
Sergunb 0:8918a71cdbe9 370 }
Sergunb 0:8918a71cdbe9 371
Sergunb 0:8918a71cdbe9 372 //Any registered callback?
Sergunb 0:8918a71cdbe9 373 if(context->settings.linkChangeEvent != NULL)
Sergunb 0:8918a71cdbe9 374 {
Sergunb 0:8918a71cdbe9 375 //Release exclusive access
Sergunb 0:8918a71cdbe9 376 osReleaseMutex(&netMutex);
Sergunb 0:8918a71cdbe9 377 //Invoke user callback function
Sergunb 0:8918a71cdbe9 378 context->settings.linkChangeEvent(context, interface, interface->linkState);
Sergunb 0:8918a71cdbe9 379 //Get exclusive access
Sergunb 0:8918a71cdbe9 380 osAcquireMutex(&netMutex);
Sergunb 0:8918a71cdbe9 381 }
Sergunb 0:8918a71cdbe9 382 }
Sergunb 0:8918a71cdbe9 383
Sergunb 0:8918a71cdbe9 384
Sergunb 0:8918a71cdbe9 385 /**
Sergunb 0:8918a71cdbe9 386 * @brief INIT state
Sergunb 0:8918a71cdbe9 387 *
Sergunb 0:8918a71cdbe9 388 * This is the initialization state, where a client begins the process of
Sergunb 0:8918a71cdbe9 389 * acquiring a lease. It also returns here when a lease ends, or when a
Sergunb 0:8918a71cdbe9 390 * lease negotiation fails
Sergunb 0:8918a71cdbe9 391 *
Sergunb 0:8918a71cdbe9 392 * @param[in] context Pointer to the DHCP client context
Sergunb 0:8918a71cdbe9 393 **/
Sergunb 0:8918a71cdbe9 394
Sergunb 0:8918a71cdbe9 395 void dhcpClientStateInit(DhcpClientContext *context)
Sergunb 0:8918a71cdbe9 396 {
Sergunb 0:8918a71cdbe9 397 systime_t delay;
Sergunb 0:8918a71cdbe9 398 NetInterface *interface;
Sergunb 0:8918a71cdbe9 399
Sergunb 0:8918a71cdbe9 400 //Point to the underlying network interface
Sergunb 0:8918a71cdbe9 401 interface = context->settings.interface;
Sergunb 0:8918a71cdbe9 402
Sergunb 0:8918a71cdbe9 403 //Check whether the DHCP client is running
Sergunb 0:8918a71cdbe9 404 if(context->running)
Sergunb 0:8918a71cdbe9 405 {
Sergunb 0:8918a71cdbe9 406 //Wait for the link to be up before starting DHCP configuration
Sergunb 0:8918a71cdbe9 407 if(interface->linkState)
Sergunb 0:8918a71cdbe9 408 {
Sergunb 0:8918a71cdbe9 409 //The client should wait for a random time to
Sergunb 0:8918a71cdbe9 410 //desynchronize the use of DHCP at startup
Sergunb 0:8918a71cdbe9 411 delay = netGetRandRange(0, DHCP_CLIENT_INIT_DELAY);
Sergunb 0:8918a71cdbe9 412
Sergunb 0:8918a71cdbe9 413 //Record the time at which the client started
Sergunb 0:8918a71cdbe9 414 //the address acquisition process
Sergunb 0:8918a71cdbe9 415 context->configStartTime = osGetSystemTime();
Sergunb 0:8918a71cdbe9 416 //Clear flag
Sergunb 0:8918a71cdbe9 417 context->timeoutEventDone = FALSE;
Sergunb 0:8918a71cdbe9 418
Sergunb 0:8918a71cdbe9 419 //Switch to the SELECTING state
Sergunb 0:8918a71cdbe9 420 dhcpClientChangeState(context, DHCP_STATE_SELECTING, delay);
Sergunb 0:8918a71cdbe9 421 }
Sergunb 0:8918a71cdbe9 422 }
Sergunb 0:8918a71cdbe9 423 }
Sergunb 0:8918a71cdbe9 424
Sergunb 0:8918a71cdbe9 425
Sergunb 0:8918a71cdbe9 426 /**
Sergunb 0:8918a71cdbe9 427 * @brief SELECTING state
Sergunb 0:8918a71cdbe9 428 *
Sergunb 0:8918a71cdbe9 429 * The client is waiting to receive DHCPOFFER messages from
Sergunb 0:8918a71cdbe9 430 * one or more DHCP servers, so it can choose one
Sergunb 0:8918a71cdbe9 431 *
Sergunb 0:8918a71cdbe9 432 * @param[in] context Pointer to the DHCP client context
Sergunb 0:8918a71cdbe9 433 **/
Sergunb 0:8918a71cdbe9 434
Sergunb 0:8918a71cdbe9 435 void dhcpClientStateSelecting(DhcpClientContext *context)
Sergunb 0:8918a71cdbe9 436 {
Sergunb 0:8918a71cdbe9 437 systime_t time;
Sergunb 0:8918a71cdbe9 438
Sergunb 0:8918a71cdbe9 439 //Get current time
Sergunb 0:8918a71cdbe9 440 time = osGetSystemTime();
Sergunb 0:8918a71cdbe9 441
Sergunb 0:8918a71cdbe9 442 //Check current time
Sergunb 0:8918a71cdbe9 443 if(timeCompare(time, context->timestamp + context->timeout) >= 0)
Sergunb 0:8918a71cdbe9 444 {
Sergunb 0:8918a71cdbe9 445 //Check retransmission counter
Sergunb 0:8918a71cdbe9 446 if(context->retransmitCount == 0)
Sergunb 0:8918a71cdbe9 447 {
Sergunb 0:8918a71cdbe9 448 //A transaction identifier is used by the client to
Sergunb 0:8918a71cdbe9 449 //match incoming DHCP messages with pending requests
Sergunb 0:8918a71cdbe9 450 context->transactionId = netGetRand();
Sergunb 0:8918a71cdbe9 451
Sergunb 0:8918a71cdbe9 452 //Send a DHCPDISCOVER message
Sergunb 0:8918a71cdbe9 453 dhcpClientSendDiscover(context);
Sergunb 0:8918a71cdbe9 454
Sergunb 0:8918a71cdbe9 455 //Initial timeout value
Sergunb 0:8918a71cdbe9 456 context->retransmitTimeout = DHCP_CLIENT_DISCOVER_INIT_RT;
Sergunb 0:8918a71cdbe9 457 }
Sergunb 0:8918a71cdbe9 458 else
Sergunb 0:8918a71cdbe9 459 {
Sergunb 0:8918a71cdbe9 460 //Send a DHCPDISCOVER message
Sergunb 0:8918a71cdbe9 461 dhcpClientSendDiscover(context);
Sergunb 0:8918a71cdbe9 462
Sergunb 0:8918a71cdbe9 463 //The timeout value is doubled for each subsequent retransmission
Sergunb 0:8918a71cdbe9 464 context->retransmitTimeout *= 2;
Sergunb 0:8918a71cdbe9 465
Sergunb 0:8918a71cdbe9 466 //Limit the timeout value to a maximum of 64 seconds
Sergunb 0:8918a71cdbe9 467 if(context->retransmitTimeout > DHCP_CLIENT_DISCOVER_MAX_RT)
Sergunb 0:8918a71cdbe9 468 context->retransmitTimeout = DHCP_CLIENT_DISCOVER_MAX_RT;
Sergunb 0:8918a71cdbe9 469 }
Sergunb 0:8918a71cdbe9 470
Sergunb 0:8918a71cdbe9 471 //Save the time at which the message was sent
Sergunb 0:8918a71cdbe9 472 context->timestamp = time;
Sergunb 0:8918a71cdbe9 473
Sergunb 0:8918a71cdbe9 474 //The timeout value should be randomized by the value of a uniform
Sergunb 0:8918a71cdbe9 475 //number chosen from the range -1 to +1
Sergunb 0:8918a71cdbe9 476 context->timeout = context->retransmitTimeout +
Sergunb 0:8918a71cdbe9 477 netGetRandRange(-DHCP_CLIENT_RAND_FACTOR, DHCP_CLIENT_RAND_FACTOR);
Sergunb 0:8918a71cdbe9 478
Sergunb 0:8918a71cdbe9 479 //Increment retransmission counter
Sergunb 0:8918a71cdbe9 480 context->retransmitCount++;
Sergunb 0:8918a71cdbe9 481 }
Sergunb 0:8918a71cdbe9 482
Sergunb 0:8918a71cdbe9 483 //Manage DHCP configuration timeout
Sergunb 0:8918a71cdbe9 484 dhcpClientCheckTimeout(context);
Sergunb 0:8918a71cdbe9 485 }
Sergunb 0:8918a71cdbe9 486
Sergunb 0:8918a71cdbe9 487
Sergunb 0:8918a71cdbe9 488 /**
Sergunb 0:8918a71cdbe9 489 * @brief REQUESTING state
Sergunb 0:8918a71cdbe9 490 *
Sergunb 0:8918a71cdbe9 491 * The client is waiting to hear back from the server
Sergunb 0:8918a71cdbe9 492 * to which it sent its request
Sergunb 0:8918a71cdbe9 493 *
Sergunb 0:8918a71cdbe9 494 * @param[in] context Pointer to the DHCP client context
Sergunb 0:8918a71cdbe9 495 **/
Sergunb 0:8918a71cdbe9 496
Sergunb 0:8918a71cdbe9 497 void dhcpClientStateRequesting(DhcpClientContext *context)
Sergunb 0:8918a71cdbe9 498 {
Sergunb 0:8918a71cdbe9 499 systime_t time;
Sergunb 0:8918a71cdbe9 500
Sergunb 0:8918a71cdbe9 501 //Get current time
Sergunb 0:8918a71cdbe9 502 time = osGetSystemTime();
Sergunb 0:8918a71cdbe9 503
Sergunb 0:8918a71cdbe9 504 //Check current time
Sergunb 0:8918a71cdbe9 505 if(timeCompare(time, context->timestamp + context->timeout) >= 0)
Sergunb 0:8918a71cdbe9 506 {
Sergunb 0:8918a71cdbe9 507 //Check retransmission counter
Sergunb 0:8918a71cdbe9 508 if(context->retransmitCount == 0)
Sergunb 0:8918a71cdbe9 509 {
Sergunb 0:8918a71cdbe9 510 //A transaction identifier is used by the client to
Sergunb 0:8918a71cdbe9 511 //match incoming DHCP messages with pending requests
Sergunb 0:8918a71cdbe9 512 context->transactionId = netGetRand();
Sergunb 0:8918a71cdbe9 513
Sergunb 0:8918a71cdbe9 514 //Send a DHCPREQUEST message
Sergunb 0:8918a71cdbe9 515 dhcpClientSendRequest(context);
Sergunb 0:8918a71cdbe9 516
Sergunb 0:8918a71cdbe9 517 //Initial timeout value
Sergunb 0:8918a71cdbe9 518 context->retransmitTimeout = DHCP_CLIENT_REQUEST_INIT_RT;
Sergunb 0:8918a71cdbe9 519
Sergunb 0:8918a71cdbe9 520 //Save the time at which the message was sent
Sergunb 0:8918a71cdbe9 521 context->timestamp = time;
Sergunb 0:8918a71cdbe9 522
Sergunb 0:8918a71cdbe9 523 //The timeout value should be randomized by the value of a uniform
Sergunb 0:8918a71cdbe9 524 //number chosen from the range -1 to +1
Sergunb 0:8918a71cdbe9 525 context->timeout = context->retransmitTimeout +
Sergunb 0:8918a71cdbe9 526 netGetRandRange(-DHCP_CLIENT_RAND_FACTOR, DHCP_CLIENT_RAND_FACTOR);
Sergunb 0:8918a71cdbe9 527
Sergunb 0:8918a71cdbe9 528 //Increment retransmission counter
Sergunb 0:8918a71cdbe9 529 context->retransmitCount++;
Sergunb 0:8918a71cdbe9 530 }
Sergunb 0:8918a71cdbe9 531 else if(context->retransmitCount < DHCP_CLIENT_REQUEST_MAX_RC)
Sergunb 0:8918a71cdbe9 532 {
Sergunb 0:8918a71cdbe9 533 //Send a DHCPREQUEST message
Sergunb 0:8918a71cdbe9 534 dhcpClientSendRequest(context);
Sergunb 0:8918a71cdbe9 535
Sergunb 0:8918a71cdbe9 536 //The timeout value is doubled for each subsequent retransmission
Sergunb 0:8918a71cdbe9 537 context->retransmitTimeout *= 2;
Sergunb 0:8918a71cdbe9 538
Sergunb 0:8918a71cdbe9 539 //Limit the timeout value to a maximum of 64 seconds
Sergunb 0:8918a71cdbe9 540 if(context->retransmitTimeout > DHCP_CLIENT_REQUEST_MAX_RT)
Sergunb 0:8918a71cdbe9 541 context->retransmitTimeout = DHCP_CLIENT_REQUEST_MAX_RT;
Sergunb 0:8918a71cdbe9 542
Sergunb 0:8918a71cdbe9 543 //Save the time at which the message was sent
Sergunb 0:8918a71cdbe9 544 context->timestamp = time;
Sergunb 0:8918a71cdbe9 545
Sergunb 0:8918a71cdbe9 546 //The timeout value should be randomized by the value of a uniform
Sergunb 0:8918a71cdbe9 547 //number chosen from the range -1 to +1
Sergunb 0:8918a71cdbe9 548 context->timeout = context->retransmitTimeout +
Sergunb 0:8918a71cdbe9 549 netGetRandRange(-DHCP_CLIENT_RAND_FACTOR, DHCP_CLIENT_RAND_FACTOR);
Sergunb 0:8918a71cdbe9 550
Sergunb 0:8918a71cdbe9 551 //Increment retransmission counter
Sergunb 0:8918a71cdbe9 552 context->retransmitCount++;
Sergunb 0:8918a71cdbe9 553 }
Sergunb 0:8918a71cdbe9 554 else
Sergunb 0:8918a71cdbe9 555 {
Sergunb 0:8918a71cdbe9 556 //If the client does not receive a response within a reasonable
Sergunb 0:8918a71cdbe9 557 //period of time, then it restarts the initialization procedure
Sergunb 0:8918a71cdbe9 558 dhcpClientChangeState(context, DHCP_STATE_INIT, 0);
Sergunb 0:8918a71cdbe9 559 }
Sergunb 0:8918a71cdbe9 560 }
Sergunb 0:8918a71cdbe9 561
Sergunb 0:8918a71cdbe9 562 //Manage DHCP configuration timeout
Sergunb 0:8918a71cdbe9 563 dhcpClientCheckTimeout(context);
Sergunb 0:8918a71cdbe9 564 }
Sergunb 0:8918a71cdbe9 565
Sergunb 0:8918a71cdbe9 566
Sergunb 0:8918a71cdbe9 567 /**
Sergunb 0:8918a71cdbe9 568 * @brief INIT-REBOOT state
Sergunb 0:8918a71cdbe9 569 *
Sergunb 0:8918a71cdbe9 570 * When a client that already has a valid lease starts up after a
Sergunb 0:8918a71cdbe9 571 * power-down or reboot, it starts here instead of the INIT state
Sergunb 0:8918a71cdbe9 572 *
Sergunb 0:8918a71cdbe9 573 * @param[in] context Pointer to the DHCP client context
Sergunb 0:8918a71cdbe9 574 **/
Sergunb 0:8918a71cdbe9 575
Sergunb 0:8918a71cdbe9 576 void dhcpClientStateInitReboot(DhcpClientContext *context)
Sergunb 0:8918a71cdbe9 577 {
Sergunb 0:8918a71cdbe9 578 systime_t delay;
Sergunb 0:8918a71cdbe9 579 NetInterface *interface;
Sergunb 0:8918a71cdbe9 580
Sergunb 0:8918a71cdbe9 581 //Point to the underlying network interface
Sergunb 0:8918a71cdbe9 582 interface = context->settings.interface;
Sergunb 0:8918a71cdbe9 583
Sergunb 0:8918a71cdbe9 584 //Check whether the DHCP client is running
Sergunb 0:8918a71cdbe9 585 if(context->running)
Sergunb 0:8918a71cdbe9 586 {
Sergunb 0:8918a71cdbe9 587 //Wait for the link to be up before starting DHCP configuration
Sergunb 0:8918a71cdbe9 588 if(interface->linkState)
Sergunb 0:8918a71cdbe9 589 {
Sergunb 0:8918a71cdbe9 590 //The client should wait for a random time to
Sergunb 0:8918a71cdbe9 591 //desynchronize the use of DHCP at startup
Sergunb 0:8918a71cdbe9 592 delay = netGetRandRange(0, DHCP_CLIENT_INIT_DELAY);
Sergunb 0:8918a71cdbe9 593
Sergunb 0:8918a71cdbe9 594 //Record the time at which the client started
Sergunb 0:8918a71cdbe9 595 //the address acquisition process
Sergunb 0:8918a71cdbe9 596 context->configStartTime = osGetSystemTime();
Sergunb 0:8918a71cdbe9 597 //Clear flag
Sergunb 0:8918a71cdbe9 598 context->timeoutEventDone = FALSE;
Sergunb 0:8918a71cdbe9 599
Sergunb 0:8918a71cdbe9 600 //Switch to the REBOOTING state
Sergunb 0:8918a71cdbe9 601 dhcpClientChangeState(context, DHCP_STATE_REBOOTING, delay);
Sergunb 0:8918a71cdbe9 602 }
Sergunb 0:8918a71cdbe9 603 }
Sergunb 0:8918a71cdbe9 604 }
Sergunb 0:8918a71cdbe9 605
Sergunb 0:8918a71cdbe9 606
Sergunb 0:8918a71cdbe9 607 /**
Sergunb 0:8918a71cdbe9 608 * @brief REBOOTING state
Sergunb 0:8918a71cdbe9 609 *
Sergunb 0:8918a71cdbe9 610 * A client that has rebooted with an assigned address is
Sergunb 0:8918a71cdbe9 611 * waiting for a confirming reply from a server
Sergunb 0:8918a71cdbe9 612 *
Sergunb 0:8918a71cdbe9 613 * @param[in] context Pointer to the DHCP client context
Sergunb 0:8918a71cdbe9 614 **/
Sergunb 0:8918a71cdbe9 615
Sergunb 0:8918a71cdbe9 616 void dhcpClientStateRebooting(DhcpClientContext *context)
Sergunb 0:8918a71cdbe9 617 {
Sergunb 0:8918a71cdbe9 618 systime_t time;
Sergunb 0:8918a71cdbe9 619
Sergunb 0:8918a71cdbe9 620 //Get current time
Sergunb 0:8918a71cdbe9 621 time = osGetSystemTime();
Sergunb 0:8918a71cdbe9 622
Sergunb 0:8918a71cdbe9 623 //Check current time
Sergunb 0:8918a71cdbe9 624 if(timeCompare(time, context->timestamp + context->timeout) >= 0)
Sergunb 0:8918a71cdbe9 625 {
Sergunb 0:8918a71cdbe9 626 //Check retransmission counter
Sergunb 0:8918a71cdbe9 627 if(context->retransmitCount == 0)
Sergunb 0:8918a71cdbe9 628 {
Sergunb 0:8918a71cdbe9 629 //A transaction identifier is used by the client to
Sergunb 0:8918a71cdbe9 630 //match incoming DHCP messages with pending requests
Sergunb 0:8918a71cdbe9 631 context->transactionId = netGetRand();
Sergunb 0:8918a71cdbe9 632
Sergunb 0:8918a71cdbe9 633 //Send a DHCPREQUEST message
Sergunb 0:8918a71cdbe9 634 dhcpClientSendRequest(context);
Sergunb 0:8918a71cdbe9 635
Sergunb 0:8918a71cdbe9 636 //Initial timeout value
Sergunb 0:8918a71cdbe9 637 context->retransmitTimeout = DHCP_CLIENT_REQUEST_INIT_RT;
Sergunb 0:8918a71cdbe9 638
Sergunb 0:8918a71cdbe9 639 //Save the time at which the message was sent
Sergunb 0:8918a71cdbe9 640 context->timestamp = time;
Sergunb 0:8918a71cdbe9 641
Sergunb 0:8918a71cdbe9 642 //The timeout value should be randomized by the value of a uniform
Sergunb 0:8918a71cdbe9 643 //number chosen from the range -1 to +1
Sergunb 0:8918a71cdbe9 644 context->timeout = context->retransmitTimeout +
Sergunb 0:8918a71cdbe9 645 netGetRandRange(-DHCP_CLIENT_RAND_FACTOR, DHCP_CLIENT_RAND_FACTOR);
Sergunb 0:8918a71cdbe9 646
Sergunb 0:8918a71cdbe9 647 //Increment retransmission counter
Sergunb 0:8918a71cdbe9 648 context->retransmitCount++;
Sergunb 0:8918a71cdbe9 649 }
Sergunb 0:8918a71cdbe9 650 else if(context->retransmitCount < DHCP_CLIENT_REQUEST_MAX_RC)
Sergunb 0:8918a71cdbe9 651 {
Sergunb 0:8918a71cdbe9 652 //Send a DHCPREQUEST message
Sergunb 0:8918a71cdbe9 653 dhcpClientSendRequest(context);
Sergunb 0:8918a71cdbe9 654
Sergunb 0:8918a71cdbe9 655 //The timeout value is doubled for each subsequent retransmission
Sergunb 0:8918a71cdbe9 656 context->retransmitTimeout *= 2;
Sergunb 0:8918a71cdbe9 657
Sergunb 0:8918a71cdbe9 658 //Limit the timeout value to a maximum of 64 seconds
Sergunb 0:8918a71cdbe9 659 if(context->retransmitTimeout > DHCP_CLIENT_REQUEST_MAX_RT)
Sergunb 0:8918a71cdbe9 660 context->retransmitTimeout = DHCP_CLIENT_REQUEST_MAX_RT;
Sergunb 0:8918a71cdbe9 661
Sergunb 0:8918a71cdbe9 662 //Save the time at which the message was sent
Sergunb 0:8918a71cdbe9 663 context->timestamp = time;
Sergunb 0:8918a71cdbe9 664
Sergunb 0:8918a71cdbe9 665 //The timeout value should be randomized by the value of a uniform
Sergunb 0:8918a71cdbe9 666 //number chosen from the range -1 to +1
Sergunb 0:8918a71cdbe9 667 context->timeout = context->retransmitTimeout +
Sergunb 0:8918a71cdbe9 668 netGetRandRange(-DHCP_CLIENT_RAND_FACTOR, DHCP_CLIENT_RAND_FACTOR);
Sergunb 0:8918a71cdbe9 669
Sergunb 0:8918a71cdbe9 670 //Increment retransmission counter
Sergunb 0:8918a71cdbe9 671 context->retransmitCount++;
Sergunb 0:8918a71cdbe9 672 }
Sergunb 0:8918a71cdbe9 673 else
Sergunb 0:8918a71cdbe9 674 {
Sergunb 0:8918a71cdbe9 675 //If the client does not receive a response within a reasonable
Sergunb 0:8918a71cdbe9 676 //period of time, then it restarts the initialization procedure
Sergunb 0:8918a71cdbe9 677 dhcpClientChangeState(context, DHCP_STATE_INIT, 0);
Sergunb 0:8918a71cdbe9 678 }
Sergunb 0:8918a71cdbe9 679 }
Sergunb 0:8918a71cdbe9 680
Sergunb 0:8918a71cdbe9 681 //Manage DHCP configuration timeout
Sergunb 0:8918a71cdbe9 682 dhcpClientCheckTimeout(context);
Sergunb 0:8918a71cdbe9 683 }
Sergunb 0:8918a71cdbe9 684
Sergunb 0:8918a71cdbe9 685
Sergunb 0:8918a71cdbe9 686 /**
Sergunb 0:8918a71cdbe9 687 * @brief PROBING state
Sergunb 0:8918a71cdbe9 688 *
Sergunb 0:8918a71cdbe9 689 * The client probes the newly received address
Sergunb 0:8918a71cdbe9 690 *
Sergunb 0:8918a71cdbe9 691 * @param[in] context Pointer to the DHCP client context
Sergunb 0:8918a71cdbe9 692 **/
Sergunb 0:8918a71cdbe9 693
Sergunb 0:8918a71cdbe9 694 void dhcpClientStateProbing(DhcpClientContext *context)
Sergunb 0:8918a71cdbe9 695 {
Sergunb 0:8918a71cdbe9 696 systime_t time;
Sergunb 0:8918a71cdbe9 697 NetInterface *interface;
Sergunb 0:8918a71cdbe9 698
Sergunb 0:8918a71cdbe9 699 //Point to the underlying network interface
Sergunb 0:8918a71cdbe9 700 interface = context->settings.interface;
Sergunb 0:8918a71cdbe9 701 //Get current time
Sergunb 0:8918a71cdbe9 702 time = osGetSystemTime();
Sergunb 0:8918a71cdbe9 703
Sergunb 0:8918a71cdbe9 704 //Check current time
Sergunb 0:8918a71cdbe9 705 if(timeCompare(time, context->timestamp + context->timeout) >= 0)
Sergunb 0:8918a71cdbe9 706 {
Sergunb 0:8918a71cdbe9 707 //The address is already in use?
Sergunb 0:8918a71cdbe9 708 if(interface->ipv4Context.addrConflict)
Sergunb 0:8918a71cdbe9 709 {
Sergunb 0:8918a71cdbe9 710 //If the client detects that the address is already in use, the
Sergunb 0:8918a71cdbe9 711 //client must send a DHCPDECLINE message to the server and
Sergunb 0:8918a71cdbe9 712 //restarts the configuration process
Sergunb 0:8918a71cdbe9 713 dhcpClientSendDecline(context);
Sergunb 0:8918a71cdbe9 714
Sergunb 0:8918a71cdbe9 715 //The client should wait a minimum of ten seconds before
Sergunb 0:8918a71cdbe9 716 //restarting the configuration process to avoid excessive
Sergunb 0:8918a71cdbe9 717 //network traffic in case of looping
Sergunb 0:8918a71cdbe9 718 dhcpClientChangeState(context, DHCP_STATE_INIT, 0);
Sergunb 0:8918a71cdbe9 719 }
Sergunb 0:8918a71cdbe9 720 //Probing is on-going?
Sergunb 0:8918a71cdbe9 721 else if(context->retransmitCount < DHCP_CLIENT_PROBE_NUM)
Sergunb 0:8918a71cdbe9 722 {
Sergunb 0:8918a71cdbe9 723 //Conflict detection is done using ARP probes
Sergunb 0:8918a71cdbe9 724 arpSendProbe(interface, interface->ipv4Context.addr);
Sergunb 0:8918a71cdbe9 725
Sergunb 0:8918a71cdbe9 726 //Save the time at which the packet was sent
Sergunb 0:8918a71cdbe9 727 context->timestamp = time;
Sergunb 0:8918a71cdbe9 728 //Delay until repeated probe
Sergunb 0:8918a71cdbe9 729 context->timeout = DHCP_CLIENT_PROBE_DELAY;
Sergunb 0:8918a71cdbe9 730 //Increment retransmission counter
Sergunb 0:8918a71cdbe9 731 context->retransmitCount++;
Sergunb 0:8918a71cdbe9 732 }
Sergunb 0:8918a71cdbe9 733 //Probing is complete?
Sergunb 0:8918a71cdbe9 734 else
Sergunb 0:8918a71cdbe9 735 {
Sergunb 0:8918a71cdbe9 736 //The use of the IPv4 address is now unrestricted
Sergunb 0:8918a71cdbe9 737 interface->ipv4Context.addrState = IPV4_ADDR_STATE_VALID;
Sergunb 0:8918a71cdbe9 738
Sergunb 0:8918a71cdbe9 739 #if (MDNS_RESPONDER_SUPPORT == ENABLED)
Sergunb 0:8918a71cdbe9 740 //Restart mDNS probing process
Sergunb 0:8918a71cdbe9 741 mdnsResponderStartProbing(interface->mdnsResponderContext);
Sergunb 0:8918a71cdbe9 742 #endif
Sergunb 0:8918a71cdbe9 743 //Dump current DHCP configuration for debugging purpose
Sergunb 0:8918a71cdbe9 744 dhcpClientDumpConfig(context);
Sergunb 0:8918a71cdbe9 745
Sergunb 0:8918a71cdbe9 746 //The client transitions to the BOUND state
Sergunb 0:8918a71cdbe9 747 dhcpClientChangeState(context, DHCP_STATE_BOUND, 0);
Sergunb 0:8918a71cdbe9 748 }
Sergunb 0:8918a71cdbe9 749 }
Sergunb 0:8918a71cdbe9 750 }
Sergunb 0:8918a71cdbe9 751
Sergunb 0:8918a71cdbe9 752
Sergunb 0:8918a71cdbe9 753 /**
Sergunb 0:8918a71cdbe9 754 * @brief BOUND state
Sergunb 0:8918a71cdbe9 755 *
Sergunb 0:8918a71cdbe9 756 * Client has a valid lease and is in its normal operating state
Sergunb 0:8918a71cdbe9 757 *
Sergunb 0:8918a71cdbe9 758 * @param[in] context Pointer to the DHCP client context
Sergunb 0:8918a71cdbe9 759 **/
Sergunb 0:8918a71cdbe9 760
Sergunb 0:8918a71cdbe9 761 void dhcpClientStateBound(DhcpClientContext *context)
Sergunb 0:8918a71cdbe9 762 {
Sergunb 0:8918a71cdbe9 763 systime_t t1;
Sergunb 0:8918a71cdbe9 764 systime_t time;
Sergunb 0:8918a71cdbe9 765
Sergunb 0:8918a71cdbe9 766 //Get current time
Sergunb 0:8918a71cdbe9 767 time = osGetSystemTime();
Sergunb 0:8918a71cdbe9 768
Sergunb 0:8918a71cdbe9 769 //A client will never attempt to extend the lifetime
Sergunb 0:8918a71cdbe9 770 //of the address when T1 set to 0xFFFFFFFF
Sergunb 0:8918a71cdbe9 771 if(context->t1 != DHCP_INFINITE_TIME)
Sergunb 0:8918a71cdbe9 772 {
Sergunb 0:8918a71cdbe9 773 //Convert T1 to milliseconds
Sergunb 0:8918a71cdbe9 774 if(context->t1 < (MAX_DELAY / 1000))
Sergunb 0:8918a71cdbe9 775 t1 = context->t1 * 1000;
Sergunb 0:8918a71cdbe9 776 else
Sergunb 0:8918a71cdbe9 777 t1 = MAX_DELAY;
Sergunb 0:8918a71cdbe9 778
Sergunb 0:8918a71cdbe9 779 //Check the time elapsed since the lease was obtained
Sergunb 0:8918a71cdbe9 780 if(timeCompare(time, context->leaseStartTime + t1) >= 0)
Sergunb 0:8918a71cdbe9 781 {
Sergunb 0:8918a71cdbe9 782 //Record the time at which the client started the address renewal process
Sergunb 0:8918a71cdbe9 783 context->configStartTime = time;
Sergunb 0:8918a71cdbe9 784
Sergunb 0:8918a71cdbe9 785 //Enter the RENEWING state
Sergunb 0:8918a71cdbe9 786 dhcpClientChangeState(context, DHCP_STATE_RENEWING, 0);
Sergunb 0:8918a71cdbe9 787 }
Sergunb 0:8918a71cdbe9 788 }
Sergunb 0:8918a71cdbe9 789 }
Sergunb 0:8918a71cdbe9 790
Sergunb 0:8918a71cdbe9 791
Sergunb 0:8918a71cdbe9 792 /**
Sergunb 0:8918a71cdbe9 793 * @brief RENEWING state
Sergunb 0:8918a71cdbe9 794 *
Sergunb 0:8918a71cdbe9 795 * Client is trying to renew its lease. It regularly sends
Sergunb 0:8918a71cdbe9 796 * DHCPREQUEST messages with the server that gave it its current
Sergunb 0:8918a71cdbe9 797 * lease specified, and waits for a reply
Sergunb 0:8918a71cdbe9 798 *
Sergunb 0:8918a71cdbe9 799 * @param[in] context Pointer to the DHCP client context
Sergunb 0:8918a71cdbe9 800 **/
Sergunb 0:8918a71cdbe9 801
Sergunb 0:8918a71cdbe9 802 void dhcpClientStateRenewing(DhcpClientContext *context)
Sergunb 0:8918a71cdbe9 803 {
Sergunb 0:8918a71cdbe9 804 systime_t t2;
Sergunb 0:8918a71cdbe9 805 systime_t time;
Sergunb 0:8918a71cdbe9 806
Sergunb 0:8918a71cdbe9 807 //Get current time
Sergunb 0:8918a71cdbe9 808 time = osGetSystemTime();
Sergunb 0:8918a71cdbe9 809
Sergunb 0:8918a71cdbe9 810 //Check current time
Sergunb 0:8918a71cdbe9 811 if(timeCompare(time, context->timestamp + context->timeout) >= 0)
Sergunb 0:8918a71cdbe9 812 {
Sergunb 0:8918a71cdbe9 813 //Convert T2 to milliseconds
Sergunb 0:8918a71cdbe9 814 if(context->t2 < (MAX_DELAY / 1000))
Sergunb 0:8918a71cdbe9 815 t2 = context->t2 * 1000;
Sergunb 0:8918a71cdbe9 816 else
Sergunb 0:8918a71cdbe9 817 t2 = MAX_DELAY;
Sergunb 0:8918a71cdbe9 818
Sergunb 0:8918a71cdbe9 819 //Check whether T2 timer has expired
Sergunb 0:8918a71cdbe9 820 if(timeCompare(time, context->leaseStartTime + t2) < 0)
Sergunb 0:8918a71cdbe9 821 {
Sergunb 0:8918a71cdbe9 822 //First DHCPREQUEST message?
Sergunb 0:8918a71cdbe9 823 if(context->retransmitCount == 0)
Sergunb 0:8918a71cdbe9 824 {
Sergunb 0:8918a71cdbe9 825 //A transaction identifier is used by the client to
Sergunb 0:8918a71cdbe9 826 //match incoming DHCP messages with pending requests
Sergunb 0:8918a71cdbe9 827 context->transactionId = netGetRand();
Sergunb 0:8918a71cdbe9 828 }
Sergunb 0:8918a71cdbe9 829
Sergunb 0:8918a71cdbe9 830 //Send a DHCPREQUEST message
Sergunb 0:8918a71cdbe9 831 dhcpClientSendRequest(context);
Sergunb 0:8918a71cdbe9 832
Sergunb 0:8918a71cdbe9 833 //Save the time at which the message was sent
Sergunb 0:8918a71cdbe9 834 context->timestamp = time;
Sergunb 0:8918a71cdbe9 835
Sergunb 0:8918a71cdbe9 836 //Compute the remaining time until T2 expires
Sergunb 0:8918a71cdbe9 837 context->timeout = context->leaseStartTime + t2 - time;
Sergunb 0:8918a71cdbe9 838
Sergunb 0:8918a71cdbe9 839 //The client should wait one-half of the remaining time until T2, down to
Sergunb 0:8918a71cdbe9 840 //a minimum of 60 seconds, before retransmitting the DHCPREQUEST message
Sergunb 0:8918a71cdbe9 841 if(context->timeout > (2 * DHCP_CLIENT_REQUEST_MIN_DELAY))
Sergunb 0:8918a71cdbe9 842 context->timeout /= 2;
Sergunb 0:8918a71cdbe9 843
Sergunb 0:8918a71cdbe9 844 //Increment retransmission counter
Sergunb 0:8918a71cdbe9 845 context->retransmitCount++;
Sergunb 0:8918a71cdbe9 846 }
Sergunb 0:8918a71cdbe9 847 else
Sergunb 0:8918a71cdbe9 848 {
Sergunb 0:8918a71cdbe9 849 //If no DHCPACK arrives before time T2, the client moves to REBINDING
Sergunb 0:8918a71cdbe9 850 dhcpClientChangeState(context, DHCP_STATE_REBINDING, 0);
Sergunb 0:8918a71cdbe9 851 }
Sergunb 0:8918a71cdbe9 852 }
Sergunb 0:8918a71cdbe9 853 }
Sergunb 0:8918a71cdbe9 854
Sergunb 0:8918a71cdbe9 855
Sergunb 0:8918a71cdbe9 856 /**
Sergunb 0:8918a71cdbe9 857 * @brief REBINDING state
Sergunb 0:8918a71cdbe9 858 *
Sergunb 0:8918a71cdbe9 859 * The client has failed to renew its lease with the server that originally
Sergunb 0:8918a71cdbe9 860 * granted it, and now seeks a lease extension with any server that can
Sergunb 0:8918a71cdbe9 861 * hear it. It periodically sends DHCPREQUEST messages with no server specified
Sergunb 0:8918a71cdbe9 862 * until it gets a reply or the lease ends
Sergunb 0:8918a71cdbe9 863 *
Sergunb 0:8918a71cdbe9 864 * @param[in] context Pointer to the DHCP client context
Sergunb 0:8918a71cdbe9 865 **/
Sergunb 0:8918a71cdbe9 866
Sergunb 0:8918a71cdbe9 867 void dhcpClientStateRebinding(DhcpClientContext *context)
Sergunb 0:8918a71cdbe9 868 {
Sergunb 0:8918a71cdbe9 869 systime_t time;
Sergunb 0:8918a71cdbe9 870 systime_t leaseTime;
Sergunb 0:8918a71cdbe9 871 NetInterface *interface;
Sergunb 0:8918a71cdbe9 872
Sergunb 0:8918a71cdbe9 873 //Point to the underlying network interface
Sergunb 0:8918a71cdbe9 874 interface = context->settings.interface;
Sergunb 0:8918a71cdbe9 875
Sergunb 0:8918a71cdbe9 876 //Get current time
Sergunb 0:8918a71cdbe9 877 time = osGetSystemTime();
Sergunb 0:8918a71cdbe9 878
Sergunb 0:8918a71cdbe9 879 //Check current time
Sergunb 0:8918a71cdbe9 880 if(timeCompare(time, context->timestamp + context->timeout) >= 0)
Sergunb 0:8918a71cdbe9 881 {
Sergunb 0:8918a71cdbe9 882 //Convert the lease time to milliseconds
Sergunb 0:8918a71cdbe9 883 if(context->leaseTime < (MAX_DELAY / 1000))
Sergunb 0:8918a71cdbe9 884 leaseTime = context->leaseTime * 1000;
Sergunb 0:8918a71cdbe9 885 else
Sergunb 0:8918a71cdbe9 886 leaseTime = MAX_DELAY;
Sergunb 0:8918a71cdbe9 887
Sergunb 0:8918a71cdbe9 888 //Check whether the lease has expired
Sergunb 0:8918a71cdbe9 889 if(timeCompare(time, context->leaseStartTime + leaseTime) < 0)
Sergunb 0:8918a71cdbe9 890 {
Sergunb 0:8918a71cdbe9 891 //First DHCPREQUEST message?
Sergunb 0:8918a71cdbe9 892 if(context->retransmitCount == 0)
Sergunb 0:8918a71cdbe9 893 {
Sergunb 0:8918a71cdbe9 894 //A transaction identifier is used by the client to
Sergunb 0:8918a71cdbe9 895 //match incoming DHCP messages with pending requests
Sergunb 0:8918a71cdbe9 896 context->transactionId = netGetRand();
Sergunb 0:8918a71cdbe9 897 }
Sergunb 0:8918a71cdbe9 898
Sergunb 0:8918a71cdbe9 899 //Send a DHCPREQUEST message
Sergunb 0:8918a71cdbe9 900 dhcpClientSendRequest(context);
Sergunb 0:8918a71cdbe9 901
Sergunb 0:8918a71cdbe9 902 //Save the time at which the message was sent
Sergunb 0:8918a71cdbe9 903 context->timestamp = time;
Sergunb 0:8918a71cdbe9 904
Sergunb 0:8918a71cdbe9 905 //Compute the remaining time until the lease expires
Sergunb 0:8918a71cdbe9 906 context->timeout = context->leaseStartTime + leaseTime - time;
Sergunb 0:8918a71cdbe9 907
Sergunb 0:8918a71cdbe9 908 //The client should wait one-half of the remaining lease time, down to a
Sergunb 0:8918a71cdbe9 909 //minimum of 60 seconds, before retransmitting the DHCPREQUEST message
Sergunb 0:8918a71cdbe9 910 if(context->timeout > (2 * DHCP_CLIENT_REQUEST_MIN_DELAY))
Sergunb 0:8918a71cdbe9 911 context->timeout /= 2;
Sergunb 0:8918a71cdbe9 912
Sergunb 0:8918a71cdbe9 913 //Increment retransmission counter
Sergunb 0:8918a71cdbe9 914 context->retransmitCount++;
Sergunb 0:8918a71cdbe9 915 }
Sergunb 0:8918a71cdbe9 916 else
Sergunb 0:8918a71cdbe9 917 {
Sergunb 0:8918a71cdbe9 918 //The host address is no longer valid...
Sergunb 0:8918a71cdbe9 919 interface->ipv4Context.addr = IPV4_UNSPECIFIED_ADDR;
Sergunb 0:8918a71cdbe9 920 interface->ipv4Context.addrState = IPV4_ADDR_STATE_INVALID;
Sergunb 0:8918a71cdbe9 921
Sergunb 0:8918a71cdbe9 922 //Clear subnet mask
Sergunb 0:8918a71cdbe9 923 interface->ipv4Context.subnetMask = IPV4_UNSPECIFIED_ADDR;
Sergunb 0:8918a71cdbe9 924
Sergunb 0:8918a71cdbe9 925 #if (MDNS_RESPONDER_SUPPORT == ENABLED)
Sergunb 0:8918a71cdbe9 926 //Restart mDNS probing process
Sergunb 0:8918a71cdbe9 927 mdnsResponderStartProbing(interface->mdnsResponderContext);
Sergunb 0:8918a71cdbe9 928 #endif
Sergunb 0:8918a71cdbe9 929
Sergunb 0:8918a71cdbe9 930 //If the lease expires before the client receives
Sergunb 0:8918a71cdbe9 931 //a DHCPACK, the client moves to INIT state
Sergunb 0:8918a71cdbe9 932 dhcpClientChangeState(context, DHCP_STATE_INIT, 0);
Sergunb 0:8918a71cdbe9 933 }
Sergunb 0:8918a71cdbe9 934 }
Sergunb 0:8918a71cdbe9 935 }
Sergunb 0:8918a71cdbe9 936
Sergunb 0:8918a71cdbe9 937
Sergunb 0:8918a71cdbe9 938 /**
Sergunb 0:8918a71cdbe9 939 * @brief Send DHCPDISCOVER message
Sergunb 0:8918a71cdbe9 940 * @param[in] context Pointer to the DHCP client context
Sergunb 0:8918a71cdbe9 941 * @return Error code
Sergunb 0:8918a71cdbe9 942 **/
Sergunb 0:8918a71cdbe9 943
Sergunb 0:8918a71cdbe9 944 error_t dhcpClientSendDiscover(DhcpClientContext *context)
Sergunb 0:8918a71cdbe9 945 {
Sergunb 0:8918a71cdbe9 946 error_t error;
Sergunb 0:8918a71cdbe9 947 size_t length;
Sergunb 0:8918a71cdbe9 948 size_t offset;
Sergunb 0:8918a71cdbe9 949 NetBuffer *buffer;
Sergunb 0:8918a71cdbe9 950 NetInterface *interface;
Sergunb 0:8918a71cdbe9 951 DhcpMessage *message;
Sergunb 0:8918a71cdbe9 952 IpAddr destIpAddr;
Sergunb 0:8918a71cdbe9 953
Sergunb 0:8918a71cdbe9 954 //DHCP message type
Sergunb 0:8918a71cdbe9 955 const uint8_t messageType = DHCP_MESSAGE_TYPE_DISCOVER;
Sergunb 0:8918a71cdbe9 956
Sergunb 0:8918a71cdbe9 957 //Point to the underlying network interface
Sergunb 0:8918a71cdbe9 958 interface = context->settings.interface;
Sergunb 0:8918a71cdbe9 959
Sergunb 0:8918a71cdbe9 960 //Allocate a memory buffer to hold the DHCP message
Sergunb 0:8918a71cdbe9 961 buffer = udpAllocBuffer(DHCP_MIN_MSG_SIZE, &offset);
Sergunb 0:8918a71cdbe9 962 //Failed to allocate buffer?
Sergunb 0:8918a71cdbe9 963 if(buffer == NULL)
Sergunb 0:8918a71cdbe9 964 return ERROR_OUT_OF_MEMORY;
Sergunb 0:8918a71cdbe9 965
Sergunb 0:8918a71cdbe9 966 //Point to the beginning of the DHCP message
Sergunb 0:8918a71cdbe9 967 message = netBufferAt(buffer, offset);
Sergunb 0:8918a71cdbe9 968 //Clear memory buffer contents
Sergunb 0:8918a71cdbe9 969 memset(message, 0, DHCP_MIN_MSG_SIZE);
Sergunb 0:8918a71cdbe9 970
Sergunb 0:8918a71cdbe9 971 //Format DHCPDISCOVER message
Sergunb 0:8918a71cdbe9 972 message->op = DHCP_OPCODE_BOOTREQUEST;
Sergunb 0:8918a71cdbe9 973 message->htype = DHCP_HARDWARE_TYPE_ETH;
Sergunb 0:8918a71cdbe9 974 message->hlen = sizeof(MacAddr);
Sergunb 0:8918a71cdbe9 975 message->xid = htonl(context->transactionId);
Sergunb 0:8918a71cdbe9 976 message->secs = dhcpClientComputeElapsedTime(context);
Sergunb 0:8918a71cdbe9 977 message->flags = HTONS(DHCP_FLAG_BROADCAST);
Sergunb 0:8918a71cdbe9 978 message->ciaddr = IPV4_UNSPECIFIED_ADDR;
Sergunb 0:8918a71cdbe9 979 message->chaddr = interface->macAddr;
Sergunb 0:8918a71cdbe9 980
Sergunb 0:8918a71cdbe9 981 //Write magic cookie before setting any option
Sergunb 0:8918a71cdbe9 982 message->magicCookie = HTONL(DHCP_MAGIC_COOKIE);
Sergunb 0:8918a71cdbe9 983 //Properly terminate options field
Sergunb 0:8918a71cdbe9 984 message->options[0] = DHCP_OPT_END;
Sergunb 0:8918a71cdbe9 985
Sergunb 0:8918a71cdbe9 986 //DHCP Message Type option
Sergunb 0:8918a71cdbe9 987 dhcpAddOption(message, DHCP_OPT_DHCP_MESSAGE_TYPE,
Sergunb 0:8918a71cdbe9 988 &messageType, sizeof(messageType));
Sergunb 0:8918a71cdbe9 989
Sergunb 0:8918a71cdbe9 990 //Retrieve the length of the host name
Sergunb 0:8918a71cdbe9 991 length = strlen(context->settings.hostname);
Sergunb 0:8918a71cdbe9 992
Sergunb 0:8918a71cdbe9 993 //Any host name defined?
Sergunb 0:8918a71cdbe9 994 if(length > 0)
Sergunb 0:8918a71cdbe9 995 {
Sergunb 0:8918a71cdbe9 996 //The Host Name option specifies the name of the client
Sergunb 0:8918a71cdbe9 997 dhcpAddOption(message, DHCP_OPT_HOST_NAME,
Sergunb 0:8918a71cdbe9 998 context->settings.hostname, length);
Sergunb 0:8918a71cdbe9 999 }
Sergunb 0:8918a71cdbe9 1000
Sergunb 0:8918a71cdbe9 1001 //Check whether rapid commit is enabled
Sergunb 0:8918a71cdbe9 1002 if(context->settings.rapidCommit)
Sergunb 0:8918a71cdbe9 1003 {
Sergunb 0:8918a71cdbe9 1004 //Include the Rapid Commit option if the client is prepared
Sergunb 0:8918a71cdbe9 1005 //to perform the DHCPDISCOVER-DHCPACK message exchange
Sergunb 0:8918a71cdbe9 1006 dhcpAddOption(message, DHCP_OPT_RAPID_COMMIT, NULL, 0);
Sergunb 0:8918a71cdbe9 1007 }
Sergunb 0:8918a71cdbe9 1008
Sergunb 0:8918a71cdbe9 1009 //Set destination IP address
Sergunb 0:8918a71cdbe9 1010 destIpAddr.length = sizeof(Ipv4Addr);
Sergunb 0:8918a71cdbe9 1011 destIpAddr.ipv4Addr = IPV4_BROADCAST_ADDR;
Sergunb 0:8918a71cdbe9 1012
Sergunb 0:8918a71cdbe9 1013 //Debug message
Sergunb 0:8918a71cdbe9 1014 TRACE_DEBUG("\r\n%s: Sending DHCP message (%" PRIuSIZE " bytes)...\r\n",
Sergunb 0:8918a71cdbe9 1015 formatSystemTime(osGetSystemTime(), NULL), DHCP_MIN_MSG_SIZE);
Sergunb 0:8918a71cdbe9 1016
Sergunb 0:8918a71cdbe9 1017 //Dump the contents of the message for debugging purpose
Sergunb 0:8918a71cdbe9 1018 dhcpDumpMessage(message, DHCP_MIN_MSG_SIZE);
Sergunb 0:8918a71cdbe9 1019
Sergunb 0:8918a71cdbe9 1020 //Broadcast DHCPDISCOVER message
Sergunb 0:8918a71cdbe9 1021 error = udpSendDatagramEx(interface, DHCP_CLIENT_PORT, &destIpAddr,
Sergunb 0:8918a71cdbe9 1022 DHCP_SERVER_PORT, buffer, offset, IPV4_DEFAULT_TTL);
Sergunb 0:8918a71cdbe9 1023
Sergunb 0:8918a71cdbe9 1024 //Free previously allocated memory
Sergunb 0:8918a71cdbe9 1025 netBufferFree(buffer);
Sergunb 0:8918a71cdbe9 1026 //Return status code
Sergunb 0:8918a71cdbe9 1027 return error;
Sergunb 0:8918a71cdbe9 1028 }
Sergunb 0:8918a71cdbe9 1029
Sergunb 0:8918a71cdbe9 1030
Sergunb 0:8918a71cdbe9 1031 /**
Sergunb 0:8918a71cdbe9 1032 * @brief Send DHCPREQUEST message
Sergunb 0:8918a71cdbe9 1033 * @param[in] context Pointer to the DHCP client context
Sergunb 0:8918a71cdbe9 1034 * @return Error code
Sergunb 0:8918a71cdbe9 1035 **/
Sergunb 0:8918a71cdbe9 1036
Sergunb 0:8918a71cdbe9 1037 error_t dhcpClientSendRequest(DhcpClientContext *context)
Sergunb 0:8918a71cdbe9 1038 {
Sergunb 0:8918a71cdbe9 1039 error_t error;
Sergunb 0:8918a71cdbe9 1040 size_t length;
Sergunb 0:8918a71cdbe9 1041 size_t offset;
Sergunb 0:8918a71cdbe9 1042 NetBuffer *buffer;
Sergunb 0:8918a71cdbe9 1043 NetInterface *interface;
Sergunb 0:8918a71cdbe9 1044 DhcpMessage *message;
Sergunb 0:8918a71cdbe9 1045 IpAddr destIpAddr;
Sergunb 0:8918a71cdbe9 1046
Sergunb 0:8918a71cdbe9 1047 //DHCP message type
Sergunb 0:8918a71cdbe9 1048 const uint8_t messageType = DHCP_MESSAGE_TYPE_REQUEST;
Sergunb 0:8918a71cdbe9 1049
Sergunb 0:8918a71cdbe9 1050 //Point to the underlying network interface
Sergunb 0:8918a71cdbe9 1051 interface = context->settings.interface;
Sergunb 0:8918a71cdbe9 1052
Sergunb 0:8918a71cdbe9 1053 //Allocate a memory buffer to hold the DHCP message
Sergunb 0:8918a71cdbe9 1054 buffer = udpAllocBuffer(DHCP_MIN_MSG_SIZE, &offset);
Sergunb 0:8918a71cdbe9 1055 //Failed to allocate buffer?
Sergunb 0:8918a71cdbe9 1056 if(buffer == NULL)
Sergunb 0:8918a71cdbe9 1057 return ERROR_OUT_OF_MEMORY;
Sergunb 0:8918a71cdbe9 1058
Sergunb 0:8918a71cdbe9 1059 //Point to the beginning of the DHCP message
Sergunb 0:8918a71cdbe9 1060 message = netBufferAt(buffer, offset);
Sergunb 0:8918a71cdbe9 1061 //Clear memory buffer contents
Sergunb 0:8918a71cdbe9 1062 memset(message, 0, DHCP_MIN_MSG_SIZE);
Sergunb 0:8918a71cdbe9 1063
Sergunb 0:8918a71cdbe9 1064 //Format DHCPREQUEST message
Sergunb 0:8918a71cdbe9 1065 message->op = DHCP_OPCODE_BOOTREQUEST;
Sergunb 0:8918a71cdbe9 1066 message->htype = DHCP_HARDWARE_TYPE_ETH;
Sergunb 0:8918a71cdbe9 1067 message->hlen = sizeof(MacAddr);
Sergunb 0:8918a71cdbe9 1068 message->xid = htonl(context->transactionId);
Sergunb 0:8918a71cdbe9 1069 message->secs = dhcpClientComputeElapsedTime(context);
Sergunb 0:8918a71cdbe9 1070
Sergunb 0:8918a71cdbe9 1071 //The client IP address must be included if the client
Sergunb 0:8918a71cdbe9 1072 //is fully configured and can respond to ARP requests
Sergunb 0:8918a71cdbe9 1073 if(context->state == DHCP_STATE_RENEWING ||
Sergunb 0:8918a71cdbe9 1074 context->state == DHCP_STATE_REBINDING)
Sergunb 0:8918a71cdbe9 1075 {
Sergunb 0:8918a71cdbe9 1076 message->flags = 0;
Sergunb 0:8918a71cdbe9 1077 message->ciaddr = interface->ipv4Context.addr;
Sergunb 0:8918a71cdbe9 1078 }
Sergunb 0:8918a71cdbe9 1079 else
Sergunb 0:8918a71cdbe9 1080 {
Sergunb 0:8918a71cdbe9 1081 message->flags = HTONS(DHCP_FLAG_BROADCAST);
Sergunb 0:8918a71cdbe9 1082 message->ciaddr = IPV4_UNSPECIFIED_ADDR;
Sergunb 0:8918a71cdbe9 1083 }
Sergunb 0:8918a71cdbe9 1084
Sergunb 0:8918a71cdbe9 1085 //Client hardware address
Sergunb 0:8918a71cdbe9 1086 message->chaddr = interface->macAddr;
Sergunb 0:8918a71cdbe9 1087 //Write magic cookie before setting any option
Sergunb 0:8918a71cdbe9 1088 message->magicCookie = HTONL(DHCP_MAGIC_COOKIE);
Sergunb 0:8918a71cdbe9 1089 //Properly terminate options field
Sergunb 0:8918a71cdbe9 1090 message->options[0] = DHCP_OPT_END;
Sergunb 0:8918a71cdbe9 1091
Sergunb 0:8918a71cdbe9 1092 //DHCP Message Type option
Sergunb 0:8918a71cdbe9 1093 dhcpAddOption(message, DHCP_OPT_DHCP_MESSAGE_TYPE,
Sergunb 0:8918a71cdbe9 1094 &messageType, sizeof(messageType));
Sergunb 0:8918a71cdbe9 1095
Sergunb 0:8918a71cdbe9 1096 //Retrieve the length of the host name
Sergunb 0:8918a71cdbe9 1097 length = strlen(context->settings.hostname);
Sergunb 0:8918a71cdbe9 1098
Sergunb 0:8918a71cdbe9 1099 //Any host name defined?
Sergunb 0:8918a71cdbe9 1100 if(length > 0)
Sergunb 0:8918a71cdbe9 1101 {
Sergunb 0:8918a71cdbe9 1102 //The Host Name option specifies the name of the client
Sergunb 0:8918a71cdbe9 1103 dhcpAddOption(message, DHCP_OPT_HOST_NAME,
Sergunb 0:8918a71cdbe9 1104 context->settings.hostname, length);
Sergunb 0:8918a71cdbe9 1105 }
Sergunb 0:8918a71cdbe9 1106
Sergunb 0:8918a71cdbe9 1107 //Server Identifier option
Sergunb 0:8918a71cdbe9 1108 if(context->state == DHCP_STATE_REQUESTING)
Sergunb 0:8918a71cdbe9 1109 {
Sergunb 0:8918a71cdbe9 1110 dhcpAddOption(message, DHCP_OPT_SERVER_IDENTIFIER,
Sergunb 0:8918a71cdbe9 1111 &context->serverIpAddr, sizeof(Ipv4Addr));
Sergunb 0:8918a71cdbe9 1112 }
Sergunb 0:8918a71cdbe9 1113
Sergunb 0:8918a71cdbe9 1114 //Requested IP Address option
Sergunb 0:8918a71cdbe9 1115 if(context->state == DHCP_STATE_REQUESTING ||
Sergunb 0:8918a71cdbe9 1116 context->state == DHCP_STATE_REBOOTING)
Sergunb 0:8918a71cdbe9 1117 {
Sergunb 0:8918a71cdbe9 1118 dhcpAddOption(message, DHCP_OPT_REQUESTED_IP_ADDRESS,
Sergunb 0:8918a71cdbe9 1119 &context->requestedIpAddr, sizeof(Ipv4Addr));
Sergunb 0:8918a71cdbe9 1120 }
Sergunb 0:8918a71cdbe9 1121
Sergunb 0:8918a71cdbe9 1122 //Parameter Request List option
Sergunb 0:8918a71cdbe9 1123 dhcpAddOption(message, DHCP_OPT_PARAM_REQUEST_LIST,
Sergunb 0:8918a71cdbe9 1124 dhcpOptionList, sizeof(dhcpOptionList));
Sergunb 0:8918a71cdbe9 1125
Sergunb 0:8918a71cdbe9 1126 //IP address is being renewed?
Sergunb 0:8918a71cdbe9 1127 if(context->state == DHCP_STATE_RENEWING)
Sergunb 0:8918a71cdbe9 1128 {
Sergunb 0:8918a71cdbe9 1129 //The client transmits the message directly to the
Sergunb 0:8918a71cdbe9 1130 //server that initially granted the lease
Sergunb 0:8918a71cdbe9 1131 destIpAddr.length = sizeof(Ipv4Addr);
Sergunb 0:8918a71cdbe9 1132 destIpAddr.ipv4Addr = context->serverIpAddr;
Sergunb 0:8918a71cdbe9 1133 }
Sergunb 0:8918a71cdbe9 1134 else
Sergunb 0:8918a71cdbe9 1135 {
Sergunb 0:8918a71cdbe9 1136 //Broadcast the message
Sergunb 0:8918a71cdbe9 1137 destIpAddr.length = sizeof(Ipv4Addr);
Sergunb 0:8918a71cdbe9 1138 destIpAddr.ipv4Addr = IPV4_BROADCAST_ADDR;
Sergunb 0:8918a71cdbe9 1139 }
Sergunb 0:8918a71cdbe9 1140
Sergunb 0:8918a71cdbe9 1141 //Debug message
Sergunb 0:8918a71cdbe9 1142 TRACE_DEBUG("\r\n%s: Sending DHCP message (%" PRIuSIZE " bytes)...\r\n",
Sergunb 0:8918a71cdbe9 1143 formatSystemTime(osGetSystemTime(), NULL), DHCP_MIN_MSG_SIZE);
Sergunb 0:8918a71cdbe9 1144
Sergunb 0:8918a71cdbe9 1145 //Dump the contents of the message for debugging purpose
Sergunb 0:8918a71cdbe9 1146 dhcpDumpMessage(message, DHCP_MIN_MSG_SIZE);
Sergunb 0:8918a71cdbe9 1147
Sergunb 0:8918a71cdbe9 1148 //Send DHCPREQUEST message
Sergunb 0:8918a71cdbe9 1149 error = udpSendDatagramEx(interface, DHCP_CLIENT_PORT, &destIpAddr,
Sergunb 0:8918a71cdbe9 1150 DHCP_SERVER_PORT, buffer, offset, IPV4_DEFAULT_TTL);
Sergunb 0:8918a71cdbe9 1151
Sergunb 0:8918a71cdbe9 1152 //Free previously allocated memory
Sergunb 0:8918a71cdbe9 1153 netBufferFree(buffer);
Sergunb 0:8918a71cdbe9 1154 //Return status code
Sergunb 0:8918a71cdbe9 1155 return error;
Sergunb 0:8918a71cdbe9 1156 }
Sergunb 0:8918a71cdbe9 1157
Sergunb 0:8918a71cdbe9 1158
Sergunb 0:8918a71cdbe9 1159 /**
Sergunb 0:8918a71cdbe9 1160 * @brief Send DHCPDECLINE message
Sergunb 0:8918a71cdbe9 1161 * @param[in] context Pointer to the DHCP client context
Sergunb 0:8918a71cdbe9 1162 * @return Error code
Sergunb 0:8918a71cdbe9 1163 **/
Sergunb 0:8918a71cdbe9 1164
Sergunb 0:8918a71cdbe9 1165 error_t dhcpClientSendDecline(DhcpClientContext *context)
Sergunb 0:8918a71cdbe9 1166 {
Sergunb 0:8918a71cdbe9 1167 error_t error;
Sergunb 0:8918a71cdbe9 1168 size_t offset;
Sergunb 0:8918a71cdbe9 1169 NetBuffer *buffer;
Sergunb 0:8918a71cdbe9 1170 NetInterface *interface;
Sergunb 0:8918a71cdbe9 1171 DhcpMessage *message;
Sergunb 0:8918a71cdbe9 1172 IpAddr destIpAddr;
Sergunb 0:8918a71cdbe9 1173
Sergunb 0:8918a71cdbe9 1174 //DHCP message type
Sergunb 0:8918a71cdbe9 1175 const uint8_t messageType = DHCP_MESSAGE_TYPE_DECLINE;
Sergunb 0:8918a71cdbe9 1176
Sergunb 0:8918a71cdbe9 1177 //Point to the underlying network interface
Sergunb 0:8918a71cdbe9 1178 interface = context->settings.interface;
Sergunb 0:8918a71cdbe9 1179
Sergunb 0:8918a71cdbe9 1180 //Allocate a memory buffer to hold the DHCP message
Sergunb 0:8918a71cdbe9 1181 buffer = udpAllocBuffer(DHCP_MIN_MSG_SIZE, &offset);
Sergunb 0:8918a71cdbe9 1182 //Failed to allocate buffer?
Sergunb 0:8918a71cdbe9 1183 if(buffer == NULL)
Sergunb 0:8918a71cdbe9 1184 return ERROR_OUT_OF_MEMORY;
Sergunb 0:8918a71cdbe9 1185
Sergunb 0:8918a71cdbe9 1186 //Point to the beginning of the DHCP message
Sergunb 0:8918a71cdbe9 1187 message = netBufferAt(buffer, offset);
Sergunb 0:8918a71cdbe9 1188 //Clear memory buffer contents
Sergunb 0:8918a71cdbe9 1189 memset(message, 0, DHCP_MIN_MSG_SIZE);
Sergunb 0:8918a71cdbe9 1190
Sergunb 0:8918a71cdbe9 1191 //Format DHCPDECLINE message
Sergunb 0:8918a71cdbe9 1192 message->op = DHCP_OPCODE_BOOTREQUEST;
Sergunb 0:8918a71cdbe9 1193 message->htype = DHCP_HARDWARE_TYPE_ETH;
Sergunb 0:8918a71cdbe9 1194 message->hlen = sizeof(MacAddr);
Sergunb 0:8918a71cdbe9 1195 message->xid = htonl(context->transactionId);
Sergunb 0:8918a71cdbe9 1196 message->secs = 0;
Sergunb 0:8918a71cdbe9 1197 message->flags = 0;
Sergunb 0:8918a71cdbe9 1198 message->ciaddr = IPV4_UNSPECIFIED_ADDR;
Sergunb 0:8918a71cdbe9 1199 message->chaddr = interface->macAddr;
Sergunb 0:8918a71cdbe9 1200
Sergunb 0:8918a71cdbe9 1201 //Write magic cookie before setting any option
Sergunb 0:8918a71cdbe9 1202 message->magicCookie = HTONL(DHCP_MAGIC_COOKIE);
Sergunb 0:8918a71cdbe9 1203 //Properly terminate options field
Sergunb 0:8918a71cdbe9 1204 message->options[0] = DHCP_OPT_END;
Sergunb 0:8918a71cdbe9 1205
Sergunb 0:8918a71cdbe9 1206 //DHCP Message Type option
Sergunb 0:8918a71cdbe9 1207 dhcpAddOption(message, DHCP_OPT_DHCP_MESSAGE_TYPE,
Sergunb 0:8918a71cdbe9 1208 &messageType, sizeof(messageType));
Sergunb 0:8918a71cdbe9 1209 //Server Identifier option
Sergunb 0:8918a71cdbe9 1210 dhcpAddOption(message, DHCP_OPT_SERVER_IDENTIFIER,
Sergunb 0:8918a71cdbe9 1211 &context->serverIpAddr, sizeof(Ipv4Addr));
Sergunb 0:8918a71cdbe9 1212 //Requested IP Address option
Sergunb 0:8918a71cdbe9 1213 dhcpAddOption(message, DHCP_OPT_REQUESTED_IP_ADDRESS,
Sergunb 0:8918a71cdbe9 1214 &context->requestedIpAddr, sizeof(Ipv4Addr));
Sergunb 0:8918a71cdbe9 1215
Sergunb 0:8918a71cdbe9 1216 //Set destination IP address
Sergunb 0:8918a71cdbe9 1217 destIpAddr.length = sizeof(Ipv4Addr);
Sergunb 0:8918a71cdbe9 1218 destIpAddr.ipv4Addr = IPV4_BROADCAST_ADDR;
Sergunb 0:8918a71cdbe9 1219
Sergunb 0:8918a71cdbe9 1220 //Debug message
Sergunb 0:8918a71cdbe9 1221 TRACE_DEBUG("\r\n%s: Sending DHCP message (%" PRIuSIZE " bytes)...\r\n",
Sergunb 0:8918a71cdbe9 1222 formatSystemTime(osGetSystemTime(), NULL), DHCP_MIN_MSG_SIZE);
Sergunb 0:8918a71cdbe9 1223
Sergunb 0:8918a71cdbe9 1224 //Dump the contents of the message for debugging purpose
Sergunb 0:8918a71cdbe9 1225 dhcpDumpMessage(message, DHCP_MIN_MSG_SIZE);
Sergunb 0:8918a71cdbe9 1226
Sergunb 0:8918a71cdbe9 1227 //Broadcast DHCPDECLINE message
Sergunb 0:8918a71cdbe9 1228 error = udpSendDatagramEx(interface, DHCP_CLIENT_PORT, &destIpAddr,
Sergunb 0:8918a71cdbe9 1229 DHCP_SERVER_PORT, buffer, offset, IPV4_DEFAULT_TTL);
Sergunb 0:8918a71cdbe9 1230
Sergunb 0:8918a71cdbe9 1231 //Free previously allocated memory
Sergunb 0:8918a71cdbe9 1232 netBufferFree(buffer);
Sergunb 0:8918a71cdbe9 1233 //Return status code
Sergunb 0:8918a71cdbe9 1234 return error;
Sergunb 0:8918a71cdbe9 1235 }
Sergunb 0:8918a71cdbe9 1236
Sergunb 0:8918a71cdbe9 1237
Sergunb 0:8918a71cdbe9 1238 /**
Sergunb 0:8918a71cdbe9 1239 * @brief Process incoming DHCP message
Sergunb 0:8918a71cdbe9 1240 * @param[in] interface Underlying network interface
Sergunb 0:8918a71cdbe9 1241 * @param[in] pseudoHeader UDP pseudo header
Sergunb 0:8918a71cdbe9 1242 * @param[in] udpHeader UDP header
Sergunb 0:8918a71cdbe9 1243 * @param[in] buffer Multi-part buffer containing the incoming DHCP message
Sergunb 0:8918a71cdbe9 1244 * @param[in] offset Offset to the first byte of the DHCP message
Sergunb 0:8918a71cdbe9 1245 * @param[in] params Pointer to the DHCP client context
Sergunb 0:8918a71cdbe9 1246 **/
Sergunb 0:8918a71cdbe9 1247
Sergunb 0:8918a71cdbe9 1248 void dhcpClientProcessMessage(NetInterface *interface,
Sergunb 0:8918a71cdbe9 1249 const IpPseudoHeader *pseudoHeader, const UdpHeader *udpHeader,
Sergunb 0:8918a71cdbe9 1250 const NetBuffer *buffer, size_t offset, void *params)
Sergunb 0:8918a71cdbe9 1251 {
Sergunb 0:8918a71cdbe9 1252 size_t length;
Sergunb 0:8918a71cdbe9 1253 DhcpClientContext *context;
Sergunb 0:8918a71cdbe9 1254 DhcpMessage *message;
Sergunb 0:8918a71cdbe9 1255 DhcpOption *option;
Sergunb 0:8918a71cdbe9 1256
Sergunb 0:8918a71cdbe9 1257 //Point to the DHCP client context
Sergunb 0:8918a71cdbe9 1258 context = (DhcpClientContext *) params;
Sergunb 0:8918a71cdbe9 1259
Sergunb 0:8918a71cdbe9 1260 //Retrieve the length of the DHCP message
Sergunb 0:8918a71cdbe9 1261 length = netBufferGetLength(buffer) - offset;
Sergunb 0:8918a71cdbe9 1262
Sergunb 0:8918a71cdbe9 1263 //Make sure the DHCP message is valid
Sergunb 0:8918a71cdbe9 1264 if(length < sizeof(DhcpMessage))
Sergunb 0:8918a71cdbe9 1265 return;
Sergunb 0:8918a71cdbe9 1266 if(length > DHCP_MAX_MSG_SIZE)
Sergunb 0:8918a71cdbe9 1267 return;
Sergunb 0:8918a71cdbe9 1268
Sergunb 0:8918a71cdbe9 1269 //Point to the beginning of the DHCP message
Sergunb 0:8918a71cdbe9 1270 message = netBufferAt(buffer, offset);
Sergunb 0:8918a71cdbe9 1271 //Sanity check
Sergunb 0:8918a71cdbe9 1272 if(message == NULL)
Sergunb 0:8918a71cdbe9 1273 return;
Sergunb 0:8918a71cdbe9 1274
Sergunb 0:8918a71cdbe9 1275 //Debug message
Sergunb 0:8918a71cdbe9 1276 TRACE_DEBUG("\r\n%s: DHCP message received (%" PRIuSIZE " bytes)...\r\n",
Sergunb 0:8918a71cdbe9 1277 formatSystemTime(osGetSystemTime(), NULL), length);
Sergunb 0:8918a71cdbe9 1278
Sergunb 0:8918a71cdbe9 1279 //Dump the contents of the message for debugging purpose
Sergunb 0:8918a71cdbe9 1280 dhcpDumpMessage(message, length);
Sergunb 0:8918a71cdbe9 1281
Sergunb 0:8918a71cdbe9 1282 //The DHCP server shall respond with a BOOTREPLY opcode
Sergunb 0:8918a71cdbe9 1283 if(message->op != DHCP_OPCODE_BOOTREPLY)
Sergunb 0:8918a71cdbe9 1284 return;
Sergunb 0:8918a71cdbe9 1285 //Enforce hardware type
Sergunb 0:8918a71cdbe9 1286 if(message->htype != DHCP_HARDWARE_TYPE_ETH)
Sergunb 0:8918a71cdbe9 1287 return;
Sergunb 0:8918a71cdbe9 1288 //Check the length of the hardware address
Sergunb 0:8918a71cdbe9 1289 if(message->hlen != sizeof(MacAddr))
Sergunb 0:8918a71cdbe9 1290 return;
Sergunb 0:8918a71cdbe9 1291 //Check magic cookie
Sergunb 0:8918a71cdbe9 1292 if(message->magicCookie != HTONL(DHCP_MAGIC_COOKIE))
Sergunb 0:8918a71cdbe9 1293 return;
Sergunb 0:8918a71cdbe9 1294
Sergunb 0:8918a71cdbe9 1295 //The DHCP Message Type option must be included in every DHCP message
Sergunb 0:8918a71cdbe9 1296 option = dhcpGetOption(message, length, DHCP_OPT_DHCP_MESSAGE_TYPE);
Sergunb 0:8918a71cdbe9 1297
Sergunb 0:8918a71cdbe9 1298 //Failed to retrieve the Message Type option?
Sergunb 0:8918a71cdbe9 1299 if(option == NULL || option->length != 1)
Sergunb 0:8918a71cdbe9 1300 return;
Sergunb 0:8918a71cdbe9 1301
Sergunb 0:8918a71cdbe9 1302 //Check message type
Sergunb 0:8918a71cdbe9 1303 switch(option->value[0])
Sergunb 0:8918a71cdbe9 1304 {
Sergunb 0:8918a71cdbe9 1305 case DHCP_MESSAGE_TYPE_OFFER:
Sergunb 0:8918a71cdbe9 1306 //Parse DHCPOFFER message
Sergunb 0:8918a71cdbe9 1307 dhcpClientParseOffer(context, message, length);
Sergunb 0:8918a71cdbe9 1308 break;
Sergunb 0:8918a71cdbe9 1309 case DHCP_MESSAGE_TYPE_ACK:
Sergunb 0:8918a71cdbe9 1310 //Parse DHCPACK message
Sergunb 0:8918a71cdbe9 1311 dhcpClientParseAck(context, message, length);
Sergunb 0:8918a71cdbe9 1312 break;
Sergunb 0:8918a71cdbe9 1313 case DHCP_MESSAGE_TYPE_NAK:
Sergunb 0:8918a71cdbe9 1314 //Parse DHCPNAK message
Sergunb 0:8918a71cdbe9 1315 dhcpClientParseNak(context, message, length);
Sergunb 0:8918a71cdbe9 1316 break;
Sergunb 0:8918a71cdbe9 1317 default:
Sergunb 0:8918a71cdbe9 1318 //Silently drop incoming message
Sergunb 0:8918a71cdbe9 1319 break;
Sergunb 0:8918a71cdbe9 1320 }
Sergunb 0:8918a71cdbe9 1321 }
Sergunb 0:8918a71cdbe9 1322
Sergunb 0:8918a71cdbe9 1323
Sergunb 0:8918a71cdbe9 1324 /**
Sergunb 0:8918a71cdbe9 1325 * @brief Parse DHCPOFFER message
Sergunb 0:8918a71cdbe9 1326 * @param[in] context Pointer to the DHCP client context
Sergunb 0:8918a71cdbe9 1327 * @param[in] message Pointer to the incoming DHCP message
Sergunb 0:8918a71cdbe9 1328 * @param[in] length Length of the incoming message to parse
Sergunb 0:8918a71cdbe9 1329 **/
Sergunb 0:8918a71cdbe9 1330
Sergunb 0:8918a71cdbe9 1331 void dhcpClientParseOffer(DhcpClientContext *context,
Sergunb 0:8918a71cdbe9 1332 const DhcpMessage *message, size_t length)
Sergunb 0:8918a71cdbe9 1333 {
Sergunb 0:8918a71cdbe9 1334 DhcpOption *serverIdOption;
Sergunb 0:8918a71cdbe9 1335 NetInterface *interface;
Sergunb 0:8918a71cdbe9 1336
Sergunb 0:8918a71cdbe9 1337 //Point to the underlying network interface
Sergunb 0:8918a71cdbe9 1338 interface = context->settings.interface;
Sergunb 0:8918a71cdbe9 1339
Sergunb 0:8918a71cdbe9 1340 //Discard any received packet that does not match the transaction ID
Sergunb 0:8918a71cdbe9 1341 if(ntohl(message->xid) != context->transactionId)
Sergunb 0:8918a71cdbe9 1342 return;
Sergunb 0:8918a71cdbe9 1343 //Make sure the IP address offered to the client is valid
Sergunb 0:8918a71cdbe9 1344 if(message->yiaddr == IPV4_UNSPECIFIED_ADDR)
Sergunb 0:8918a71cdbe9 1345 return;
Sergunb 0:8918a71cdbe9 1346 //Check MAC address
Sergunb 0:8918a71cdbe9 1347 if(!macCompAddr(&message->chaddr, &interface->macAddr))
Sergunb 0:8918a71cdbe9 1348 return;
Sergunb 0:8918a71cdbe9 1349
Sergunb 0:8918a71cdbe9 1350 //Make sure that the DHCPOFFER message is received in response to
Sergunb 0:8918a71cdbe9 1351 //a DHCPDISCOVER message
Sergunb 0:8918a71cdbe9 1352 if(context->state != DHCP_STATE_SELECTING)
Sergunb 0:8918a71cdbe9 1353 return;
Sergunb 0:8918a71cdbe9 1354
Sergunb 0:8918a71cdbe9 1355 //A DHCP server always returns its own address in the Server Identifier option
Sergunb 0:8918a71cdbe9 1356 serverIdOption = dhcpGetOption(message, length, DHCP_OPT_SERVER_IDENTIFIER);
Sergunb 0:8918a71cdbe9 1357
Sergunb 0:8918a71cdbe9 1358 //Failed to retrieve the Server Identifier option?
Sergunb 0:8918a71cdbe9 1359 if(serverIdOption == NULL || serverIdOption->length != 4)
Sergunb 0:8918a71cdbe9 1360 return;
Sergunb 0:8918a71cdbe9 1361
Sergunb 0:8918a71cdbe9 1362 //Record the IP address of the DHCP server
Sergunb 0:8918a71cdbe9 1363 ipv4CopyAddr(&context->serverIpAddr, serverIdOption->value);
Sergunb 0:8918a71cdbe9 1364 //Record the IP address offered to the client
Sergunb 0:8918a71cdbe9 1365 context->requestedIpAddr = message->yiaddr;
Sergunb 0:8918a71cdbe9 1366
Sergunb 0:8918a71cdbe9 1367 //Switch to the REQUESTING state
Sergunb 0:8918a71cdbe9 1368 dhcpClientChangeState(context, DHCP_STATE_REQUESTING, 0);
Sergunb 0:8918a71cdbe9 1369 }
Sergunb 0:8918a71cdbe9 1370
Sergunb 0:8918a71cdbe9 1371
Sergunb 0:8918a71cdbe9 1372 /**
Sergunb 0:8918a71cdbe9 1373 * @brief Parse DHCPACK message
Sergunb 0:8918a71cdbe9 1374 * @param[in] context Pointer to the DHCP client context
Sergunb 0:8918a71cdbe9 1375 * @param[in] message Pointer to the incoming DHCP message
Sergunb 0:8918a71cdbe9 1376 * @param[in] length Length of the incoming message to parse
Sergunb 0:8918a71cdbe9 1377 * @return Error code
Sergunb 0:8918a71cdbe9 1378 **/
Sergunb 0:8918a71cdbe9 1379
Sergunb 0:8918a71cdbe9 1380 void dhcpClientParseAck(DhcpClientContext *context,
Sergunb 0:8918a71cdbe9 1381 const DhcpMessage *message, size_t length)
Sergunb 0:8918a71cdbe9 1382 {
Sergunb 0:8918a71cdbe9 1383 uint_t i;
Sergunb 0:8918a71cdbe9 1384 uint_t n;
Sergunb 0:8918a71cdbe9 1385 DhcpOption *option;
Sergunb 0:8918a71cdbe9 1386 DhcpOption *serverIdOption;
Sergunb 0:8918a71cdbe9 1387 NetInterface *interface;
Sergunb 0:8918a71cdbe9 1388
Sergunb 0:8918a71cdbe9 1389 //Point to the underlying network interface
Sergunb 0:8918a71cdbe9 1390 interface = context->settings.interface;
Sergunb 0:8918a71cdbe9 1391
Sergunb 0:8918a71cdbe9 1392 //Discard any received packet that does not match the transaction ID
Sergunb 0:8918a71cdbe9 1393 if(ntohl(message->xid) != context->transactionId)
Sergunb 0:8918a71cdbe9 1394 return;
Sergunb 0:8918a71cdbe9 1395 //Make sure the IP address assigned to the client is valid
Sergunb 0:8918a71cdbe9 1396 if(message->yiaddr == IPV4_UNSPECIFIED_ADDR)
Sergunb 0:8918a71cdbe9 1397 return;
Sergunb 0:8918a71cdbe9 1398 //Check MAC address
Sergunb 0:8918a71cdbe9 1399 if(!macCompAddr(&message->chaddr, &interface->macAddr))
Sergunb 0:8918a71cdbe9 1400 return;
Sergunb 0:8918a71cdbe9 1401
Sergunb 0:8918a71cdbe9 1402 //A DHCP server always returns its own address in the Server Identifier option
Sergunb 0:8918a71cdbe9 1403 serverIdOption = dhcpGetOption(message, length, DHCP_OPT_SERVER_IDENTIFIER);
Sergunb 0:8918a71cdbe9 1404
Sergunb 0:8918a71cdbe9 1405 //Failed to retrieve the Server Identifier option?
Sergunb 0:8918a71cdbe9 1406 if(serverIdOption == NULL || serverIdOption->length != 4)
Sergunb 0:8918a71cdbe9 1407 return;
Sergunb 0:8918a71cdbe9 1408
Sergunb 0:8918a71cdbe9 1409 //Check current state
Sergunb 0:8918a71cdbe9 1410 if(context->state == DHCP_STATE_SELECTING)
Sergunb 0:8918a71cdbe9 1411 {
Sergunb 0:8918a71cdbe9 1412 //A DHCPACK message is not acceptable when rapid commit is disallowed
Sergunb 0:8918a71cdbe9 1413 if(!context->settings.rapidCommit)
Sergunb 0:8918a71cdbe9 1414 return;
Sergunb 0:8918a71cdbe9 1415
Sergunb 0:8918a71cdbe9 1416 //Search for the Rapid Commit option
Sergunb 0:8918a71cdbe9 1417 option = dhcpGetOption(message, length, DHCP_OPT_RAPID_COMMIT);
Sergunb 0:8918a71cdbe9 1418
Sergunb 0:8918a71cdbe9 1419 //A server must include this option in a DHCPACK message sent
Sergunb 0:8918a71cdbe9 1420 //in a response to a DHCPDISCOVER message when completing the
Sergunb 0:8918a71cdbe9 1421 //DHCPDISCOVER-DHCPACK message exchange
Sergunb 0:8918a71cdbe9 1422 if(option == NULL || option->length != 0)
Sergunb 0:8918a71cdbe9 1423 return;
Sergunb 0:8918a71cdbe9 1424 }
Sergunb 0:8918a71cdbe9 1425 else if(context->state == DHCP_STATE_REQUESTING ||
Sergunb 0:8918a71cdbe9 1426 context->state == DHCP_STATE_RENEWING)
Sergunb 0:8918a71cdbe9 1427 {
Sergunb 0:8918a71cdbe9 1428 //Check the server identifier
Sergunb 0:8918a71cdbe9 1429 if(!ipv4CompAddr(serverIdOption->value, &context->serverIpAddr))
Sergunb 0:8918a71cdbe9 1430 return;
Sergunb 0:8918a71cdbe9 1431 }
Sergunb 0:8918a71cdbe9 1432 else if(context->state == DHCP_STATE_REBOOTING ||
Sergunb 0:8918a71cdbe9 1433 context->state == DHCP_STATE_REBINDING)
Sergunb 0:8918a71cdbe9 1434 {
Sergunb 0:8918a71cdbe9 1435 //Do not check the server identifier
Sergunb 0:8918a71cdbe9 1436 }
Sergunb 0:8918a71cdbe9 1437 else
Sergunb 0:8918a71cdbe9 1438 {
Sergunb 0:8918a71cdbe9 1439 //Silently discard the DHCPACK message
Sergunb 0:8918a71cdbe9 1440 return;
Sergunb 0:8918a71cdbe9 1441 }
Sergunb 0:8918a71cdbe9 1442
Sergunb 0:8918a71cdbe9 1443 //Retrieve IP Address Lease Time option
Sergunb 0:8918a71cdbe9 1444 option = dhcpGetOption(message, length, DHCP_OPT_IP_ADDRESS_LEASE_TIME);
Sergunb 0:8918a71cdbe9 1445
Sergunb 0:8918a71cdbe9 1446 //Failed to retrieve specified option?
Sergunb 0:8918a71cdbe9 1447 if(option == NULL || option->length != 4)
Sergunb 0:8918a71cdbe9 1448 return;
Sergunb 0:8918a71cdbe9 1449
Sergunb 0:8918a71cdbe9 1450 //Record the lease time
Sergunb 0:8918a71cdbe9 1451 context->leaseTime = LOAD32BE(option->value);
Sergunb 0:8918a71cdbe9 1452
Sergunb 0:8918a71cdbe9 1453 //Retrieve Renewal Time Value option
Sergunb 0:8918a71cdbe9 1454 option = dhcpGetOption(message, length, DHCP_OPT_RENEWAL_TIME_VALUE);
Sergunb 0:8918a71cdbe9 1455
Sergunb 0:8918a71cdbe9 1456 //Specified option found?
Sergunb 0:8918a71cdbe9 1457 if(option != NULL && option->length == 4)
Sergunb 0:8918a71cdbe9 1458 {
Sergunb 0:8918a71cdbe9 1459 //This option specifies the time interval from address assignment
Sergunb 0:8918a71cdbe9 1460 //until the client transitions to the RENEWING state
Sergunb 0:8918a71cdbe9 1461 context->t1 = LOAD32BE(option->value);
Sergunb 0:8918a71cdbe9 1462 }
Sergunb 0:8918a71cdbe9 1463 else if(context->leaseTime != DHCP_INFINITE_TIME)
Sergunb 0:8918a71cdbe9 1464 {
Sergunb 0:8918a71cdbe9 1465 //By default, T1 is set to 50% of the lease time
Sergunb 0:8918a71cdbe9 1466 context->t1 = context->leaseTime / 2;
Sergunb 0:8918a71cdbe9 1467 }
Sergunb 0:8918a71cdbe9 1468 else
Sergunb 0:8918a71cdbe9 1469 {
Sergunb 0:8918a71cdbe9 1470 //Infinite lease
Sergunb 0:8918a71cdbe9 1471 context->t1 = DHCP_INFINITE_TIME;
Sergunb 0:8918a71cdbe9 1472 }
Sergunb 0:8918a71cdbe9 1473
Sergunb 0:8918a71cdbe9 1474 //Retrieve Rebinding Time value option
Sergunb 0:8918a71cdbe9 1475 option = dhcpGetOption(message, length, DHCP_OPT_REBINDING_TIME_VALUE);
Sergunb 0:8918a71cdbe9 1476
Sergunb 0:8918a71cdbe9 1477 //Specified option found?
Sergunb 0:8918a71cdbe9 1478 if(option != NULL && option->length == 4)
Sergunb 0:8918a71cdbe9 1479 {
Sergunb 0:8918a71cdbe9 1480 //This option specifies the time interval from address assignment
Sergunb 0:8918a71cdbe9 1481 //until the client transitions to the REBINDING state
Sergunb 0:8918a71cdbe9 1482 context->t2 = LOAD32BE(option->value);
Sergunb 0:8918a71cdbe9 1483 }
Sergunb 0:8918a71cdbe9 1484 else if(context->leaseTime != DHCP_INFINITE_TIME)
Sergunb 0:8918a71cdbe9 1485 {
Sergunb 0:8918a71cdbe9 1486 //By default, T2 is set to 87.5% of the lease time
Sergunb 0:8918a71cdbe9 1487 context->t2 = context->leaseTime * 7 / 8;
Sergunb 0:8918a71cdbe9 1488 }
Sergunb 0:8918a71cdbe9 1489 else
Sergunb 0:8918a71cdbe9 1490 {
Sergunb 0:8918a71cdbe9 1491 //Infinite lease
Sergunb 0:8918a71cdbe9 1492 context->t2 = DHCP_INFINITE_TIME;
Sergunb 0:8918a71cdbe9 1493 }
Sergunb 0:8918a71cdbe9 1494
Sergunb 0:8918a71cdbe9 1495 //Retrieve Subnet Mask option
Sergunb 0:8918a71cdbe9 1496 option = dhcpGetOption(message, length, DHCP_OPT_SUBNET_MASK);
Sergunb 0:8918a71cdbe9 1497
Sergunb 0:8918a71cdbe9 1498 //The specified option has been found?
Sergunb 0:8918a71cdbe9 1499 if(option != NULL && option->length == sizeof(Ipv4Addr))
Sergunb 0:8918a71cdbe9 1500 {
Sergunb 0:8918a71cdbe9 1501 //Record subnet mask
Sergunb 0:8918a71cdbe9 1502 ipv4CopyAddr(&interface->ipv4Context.subnetMask, option->value);
Sergunb 0:8918a71cdbe9 1503 }
Sergunb 0:8918a71cdbe9 1504
Sergunb 0:8918a71cdbe9 1505 //Retrieve Router option
Sergunb 0:8918a71cdbe9 1506 option = dhcpGetOption(message, length, DHCP_OPT_ROUTER);
Sergunb 0:8918a71cdbe9 1507
Sergunb 0:8918a71cdbe9 1508 //The specified option has been found?
Sergunb 0:8918a71cdbe9 1509 if(option != NULL && !(option->length % sizeof(Ipv4Addr)))
Sergunb 0:8918a71cdbe9 1510 {
Sergunb 0:8918a71cdbe9 1511 //Save default gateway
Sergunb 0:8918a71cdbe9 1512 if(option->length >= sizeof(Ipv4Addr))
Sergunb 0:8918a71cdbe9 1513 ipv4CopyAddr(&interface->ipv4Context.defaultGateway, option->value);
Sergunb 0:8918a71cdbe9 1514 }
Sergunb 0:8918a71cdbe9 1515
Sergunb 0:8918a71cdbe9 1516 //Use the DNS servers provided by the DHCP server?
Sergunb 0:8918a71cdbe9 1517 if(!context->settings.manualDnsConfig)
Sergunb 0:8918a71cdbe9 1518 {
Sergunb 0:8918a71cdbe9 1519 //Retrieve DNS Server option
Sergunb 0:8918a71cdbe9 1520 option = dhcpGetOption(message, length, DHCP_OPT_DNS_SERVER);
Sergunb 0:8918a71cdbe9 1521
Sergunb 0:8918a71cdbe9 1522 //The specified option has been found?
Sergunb 0:8918a71cdbe9 1523 if(option != NULL && !(option->length % sizeof(Ipv4Addr)))
Sergunb 0:8918a71cdbe9 1524 {
Sergunb 0:8918a71cdbe9 1525 //Get the number of addresses provided in the response
Sergunb 0:8918a71cdbe9 1526 n = option->length / sizeof(Ipv4Addr);
Sergunb 0:8918a71cdbe9 1527
Sergunb 0:8918a71cdbe9 1528 //Loop through the list of addresses
Sergunb 0:8918a71cdbe9 1529 for(i = 0; i < n && i < IPV4_DNS_SERVER_LIST_SIZE; i++)
Sergunb 0:8918a71cdbe9 1530 {
Sergunb 0:8918a71cdbe9 1531 //Record DNS server address
Sergunb 0:8918a71cdbe9 1532 ipv4CopyAddr(&interface->ipv4Context.dnsServerList[i],
Sergunb 0:8918a71cdbe9 1533 option->value + i * sizeof(Ipv4Addr));
Sergunb 0:8918a71cdbe9 1534 }
Sergunb 0:8918a71cdbe9 1535 }
Sergunb 0:8918a71cdbe9 1536 }
Sergunb 0:8918a71cdbe9 1537
Sergunb 0:8918a71cdbe9 1538 //Retrieve MTU option
Sergunb 0:8918a71cdbe9 1539 option = dhcpGetOption(message, length, DHCP_OPT_INTERFACE_MTU);
Sergunb 0:8918a71cdbe9 1540
Sergunb 0:8918a71cdbe9 1541 //The specified option has been found?
Sergunb 0:8918a71cdbe9 1542 if(option != NULL && option->length == 2)
Sergunb 0:8918a71cdbe9 1543 {
Sergunb 0:8918a71cdbe9 1544 //This option specifies the MTU to use on this interface
Sergunb 0:8918a71cdbe9 1545 n = LOAD16BE(option->value);
Sergunb 0:8918a71cdbe9 1546
Sergunb 0:8918a71cdbe9 1547 //Make sure that the option's value is acceptable
Sergunb 0:8918a71cdbe9 1548 if(n >= IPV4_MINIMUM_MTU && n <= interface->nicDriver->mtu)
Sergunb 0:8918a71cdbe9 1549 {
Sergunb 0:8918a71cdbe9 1550 //Set the MTU to be used on the interface
Sergunb 0:8918a71cdbe9 1551 interface->ipv4Context.linkMtu = n;
Sergunb 0:8918a71cdbe9 1552 }
Sergunb 0:8918a71cdbe9 1553 }
Sergunb 0:8918a71cdbe9 1554
Sergunb 0:8918a71cdbe9 1555 //Record the IP address of the DHCP server
Sergunb 0:8918a71cdbe9 1556 ipv4CopyAddr(&context->serverIpAddr, serverIdOption->value);
Sergunb 0:8918a71cdbe9 1557 //Record the IP address assigned to the client
Sergunb 0:8918a71cdbe9 1558 context->requestedIpAddr = message->yiaddr;
Sergunb 0:8918a71cdbe9 1559
Sergunb 0:8918a71cdbe9 1560 //Save the time a which the lease was obtained
Sergunb 0:8918a71cdbe9 1561 context->leaseStartTime = osGetSystemTime();
Sergunb 0:8918a71cdbe9 1562
Sergunb 0:8918a71cdbe9 1563 //Check current state
Sergunb 0:8918a71cdbe9 1564 if(context->state == DHCP_STATE_REQUESTING ||
Sergunb 0:8918a71cdbe9 1565 context->state == DHCP_STATE_REBOOTING)
Sergunb 0:8918a71cdbe9 1566 {
Sergunb 0:8918a71cdbe9 1567 //Use the IP address as a tentative address
Sergunb 0:8918a71cdbe9 1568 interface->ipv4Context.addr = message->yiaddr;
Sergunb 0:8918a71cdbe9 1569 interface->ipv4Context.addrState = IPV4_ADDR_STATE_TENTATIVE;
Sergunb 0:8918a71cdbe9 1570
Sergunb 0:8918a71cdbe9 1571 //Clear conflict flag
Sergunb 0:8918a71cdbe9 1572 interface->ipv4Context.addrConflict = FALSE;
Sergunb 0:8918a71cdbe9 1573
Sergunb 0:8918a71cdbe9 1574 //The client should probe the newly received address
Sergunb 0:8918a71cdbe9 1575 dhcpClientChangeState(context, DHCP_STATE_PROBING, 0);
Sergunb 0:8918a71cdbe9 1576 }
Sergunb 0:8918a71cdbe9 1577 else
Sergunb 0:8918a71cdbe9 1578 {
Sergunb 0:8918a71cdbe9 1579 //Assign the IP address to the client
Sergunb 0:8918a71cdbe9 1580 interface->ipv4Context.addr = message->yiaddr;
Sergunb 0:8918a71cdbe9 1581 interface->ipv4Context.addrState = IPV4_ADDR_STATE_VALID;
Sergunb 0:8918a71cdbe9 1582
Sergunb 0:8918a71cdbe9 1583 #if (MDNS_RESPONDER_SUPPORT == ENABLED)
Sergunb 0:8918a71cdbe9 1584 //Restart mDNS probing process
Sergunb 0:8918a71cdbe9 1585 mdnsResponderStartProbing(interface->mdnsResponderContext);
Sergunb 0:8918a71cdbe9 1586 #endif
Sergunb 0:8918a71cdbe9 1587 //The client transitions to the BOUND state
Sergunb 0:8918a71cdbe9 1588 dhcpClientChangeState(context, DHCP_STATE_BOUND, 0);
Sergunb 0:8918a71cdbe9 1589 }
Sergunb 0:8918a71cdbe9 1590 }
Sergunb 0:8918a71cdbe9 1591
Sergunb 0:8918a71cdbe9 1592
Sergunb 0:8918a71cdbe9 1593 /**
Sergunb 0:8918a71cdbe9 1594 * @brief Parse DHCPNAK message
Sergunb 0:8918a71cdbe9 1595 * @param[in] context Pointer to the DHCP client context
Sergunb 0:8918a71cdbe9 1596 * @param[in] message Pointer to the incoming DHCP message
Sergunb 0:8918a71cdbe9 1597 * @param[in] length Length of the incoming message to parse
Sergunb 0:8918a71cdbe9 1598 * @return Error code
Sergunb 0:8918a71cdbe9 1599 **/
Sergunb 0:8918a71cdbe9 1600
Sergunb 0:8918a71cdbe9 1601 void dhcpClientParseNak(DhcpClientContext *context,
Sergunb 0:8918a71cdbe9 1602 const DhcpMessage *message, size_t length)
Sergunb 0:8918a71cdbe9 1603 {
Sergunb 0:8918a71cdbe9 1604 DhcpOption *serverIdOption;
Sergunb 0:8918a71cdbe9 1605 NetInterface *interface;
Sergunb 0:8918a71cdbe9 1606
Sergunb 0:8918a71cdbe9 1607 //Point to the underlying network interface
Sergunb 0:8918a71cdbe9 1608 interface = context->settings.interface;
Sergunb 0:8918a71cdbe9 1609
Sergunb 0:8918a71cdbe9 1610 //Discard any received packet that does not match the transaction ID
Sergunb 0:8918a71cdbe9 1611 if(ntohl(message->xid) != context->transactionId)
Sergunb 0:8918a71cdbe9 1612 return;
Sergunb 0:8918a71cdbe9 1613 //Check MAC address
Sergunb 0:8918a71cdbe9 1614 if(!macCompAddr(&message->chaddr, &interface->macAddr))
Sergunb 0:8918a71cdbe9 1615 return;
Sergunb 0:8918a71cdbe9 1616
Sergunb 0:8918a71cdbe9 1617 //A DHCP server always returns its own address in the Server Identifier option
Sergunb 0:8918a71cdbe9 1618 serverIdOption = dhcpGetOption(message, length, DHCP_OPT_SERVER_IDENTIFIER);
Sergunb 0:8918a71cdbe9 1619
Sergunb 0:8918a71cdbe9 1620 //Failed to retrieve the Server Identifier option?
Sergunb 0:8918a71cdbe9 1621 if(serverIdOption == NULL || serverIdOption->length != 4)
Sergunb 0:8918a71cdbe9 1622 return;
Sergunb 0:8918a71cdbe9 1623
Sergunb 0:8918a71cdbe9 1624 //Check current state
Sergunb 0:8918a71cdbe9 1625 if(context->state == DHCP_STATE_REQUESTING ||
Sergunb 0:8918a71cdbe9 1626 context->state == DHCP_STATE_RENEWING)
Sergunb 0:8918a71cdbe9 1627 {
Sergunb 0:8918a71cdbe9 1628 //Check the server identifier
Sergunb 0:8918a71cdbe9 1629 if(!ipv4CompAddr(serverIdOption->value, &context->serverIpAddr))
Sergunb 0:8918a71cdbe9 1630 return;
Sergunb 0:8918a71cdbe9 1631 }
Sergunb 0:8918a71cdbe9 1632 else if(context->state == DHCP_STATE_REBOOTING ||
Sergunb 0:8918a71cdbe9 1633 context->state == DHCP_STATE_REBINDING)
Sergunb 0:8918a71cdbe9 1634 {
Sergunb 0:8918a71cdbe9 1635 //Do not check the server identifier
Sergunb 0:8918a71cdbe9 1636 }
Sergunb 0:8918a71cdbe9 1637 else
Sergunb 0:8918a71cdbe9 1638 {
Sergunb 0:8918a71cdbe9 1639 //Silently discard the DHCPNAK message
Sergunb 0:8918a71cdbe9 1640 return;
Sergunb 0:8918a71cdbe9 1641 }
Sergunb 0:8918a71cdbe9 1642
Sergunb 0:8918a71cdbe9 1643 //The host address is no longer appropriate for the link
Sergunb 0:8918a71cdbe9 1644 interface->ipv4Context.addr = IPV4_UNSPECIFIED_ADDR;
Sergunb 0:8918a71cdbe9 1645 interface->ipv4Context.addrState = IPV4_ADDR_STATE_INVALID;
Sergunb 0:8918a71cdbe9 1646
Sergunb 0:8918a71cdbe9 1647 //Clear subnet mask
Sergunb 0:8918a71cdbe9 1648 interface->ipv4Context.subnetMask = IPV4_UNSPECIFIED_ADDR;
Sergunb 0:8918a71cdbe9 1649
Sergunb 0:8918a71cdbe9 1650 #if (MDNS_RESPONDER_SUPPORT == ENABLED)
Sergunb 0:8918a71cdbe9 1651 //Restart mDNS probing process
Sergunb 0:8918a71cdbe9 1652 mdnsResponderStartProbing(interface->mdnsResponderContext);
Sergunb 0:8918a71cdbe9 1653 #endif
Sergunb 0:8918a71cdbe9 1654
Sergunb 0:8918a71cdbe9 1655 //Restart DHCP configuration
Sergunb 0:8918a71cdbe9 1656 dhcpClientChangeState(context, DHCP_STATE_INIT, 0);
Sergunb 0:8918a71cdbe9 1657 }
Sergunb 0:8918a71cdbe9 1658
Sergunb 0:8918a71cdbe9 1659
Sergunb 0:8918a71cdbe9 1660 /**
Sergunb 0:8918a71cdbe9 1661 * @brief Manage DHCP configuration timeout
Sergunb 0:8918a71cdbe9 1662 * @param[in] context Pointer to the DHCP client context
Sergunb 0:8918a71cdbe9 1663 **/
Sergunb 0:8918a71cdbe9 1664
Sergunb 0:8918a71cdbe9 1665 void dhcpClientCheckTimeout(DhcpClientContext *context)
Sergunb 0:8918a71cdbe9 1666 {
Sergunb 0:8918a71cdbe9 1667 systime_t time;
Sergunb 0:8918a71cdbe9 1668 NetInterface *interface;
Sergunb 0:8918a71cdbe9 1669
Sergunb 0:8918a71cdbe9 1670 //Point to the underlying network interface
Sergunb 0:8918a71cdbe9 1671 interface = context->settings.interface;
Sergunb 0:8918a71cdbe9 1672
Sergunb 0:8918a71cdbe9 1673 //Get current time
Sergunb 0:8918a71cdbe9 1674 time = osGetSystemTime();
Sergunb 0:8918a71cdbe9 1675
Sergunb 0:8918a71cdbe9 1676 //Any registered callback?
Sergunb 0:8918a71cdbe9 1677 if(context->settings.timeoutEvent != NULL)
Sergunb 0:8918a71cdbe9 1678 {
Sergunb 0:8918a71cdbe9 1679 //DHCP configuration timeout?
Sergunb 0:8918a71cdbe9 1680 if(timeCompare(time, context->configStartTime + context->settings.timeout) >= 0)
Sergunb 0:8918a71cdbe9 1681 {
Sergunb 0:8918a71cdbe9 1682 //Ensure the callback function is only called once
Sergunb 0:8918a71cdbe9 1683 if(!context->timeoutEventDone)
Sergunb 0:8918a71cdbe9 1684 {
Sergunb 0:8918a71cdbe9 1685 //Release exclusive access
Sergunb 0:8918a71cdbe9 1686 osReleaseMutex(&netMutex);
Sergunb 0:8918a71cdbe9 1687 //Invoke user callback function
Sergunb 0:8918a71cdbe9 1688 context->settings.timeoutEvent(context, interface);
Sergunb 0:8918a71cdbe9 1689 //Get exclusive access
Sergunb 0:8918a71cdbe9 1690 osAcquireMutex(&netMutex);
Sergunb 0:8918a71cdbe9 1691
Sergunb 0:8918a71cdbe9 1692 //Set flag
Sergunb 0:8918a71cdbe9 1693 context->timeoutEventDone = TRUE;
Sergunb 0:8918a71cdbe9 1694 }
Sergunb 0:8918a71cdbe9 1695 }
Sergunb 0:8918a71cdbe9 1696 }
Sergunb 0:8918a71cdbe9 1697 }
Sergunb 0:8918a71cdbe9 1698
Sergunb 0:8918a71cdbe9 1699
Sergunb 0:8918a71cdbe9 1700 /**
Sergunb 0:8918a71cdbe9 1701 * @brief Compute the appropriate secs field
Sergunb 0:8918a71cdbe9 1702 *
Sergunb 0:8918a71cdbe9 1703 * Compute the number of seconds elapsed since the client began
Sergunb 0:8918a71cdbe9 1704 * address acquisition or renewal process
Sergunb 0:8918a71cdbe9 1705 *
Sergunb 0:8918a71cdbe9 1706 * @param[in] context Pointer to the DHCP client context
Sergunb 0:8918a71cdbe9 1707 * @return The elapsed time expressed in seconds
Sergunb 0:8918a71cdbe9 1708 **/
Sergunb 0:8918a71cdbe9 1709
Sergunb 0:8918a71cdbe9 1710 uint16_t dhcpClientComputeElapsedTime(DhcpClientContext *context)
Sergunb 0:8918a71cdbe9 1711 {
Sergunb 0:8918a71cdbe9 1712 systime_t time;
Sergunb 0:8918a71cdbe9 1713
Sergunb 0:8918a71cdbe9 1714 //Compute the time elapsed since the DHCP configuration process started
Sergunb 0:8918a71cdbe9 1715 time = (osGetSystemTime() - context->configStartTime) / 1000;
Sergunb 0:8918a71cdbe9 1716
Sergunb 0:8918a71cdbe9 1717 //The value 0xFFFF is used to represent any elapsed time values
Sergunb 0:8918a71cdbe9 1718 //greater than the largest time value that can be represented
Sergunb 0:8918a71cdbe9 1719 time = MIN(time, 0xFFFF);
Sergunb 0:8918a71cdbe9 1720
Sergunb 0:8918a71cdbe9 1721 //Convert the 16-bit value to network byte order
Sergunb 0:8918a71cdbe9 1722 return htons(time);
Sergunb 0:8918a71cdbe9 1723 }
Sergunb 0:8918a71cdbe9 1724
Sergunb 0:8918a71cdbe9 1725
Sergunb 0:8918a71cdbe9 1726 /**
Sergunb 0:8918a71cdbe9 1727 * @brief Update DHCP FSM state
Sergunb 0:8918a71cdbe9 1728 * @param[in] context Pointer to the DHCP client context
Sergunb 0:8918a71cdbe9 1729 * @param[in] newState New DHCP state to switch to
Sergunb 0:8918a71cdbe9 1730 * @param[in] delay Initial delay
Sergunb 0:8918a71cdbe9 1731 **/
Sergunb 0:8918a71cdbe9 1732
Sergunb 0:8918a71cdbe9 1733 void dhcpClientChangeState(DhcpClientContext *context,
Sergunb 0:8918a71cdbe9 1734 DhcpState newState, systime_t delay)
Sergunb 0:8918a71cdbe9 1735 {
Sergunb 0:8918a71cdbe9 1736 systime_t time;
Sergunb 0:8918a71cdbe9 1737
Sergunb 0:8918a71cdbe9 1738 //Get current time
Sergunb 0:8918a71cdbe9 1739 time = osGetSystemTime();
Sergunb 0:8918a71cdbe9 1740
Sergunb 0:8918a71cdbe9 1741 #if (DHCP_TRACE_LEVEL >= TRACE_LEVEL_INFO)
Sergunb 0:8918a71cdbe9 1742 //Sanity check
Sergunb 0:8918a71cdbe9 1743 if(newState <= DHCP_STATE_REBINDING)
Sergunb 0:8918a71cdbe9 1744 {
Sergunb 0:8918a71cdbe9 1745 //DHCP FSM states
Sergunb 0:8918a71cdbe9 1746 static const char_t *stateLabel[] =
Sergunb 0:8918a71cdbe9 1747 {
Sergunb 0:8918a71cdbe9 1748 "INIT",
Sergunb 0:8918a71cdbe9 1749 "SELECTING",
Sergunb 0:8918a71cdbe9 1750 "REQUESTING",
Sergunb 0:8918a71cdbe9 1751 "INIT-REBOOT",
Sergunb 0:8918a71cdbe9 1752 "REBOOTING",
Sergunb 0:8918a71cdbe9 1753 "PROBING",
Sergunb 0:8918a71cdbe9 1754 "BOUND",
Sergunb 0:8918a71cdbe9 1755 "RENEWING",
Sergunb 0:8918a71cdbe9 1756 "REBINDING"
Sergunb 0:8918a71cdbe9 1757 };
Sergunb 0:8918a71cdbe9 1758
Sergunb 0:8918a71cdbe9 1759 //Debug message
Sergunb 0:8918a71cdbe9 1760 TRACE_INFO("%s: DHCP client %s state\r\n",
Sergunb 0:8918a71cdbe9 1761 formatSystemTime(time, NULL), stateLabel[newState]);
Sergunb 0:8918a71cdbe9 1762 }
Sergunb 0:8918a71cdbe9 1763 #endif
Sergunb 0:8918a71cdbe9 1764
Sergunb 0:8918a71cdbe9 1765 //Set time stamp
Sergunb 0:8918a71cdbe9 1766 context->timestamp = time;
Sergunb 0:8918a71cdbe9 1767 //Set initial delay
Sergunb 0:8918a71cdbe9 1768 context->timeout = delay;
Sergunb 0:8918a71cdbe9 1769 //Reset retransmission counter
Sergunb 0:8918a71cdbe9 1770 context->retransmitCount = 0;
Sergunb 0:8918a71cdbe9 1771 //Switch to the new state
Sergunb 0:8918a71cdbe9 1772 context->state = newState;
Sergunb 0:8918a71cdbe9 1773
Sergunb 0:8918a71cdbe9 1774 //Any registered callback?
Sergunb 0:8918a71cdbe9 1775 if(context->settings.stateChangeEvent != NULL)
Sergunb 0:8918a71cdbe9 1776 {
Sergunb 0:8918a71cdbe9 1777 NetInterface *interface;
Sergunb 0:8918a71cdbe9 1778
Sergunb 0:8918a71cdbe9 1779 //Point to the underlying network interface
Sergunb 0:8918a71cdbe9 1780 interface = context->settings.interface;
Sergunb 0:8918a71cdbe9 1781
Sergunb 0:8918a71cdbe9 1782 //Release exclusive access
Sergunb 0:8918a71cdbe9 1783 osReleaseMutex(&netMutex);
Sergunb 0:8918a71cdbe9 1784 //Invoke user callback function
Sergunb 0:8918a71cdbe9 1785 context->settings.stateChangeEvent(context, interface, newState);
Sergunb 0:8918a71cdbe9 1786 //Get exclusive access
Sergunb 0:8918a71cdbe9 1787 osAcquireMutex(&netMutex);
Sergunb 0:8918a71cdbe9 1788 }
Sergunb 0:8918a71cdbe9 1789 }
Sergunb 0:8918a71cdbe9 1790
Sergunb 0:8918a71cdbe9 1791
Sergunb 0:8918a71cdbe9 1792 /**
Sergunb 0:8918a71cdbe9 1793 * @brief Dump DHCP configuration for debugging purpose
Sergunb 0:8918a71cdbe9 1794 * @param[in] context Pointer to the DHCP client context
Sergunb 0:8918a71cdbe9 1795 **/
Sergunb 0:8918a71cdbe9 1796
Sergunb 0:8918a71cdbe9 1797 void dhcpClientDumpConfig(DhcpClientContext *context)
Sergunb 0:8918a71cdbe9 1798 {
Sergunb 0:8918a71cdbe9 1799 #if (DHCP_TRACE_LEVEL >= TRACE_LEVEL_INFO)
Sergunb 0:8918a71cdbe9 1800 uint_t i;
Sergunb 0:8918a71cdbe9 1801 NetInterface *interface;
Sergunb 0:8918a71cdbe9 1802 Ipv4Context *ipv4Context;
Sergunb 0:8918a71cdbe9 1803
Sergunb 0:8918a71cdbe9 1804 //Point to the underlying network interface
Sergunb 0:8918a71cdbe9 1805 interface = context->settings.interface;
Sergunb 0:8918a71cdbe9 1806 //Point to the IPv4 context
Sergunb 0:8918a71cdbe9 1807 ipv4Context = &interface->ipv4Context;
Sergunb 0:8918a71cdbe9 1808
Sergunb 0:8918a71cdbe9 1809 //Debug message
Sergunb 0:8918a71cdbe9 1810 TRACE_INFO("\r\n");
Sergunb 0:8918a71cdbe9 1811 TRACE_INFO("DHCP configuration:\r\n");
Sergunb 0:8918a71cdbe9 1812
Sergunb 0:8918a71cdbe9 1813 //Lease start time
Sergunb 0:8918a71cdbe9 1814 TRACE_INFO(" Lease Start Time = %s\r\n",
Sergunb 0:8918a71cdbe9 1815 formatSystemTime(context->leaseStartTime, NULL));
Sergunb 0:8918a71cdbe9 1816
Sergunb 0:8918a71cdbe9 1817 //Lease time
Sergunb 0:8918a71cdbe9 1818 TRACE_INFO(" Lease Time = %" PRIu32 "s\r\n", context->leaseTime);
Sergunb 0:8918a71cdbe9 1819 //Renewal time
Sergunb 0:8918a71cdbe9 1820 TRACE_INFO(" T1 = %" PRIu32 "s\r\n", context->t1);
Sergunb 0:8918a71cdbe9 1821 //Rebinding time
Sergunb 0:8918a71cdbe9 1822 TRACE_INFO(" T2 = %" PRIu32 "s\r\n", context->t2);
Sergunb 0:8918a71cdbe9 1823
Sergunb 0:8918a71cdbe9 1824 //Host address
Sergunb 0:8918a71cdbe9 1825 TRACE_INFO(" IPv4 Address = %s\r\n",
Sergunb 0:8918a71cdbe9 1826 ipv4AddrToString(ipv4Context->addr, NULL));
Sergunb 0:8918a71cdbe9 1827
Sergunb 0:8918a71cdbe9 1828 //Subnet mask
Sergunb 0:8918a71cdbe9 1829 TRACE_INFO(" Subnet Mask = %s\r\n",
Sergunb 0:8918a71cdbe9 1830 ipv4AddrToString(ipv4Context->subnetMask, NULL));
Sergunb 0:8918a71cdbe9 1831
Sergunb 0:8918a71cdbe9 1832 //Default gateway
Sergunb 0:8918a71cdbe9 1833 TRACE_INFO(" Default Gateway = %s\r\n",
Sergunb 0:8918a71cdbe9 1834 ipv4AddrToString(ipv4Context->defaultGateway, NULL));
Sergunb 0:8918a71cdbe9 1835
Sergunb 0:8918a71cdbe9 1836 //DNS servers
Sergunb 0:8918a71cdbe9 1837 for(i = 0; i < IPV4_DNS_SERVER_LIST_SIZE; i++)
Sergunb 0:8918a71cdbe9 1838 {
Sergunb 0:8918a71cdbe9 1839 TRACE_INFO(" DNS Server %u = %s\r\n", i + 1,
Sergunb 0:8918a71cdbe9 1840 ipv4AddrToString(ipv4Context->dnsServerList[i], NULL));
Sergunb 0:8918a71cdbe9 1841 }
Sergunb 0:8918a71cdbe9 1842
Sergunb 0:8918a71cdbe9 1843 //Maximum transmit unit
Sergunb 0:8918a71cdbe9 1844 TRACE_INFO(" MTU = %" PRIuSIZE "\r\n", interface->ipv4Context.linkMtu);
Sergunb 0:8918a71cdbe9 1845 TRACE_INFO("\r\n");
Sergunb 0:8918a71cdbe9 1846 #endif
Sergunb 0:8918a71cdbe9 1847 }
Sergunb 0:8918a71cdbe9 1848
Sergunb 0:8918a71cdbe9 1849 #endif
Sergunb 0:8918a71cdbe9 1850