Webserver+3d print

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers auto_ip.c Source File

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