Webserver+3d print
Embed:
(wiki syntax)
Show/hide line numbers
auto_ip.c
Go to the documentation of this file.
00001 /** 00002 * @file auto_ip.c 00003 * @brief Auto-IP (Dynamic Configuration of IPv4 Link-Local Addresses) 00004 * 00005 * @section License 00006 * 00007 * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved. 00008 * 00009 * This file is part of CycloneTCP Open. 00010 * 00011 * This program is free software; you can redistribute it and/or 00012 * modify it under the terms of the GNU General Public License 00013 * as published by the Free Software Foundation; either version 2 00014 * of the License, or (at your option) any later version. 00015 * 00016 * This program is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 * GNU General Public License for more details. 00020 * 00021 * You should have received a copy of the GNU General Public License 00022 * along with this program; if not, write to the Free Software Foundation, 00023 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00024 * 00025 * @section Description 00026 * 00027 * Auto-IP describes a method by which a host may automatically configure an 00028 * interface with an IPv4 address in the 169.254/16 prefix that is valid for 00029 * Link-Local communication on that interface. This is especially valuable in 00030 * environments where no other configuration mechanism is available. Refer to 00031 * the following RFCs for complete details: 00032 * - RFC 3927: Dynamic Configuration of IPv4 Link-Local Addresses 00033 * - RFC 5227: IPv4 Address Conflict Detection 00034 * 00035 * @author Oryx Embedded SARL (www.oryx-embedded.com) 00036 * @version 1.7.6 00037 **/ 00038 00039 //Switch to the appropriate trace level 00040 #define TRACE_LEVEL AUTO_IP_TRACE_LEVEL 00041 00042 //Dependencies 00043 #include "core/net.h" 00044 #include "core/ethernet.h" 00045 #include "ipv4/arp.h" 00046 #include "ipv4/auto_ip.h" 00047 #include "mdns/mdns_responder.h" 00048 #include "debug.h" 00049 00050 //Check TCP/IP stack configuration 00051 #if (IPV4_SUPPORT == ENABLED && AUTO_IP_SUPPORT == ENABLED) 00052 00053 //Tick counter to handle periodic operations 00054 systime_t autoIpTickCounter; 00055 00056 00057 /** 00058 * @brief Initialize settings with default values 00059 * @param[out] settings Structure that contains Auto-IP settings 00060 **/ 00061 00062 void autoIpGetDefaultSettings(AutoIpSettings *settings) 00063 { 00064 //Use default interface 00065 settings->interface = netGetDefaultInterface(); 00066 00067 //Initial link-local address to be used 00068 settings->linkLocalAddr = IPV4_UNSPECIFIED_ADDR; 00069 //Link state change event 00070 settings->linkChangeEvent = NULL; 00071 //FSM state change event 00072 settings->stateChangeEvent = NULL; 00073 } 00074 00075 00076 /** 00077 * @brief Auto-IP initialization 00078 * @param[in] context Pointer to the Auto-IP context 00079 * @param[in] settings Auto-IP specific settings 00080 * @return Error code 00081 **/ 00082 00083 error_t autoIpInit(AutoIpContext *context, const AutoIpSettings *settings) 00084 { 00085 NetInterface *interface; 00086 00087 //Debug message 00088 TRACE_INFO("Initializing Auto-IP...\r\n"); 00089 00090 //Ensure the parameters are valid 00091 if(context == NULL || settings == NULL) 00092 return ERROR_INVALID_PARAMETER; 00093 00094 //A valid pointer to the interface being configured is required 00095 if(settings->interface == NULL) 00096 return ERROR_INVALID_PARAMETER; 00097 00098 //Point to the underlying network interface 00099 interface = settings->interface; 00100 00101 //Clear the Auto-IP context 00102 memset(context, 0, sizeof(AutoIpContext)); 00103 //Save user settings 00104 context->settings = *settings; 00105 00106 //Use default link-local address 00107 context->linkLocalAddr = settings->linkLocalAddr; 00108 //Reset conflict counter 00109 context->conflictCount = 0; 00110 00111 //Auto-IP operation is currently suspended 00112 context->running = FALSE; 00113 //Initialize state machine 00114 context->state = AUTO_IP_STATE_INIT; 00115 00116 //Attach the Auto-IP context to the network interface 00117 interface->autoIpContext = context; 00118 00119 //Successful initialization 00120 return NO_ERROR; 00121 } 00122 00123 00124 /** 00125 * @brief Start Auto-IP process 00126 * @param[in] context Pointer to the Auto-IP context 00127 * @return Error code 00128 **/ 00129 00130 error_t autoIpStart(AutoIpContext *context) 00131 { 00132 //Check parameter 00133 if(context == NULL) 00134 return ERROR_INVALID_PARAMETER; 00135 00136 //Debug message 00137 TRACE_INFO("Starting Auto-IP...\r\n"); 00138 00139 //Get exclusive access 00140 osAcquireMutex(&netMutex); 00141 00142 //Start Auto-IP operation 00143 context->running = TRUE; 00144 //Initialize state machine 00145 context->state = AUTO_IP_STATE_INIT; 00146 //Reset conflict counter 00147 context->conflictCount = 0; 00148 00149 //Release exclusive access 00150 osReleaseMutex(&netMutex); 00151 00152 //Successful processing 00153 return NO_ERROR; 00154 } 00155 00156 00157 /** 00158 * @brief Stop Auto-IP process 00159 * @param[in] context Pointer to the Auto-IP context 00160 * @return Error code 00161 **/ 00162 00163 error_t autoIpStop(AutoIpContext *context) 00164 { 00165 //Check parameter 00166 if(context == NULL) 00167 return ERROR_INVALID_PARAMETER; 00168 00169 //Debug message 00170 TRACE_INFO("Stopping Auto-IP...\r\n"); 00171 00172 //Get exclusive access 00173 osAcquireMutex(&netMutex); 00174 00175 //Suspend Auto-IP operation 00176 context->running = FALSE; 00177 //Reinitialize state machine 00178 context->state = AUTO_IP_STATE_INIT; 00179 00180 //Release exclusive access 00181 osReleaseMutex(&netMutex); 00182 00183 //Successful processing 00184 return NO_ERROR; 00185 } 00186 00187 00188 /** 00189 * @brief Retrieve current state 00190 * @param[in] context Pointer to the Auto-IP context 00191 * @return Current Auto-IP state 00192 **/ 00193 00194 AutoIpState autoIpGetState(AutoIpContext *context) 00195 { 00196 AutoIpState state; 00197 00198 //Get exclusive access 00199 osAcquireMutex(&netMutex); 00200 //Get current state 00201 state = context->state; 00202 //Release exclusive access 00203 osReleaseMutex(&netMutex); 00204 00205 //Return current state 00206 return state; 00207 } 00208 00209 00210 /** 00211 * @brief Auto-IP timer handler 00212 * 00213 * This routine must be periodically called by the TCP/IP stack to 00214 * manage Auto-IP operation 00215 * 00216 * @param[in] context Pointer to the Auto-IP context 00217 **/ 00218 00219 void autoIpTick(AutoIpContext *context) 00220 { 00221 systime_t time; 00222 systime_t delay; 00223 NetInterface *interface; 00224 00225 //Make sure Auto-IP has been properly instantiated 00226 if(context == NULL) 00227 return; 00228 00229 //Point to the underlying network interface 00230 interface = context->settings.interface; 00231 00232 //Get current time 00233 time = osGetSystemTime(); 00234 00235 //Check current state 00236 if(context->state == AUTO_IP_STATE_INIT) 00237 { 00238 //Wait for the link to be up before starting Auto-IP 00239 if(context->running && interface->linkState) 00240 { 00241 //Configure subnet mask 00242 interface->ipv4Context.subnetMask = AUTO_IP_MASK; 00243 00244 //The address must be in the range from 169.54.1.0 to 169.254.254.255 00245 if(ntohl(context->linkLocalAddr) < ntohl(AUTO_IP_ADDR_MIN) || 00246 ntohl(context->linkLocalAddr) > ntohl(AUTO_IP_ADDR_MAX)) 00247 { 00248 //Generate a random link-local address 00249 autoIpGenerateAddr(&context->linkLocalAddr); 00250 } 00251 00252 //Use the link-local address as a tentative address 00253 interface->ipv4Context.addr = context->linkLocalAddr; 00254 interface->ipv4Context.addrState = IPV4_ADDR_STATE_TENTATIVE; 00255 00256 //Clear conflict flag 00257 interface->ipv4Context.addrConflict = FALSE; 00258 00259 //Initial random delay 00260 delay = netGetRandRange(0, AUTO_IP_PROBE_WAIT); 00261 00262 //The number of conflicts exceeds the maximum acceptable value? 00263 if(context->conflictCount >= AUTO_IP_MAX_CONFLICTS) 00264 { 00265 //The host must limit the rate at which it probes for new addresses 00266 delay += AUTO_IP_RATE_LIMIT_INTERVAL; 00267 } 00268 00269 //Verify the uniqueness of the link-local address 00270 autoIpChangeState(context, AUTO_IP_STATE_PROBING, delay); 00271 } 00272 } 00273 else if(context->state == AUTO_IP_STATE_PROBING) 00274 { 00275 //Any conflict detected? 00276 if(interface->ipv4Context.addrConflict) 00277 { 00278 //The address is already in use by some other host and 00279 //must not be assigned to the interface 00280 interface->ipv4Context.addr = IPV4_UNSPECIFIED_ADDR; 00281 interface->ipv4Context.addrState = IPV4_ADDR_STATE_INVALID; 00282 00283 //The host should maintain a counter of the number of address 00284 //conflicts it has experienced 00285 context->conflictCount++; 00286 00287 //The host must pick a new random address... 00288 autoIpGenerateAddr(&context->linkLocalAddr); 00289 //...and repeat the process 00290 autoIpChangeState(context, AUTO_IP_STATE_INIT, 0); 00291 } 00292 else 00293 { 00294 //Check current time 00295 if(timeCompare(time, context->timestamp + context->timeout) >= 0) 00296 { 00297 //Address Conflict Detection is on-going? 00298 if(context->retransmitCount < AUTO_IP_PROBE_NUM) 00299 { 00300 //Conflict detection is done using ARP probes 00301 arpSendProbe(interface, context->linkLocalAddr); 00302 00303 //Save the time at which the packet was sent 00304 context->timestamp = time; 00305 //Increment retransmission counter 00306 context->retransmitCount++; 00307 00308 //Last probe packet sent? 00309 if(context->retransmitCount == AUTO_IP_PROBE_NUM) 00310 { 00311 //Delay before announcing 00312 context->timeout = AUTO_IP_ANNOUNCE_WAIT; 00313 } 00314 else 00315 { 00316 //Maximum delay till repeated probe 00317 context->timeout = netGetRandRange(AUTO_IP_PROBE_MIN, 00318 AUTO_IP_PROBE_MAX); 00319 } 00320 } 00321 else 00322 { 00323 //The use of the IPv4 address is now unrestricted 00324 interface->ipv4Context.addrState = IPV4_ADDR_STATE_VALID; 00325 00326 #if (MDNS_RESPONDER_SUPPORT == ENABLED) 00327 //Restart mDNS probing process 00328 mdnsResponderStartProbing(interface->mdnsResponderContext); 00329 #endif 00330 //The host must then announce its claimed address 00331 autoIpChangeState(context, AUTO_IP_STATE_ANNOUNCING, 0); 00332 } 00333 } 00334 } 00335 } 00336 else if(context->state == AUTO_IP_STATE_ANNOUNCING) 00337 { 00338 //Check current time 00339 if(timeCompare(time, context->timestamp + context->timeout) >= 0) 00340 { 00341 //An ARP announcement is identical to an ARP probe, except that 00342 //now the sender and target IP addresses are both set to the 00343 //host's newly selected IPv4 address 00344 arpSendRequest(interface, context->linkLocalAddr, &MAC_BROADCAST_ADDR); 00345 00346 //Save the time at which the packet was sent 00347 context->timestamp = time; 00348 //Time interval between announcement packets 00349 context->timeout = AUTO_IP_ANNOUNCE_INTERVAL; 00350 //Increment retransmission counter 00351 context->retransmitCount++; 00352 00353 //Announcing is complete? 00354 if(context->retransmitCount >= AUTO_IP_ANNOUNCE_NUM) 00355 { 00356 //Successful address autoconfiguration 00357 autoIpChangeState(context, AUTO_IP_STATE_CONFIGURED, 0); 00358 //Reset conflict counter 00359 context->conflictCount = 0; 00360 00361 //Dump current IPv4 configuration for debugging purpose 00362 autoIpDumpConfig(context); 00363 } 00364 } 00365 } 00366 else if(context->state == AUTO_IP_STATE_CONFIGURED) 00367 { 00368 //Address Conflict Detection is an ongoing process that is in effect 00369 //for as long as a host is using an IPv4 link-local address 00370 if(interface->ipv4Context.addrConflict) 00371 { 00372 //The host may elect to attempt to defend its address by recording 00373 //the time that the conflicting ARP packet was received, and then 00374 //broadcasting one single ARP announcement, giving its own IP and 00375 //hardware addresses as the sender addresses of the ARP 00376 #if (AUTO_IP_BCT_SUPPORT == ENABLED) 00377 arpSendProbe(interface, context->linkLocalAddr); 00378 #else 00379 arpSendRequest(interface, context->linkLocalAddr, &MAC_BROADCAST_ADDR); 00380 #endif 00381 //Clear conflict flag 00382 interface->ipv4Context.addrConflict = FALSE; 00383 00384 //The host can then continue to use the address normally without 00385 //any further special action 00386 autoIpChangeState(context, AUTO_IP_STATE_DEFENDING, 0); 00387 } 00388 } 00389 else if(context->state == AUTO_IP_STATE_DEFENDING) 00390 { 00391 //if this is not the first conflicting ARP packet the host has seen, and 00392 //the time recorded for the previous conflicting ARP packet is recent, 00393 //within DEFEND_INTERVAL seconds, then the host must immediately cease 00394 //using this address 00395 if(interface->ipv4Context.addrConflict) 00396 { 00397 //The link-local address cannot be used anymore 00398 interface->ipv4Context.addr = IPV4_UNSPECIFIED_ADDR; 00399 interface->ipv4Context.addrState = IPV4_ADDR_STATE_INVALID; 00400 00401 #if (MDNS_RESPONDER_SUPPORT == ENABLED) 00402 //Restart mDNS probing process 00403 mdnsResponderStartProbing(interface->mdnsResponderContext); 00404 #endif 00405 //The host must pick a new random address... 00406 autoIpGenerateAddr(&context->linkLocalAddr); 00407 //...and probes/announces again 00408 autoIpChangeState(context, AUTO_IP_STATE_INIT, 0); 00409 } 00410 else 00411 { 00412 //Check whether the DEFEND_INTERVAL has elapsed 00413 if(timeCompare(time, context->timestamp + AUTO_IP_DEFEND_INTERVAL) >= 0) 00414 { 00415 //The host can continue to use its link-local address 00416 autoIpChangeState(context, AUTO_IP_STATE_CONFIGURED, 0); 00417 } 00418 } 00419 } 00420 } 00421 00422 00423 /** 00424 * @brief Callback function for link change event 00425 * @param[in] context Pointer to the Auto-IP context 00426 **/ 00427 00428 void autoIpLinkChangeEvent(AutoIpContext *context) 00429 { 00430 NetInterface *interface; 00431 00432 //Make sure Auto-IP has been properly instantiated 00433 if(context == NULL) 00434 return; 00435 00436 //Point to the underlying network interface 00437 interface = context->settings.interface; 00438 00439 //Check whether Auto-IP is enabled 00440 if(context->running) 00441 { 00442 //The host address is not longer valid 00443 interface->ipv4Context.addr = IPV4_UNSPECIFIED_ADDR; 00444 interface->ipv4Context.addrState = IPV4_ADDR_STATE_INVALID; 00445 00446 #if (MDNS_RESPONDER_SUPPORT == ENABLED) 00447 //Restart mDNS probing process 00448 mdnsResponderStartProbing(interface->mdnsResponderContext); 00449 #endif 00450 00451 //Clear subnet mask 00452 interface->ipv4Context.subnetMask = IPV4_UNSPECIFIED_ADDR; 00453 } 00454 00455 //Reinitialize state machine 00456 context->state = AUTO_IP_STATE_INIT; 00457 //Reset conflict counter 00458 context->conflictCount = 0; 00459 00460 //Any registered callback? 00461 if(context->settings.linkChangeEvent != NULL) 00462 { 00463 //Release exclusive access 00464 osReleaseMutex(&netMutex); 00465 //Invoke user callback function 00466 context->settings.linkChangeEvent(context, interface, interface->linkState); 00467 //Get exclusive access 00468 osAcquireMutex(&netMutex); 00469 } 00470 } 00471 00472 00473 /** 00474 * @brief Update Auto-IP FSM state 00475 * @param[in] context Pointer to the Auto-IP context 00476 * @param[in] newState New Auto-IP state to switch to 00477 * @param[in] delay Initial delay 00478 **/ 00479 00480 void autoIpChangeState(AutoIpContext *context, 00481 AutoIpState newState, systime_t delay) 00482 { 00483 NetInterface *interface; 00484 00485 //Point to the underlying network interface 00486 interface = context->settings.interface; 00487 00488 //Set time stamp 00489 context->timestamp = osGetSystemTime(); 00490 //Set initial delay 00491 context->timeout = delay; 00492 //Reset retransmission counter 00493 context->retransmitCount = 0; 00494 //Switch to the new state 00495 context->state = newState; 00496 00497 //Any registered callback? 00498 if(context->settings.stateChangeEvent != NULL) 00499 { 00500 //Release exclusive access 00501 osReleaseMutex(&netMutex); 00502 //Invoke user callback function 00503 context->settings.stateChangeEvent(context, interface, newState); 00504 //Get exclusive access 00505 osAcquireMutex(&netMutex); 00506 } 00507 } 00508 00509 00510 /** 00511 * @brief Generate a random link-local address 00512 * @param[out] ipAddr Random link-local address 00513 **/ 00514 00515 void autoIpGenerateAddr(Ipv4Addr *ipAddr) 00516 { 00517 uint32_t n; 00518 00519 //Generate a random address in the range from 169.254.1.0 to 169.254.254.255 00520 n = netGetRand() % ntohl(AUTO_IP_ADDR_MAX - AUTO_IP_ADDR_MIN); 00521 n += ntohl(AUTO_IP_ADDR_MIN); 00522 00523 //Convert the resulting address to network byte order 00524 *ipAddr = htonl(n); 00525 } 00526 00527 00528 /** 00529 * @brief Dump Auto-IP configuration for debugging purpose 00530 * @param[in] context Pointer to the Auto-IP context 00531 **/ 00532 00533 void autoIpDumpConfig(AutoIpContext *context) 00534 { 00535 #if (AUTO_IP_TRACE_LEVEL >= TRACE_LEVEL_INFO) 00536 NetInterface *interface; 00537 Ipv4Context *ipv4Context; 00538 00539 //Point to the underlying network interface 00540 interface = context->settings.interface; 00541 //Point to the IPv4 context 00542 ipv4Context = &interface->ipv4Context; 00543 00544 //Debug message 00545 TRACE_INFO("\r\n"); 00546 TRACE_INFO("Auto-IP configuration:\r\n"); 00547 00548 //Link-local address 00549 TRACE_INFO(" Link-local Address = %s\r\n", 00550 ipv4AddrToString(ipv4Context->addr, NULL)); 00551 00552 //Subnet mask 00553 TRACE_INFO(" Subnet Mask = %s\r\n", 00554 ipv4AddrToString(ipv4Context->subnetMask, NULL)); 00555 00556 //Debug message 00557 TRACE_INFO("\r\n"); 00558 #endif 00559 } 00560 00561 #endif 00562
Generated on Tue Jul 12 2022 17:10:12 by
