Webserver+3d print

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ndp_router_adv.c Source File

ndp_router_adv.c

Go to the documentation of this file.
00001 /**
00002  * @file ndp_router_adv.c
00003  * @brief Router advertisement service
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  * @author Oryx Embedded SARL (www.oryx-embedded.com)
00026  * @version 1.7.6
00027  **/
00028 
00029 //Switch to the appropriate trace level
00030 #define TRACE_LEVEL NDP_TRACE_LEVEL
00031 
00032 //Dependencies
00033 #include "core/net.h"
00034 #include "core/ip.h"
00035 #include "ipv6/ipv6.h"
00036 #include "ipv6/ipv6_misc.h"
00037 #include "ipv6/icmpv6.h"
00038 #include "ipv6/ndp.h"
00039 #include "ipv6/ndp_cache.h"
00040 #include "ipv6/ndp_misc.h"
00041 #include "ipv6/ndp_router_adv.h"
00042 #include "debug.h"
00043 
00044 //Check TCP/IP stack configuration
00045 #if (IPV6_SUPPORT == ENABLED && NDP_ROUTER_ADV_SUPPORT == ENABLED)
00046 
00047 //Tick counter to handle periodic operations
00048 systime_t ndpRouterAdvTickCounter;
00049 
00050 
00051 /**
00052  * @brief Initialize settings with default values
00053  * @param[out] settings Structure that contains the RA service configuration variables
00054  **/
00055 
00056 void ndpRouterAdvGetDefaultSettings(NdpRouterAdvSettings *settings)
00057 {
00058    //Underlying network interface
00059    settings->interface = netGetDefaultInterface();
00060 
00061    //The maximum time allowed between sending unsolicited multicast
00062    //Router Advertisements from the interface
00063    settings->maxRtrAdvInterval = NDP_MAX_RTR_ADVERT_INTERVAL;
00064 
00065    //The minimum time allowed between sending unsolicited multicast
00066    //Router Advertisements from the interface
00067    settings->minRtrAdvInterval = NDP_MAX_RTR_ADVERT_INTERVAL / 3;
00068 
00069    //The default value to be placed in the Cur Hop Limit field in the
00070    //Router Advertisement messages sent by the router
00071    settings->curHopLimit = 0;
00072 
00073    //The value to be placed in the Managed Address Configuration
00074    //flag in the Router Advertisement
00075    settings->managedFlag = FALSE;
00076 
00077    //The value to be placed in the Other Configuration flag
00078    //in the Router Advertisement
00079    settings->otherConfigFlag = FALSE;
00080 
00081    //The value to be placed in the Mobile IPv6 Home Agent
00082    //flag in the Router Advertisement
00083    settings->homeAgentFlag = FALSE;
00084 
00085    //The value to be placed in the Router Selection Preferences
00086    //field in the Router Advertisement
00087    settings->preference = NDP_ROUTER_SEL_PREFERENCE_MEDIUM;
00088 
00089    //The value to be placed in the Neighbor Discovery Proxy
00090    //flag in the Router Advertisement
00091    settings->proxyFlag = FALSE;
00092 
00093    //The value to be placed in the Router Lifetime field of
00094    //Router Advertisements sent from the interface
00095    settings->defaultLifetime = 3 * (NDP_MAX_RTR_ADVERT_INTERVAL / 1000);
00096 
00097    //The value to be placed in the Reachable Time field in the
00098    //Router Advertisement messages sent by the router
00099    settings->reachableTime = 0;
00100 
00101    //The value to be placed in the Retrans Timer field in the
00102    //Router Advertisement messages sent by the router
00103    settings->retransTimer = 0;
00104 
00105    //The value to be placed in the MTU option sent by the router
00106    settings->linkMtu = 0;
00107 
00108    //A list of prefixes to be placed in Prefix Information options (PIO)
00109    //in Router Advertisement messages sent from the interface
00110    settings->prefixList = NULL;
00111    settings->prefixListLength = 0;
00112 
00113    //A list of routes to be placed in Route Information options (RIO)
00114    //in Router Advertisement messages sent from the interface
00115    settings->routeList = NULL;
00116    settings->routeListLength = 0;
00117 
00118    //A list of header compression contexts to be placed in the 6LoWPAN Context
00119    //options (6CO) in Router Advertisement messages sent from the interface
00120    settings->contextList = NULL;
00121    settings->contextListLength = 0;
00122 }
00123 
00124 
00125 /**
00126  * @brief RA service initialization
00127  * @param[in] context Pointer to the RA service context
00128  * @param[in] settings RA service configuration variables
00129  * @return Error code
00130  **/
00131 
00132 error_t ndpRouterAdvInit(NdpRouterAdvContext *context, const NdpRouterAdvSettings *settings)
00133 {
00134    NetInterface *interface;
00135 
00136    //Debug message
00137    TRACE_INFO("Initializing Router Advertisement service...\r\n");
00138 
00139    //Ensure the parameters are valid
00140    if(!context || !settings)
00141       return ERROR_INVALID_PARAMETER;
00142 
00143    //Valid network interface?
00144    if(!settings->interface)
00145       return ERROR_INVALID_PARAMETER;
00146 
00147    //Get exclusive access
00148    osAcquireMutex(&netMutex);
00149 
00150    //Point to the underlying network interface
00151    interface = settings->interface;
00152 
00153    //Clear the RA service context
00154    memset(context, 0, sizeof(NdpRouterAdvContext));
00155    //Save user settings
00156    context->settings = *settings;
00157 
00158    //The RA service is currently disabled on the interface
00159    context->running = FALSE;
00160    //Attach the RA service context to the network interface
00161    interface->ndpRouterAdvContext = context;
00162 
00163    //Release exclusive access
00164    osReleaseMutex(&netMutex);
00165 
00166    //Successful initialization
00167    return NO_ERROR;
00168 }
00169 
00170 
00171 /**
00172  * @brief Start RA service
00173  * @param[in] context Pointer to the RA service context
00174  * @return Error code
00175  **/
00176 
00177 error_t ndpRouterAdvStart(NdpRouterAdvContext *context)
00178 {
00179    error_t error;
00180    NetInterface *interface;
00181 
00182    //Check parameter
00183    if(context == NULL)
00184       return ERROR_INVALID_PARAMETER;
00185 
00186    //Debug message
00187    TRACE_INFO("Starting Router Advertisement service...\r\n");
00188 
00189    //Get exclusive access
00190    osAcquireMutex(&netMutex);
00191 
00192    //Check whether the service is running
00193    if(!context->running)
00194    {
00195       //Point to the underlying network interface
00196       interface = context->settings.interface;
00197 
00198       //Join the All-Routers multicast address
00199       error = ipv6JoinMulticastGroup(interface, &IPV6_LINK_LOCAL_ALL_ROUTERS_ADDR);
00200 
00201       //Successful membership registration?
00202       if(!error)
00203       {
00204          //Reset variables
00205          context->timestamp = osGetSystemTime();
00206          context->timeout = 0;
00207          context->routerAdvCount = 0;
00208 
00209          //Enable the router to forward packets to or from the interface
00210          interface->ipv6Context.isRouter = TRUE;
00211 
00212          //Default Hop Limit value
00213          if(context->settings.curHopLimit != 0)
00214             interface->ipv6Context.curHopLimit = context->settings.curHopLimit;
00215 
00216          //The time a node assumes a neighbor is reachable
00217          if(context->settings.reachableTime != 0)
00218             interface->ndpContext.reachableTime = context->settings.reachableTime;
00219 
00220          //The time between retransmissions of NS messages
00221          if(context->settings.retransTimer != 0)
00222             interface->ndpContext.retransTimer = context->settings.retransTimer;
00223 
00224          //Start transmitting Router Advertisements
00225          context->running = TRUE;
00226       }
00227    }
00228    else
00229    {
00230       //The service is already running...
00231       error = NO_ERROR;
00232    }
00233 
00234    //Release exclusive access
00235    osReleaseMutex(&netMutex);
00236 
00237    //Return status code
00238    return error;
00239 }
00240 
00241 
00242 /**
00243  * @brief Stop RA service
00244  * @param[in] context Pointer to the RA service context
00245  * @return Error code
00246  **/
00247 
00248 error_t ndpRouterAdvStop(NdpRouterAdvContext *context)
00249 {
00250    error_t error;
00251    NetInterface *interface;
00252 
00253    //Check parameter
00254    if(context == NULL)
00255       return ERROR_INVALID_PARAMETER;
00256 
00257    //Debug message
00258    TRACE_INFO("Stopping Router Advertisement service...\r\n");
00259 
00260    //Get exclusive access
00261    osAcquireMutex(&netMutex);
00262 
00263    //Check whether the service is running
00264    if(context->running)
00265    {
00266       //Point to the underlying network interface
00267       interface = context->settings.interface;
00268 
00269       //The router should transmit one or more final multicast Router
00270       //Advertisements with a Router Lifetime field of zero
00271       ndpSendRouterAdv(context, 0);
00272 
00273       //Leave the All-Routers multicast address
00274       error = ipv6LeaveMulticastGroup(interface, &IPV6_LINK_LOCAL_ALL_ROUTERS_ADDR);
00275 
00276       //Restore default parameters
00277       interface->ipv6Context.curHopLimit = IPV6_DEFAULT_HOP_LIMIT;
00278       interface->ndpContext.reachableTime = NDP_REACHABLE_TIME;
00279       interface->ndpContext.retransTimer = NDP_RETRANS_TIMER;
00280 
00281       //Stop transmitting Router Advertisements
00282       context->running = FALSE;
00283    }
00284    else
00285    {
00286       //The service is not running...
00287       error = NO_ERROR;
00288    }
00289 
00290    //Release exclusive access
00291    osReleaseMutex(&netMutex);
00292 
00293    //Return status code
00294    return error;
00295 }
00296 
00297 
00298 /**
00299  * @brief RA service timer handler
00300  * @param[in] context Pointer to the RA service context
00301  **/
00302 
00303 void ndpRouterAdvTick(NdpRouterAdvContext *context)
00304 {
00305    systime_t time;
00306    NetInterface *interface;
00307    NdpRouterAdvSettings *settings;
00308 
00309    //Make sure the RA service has been properly instantiated
00310    if(context == NULL)
00311       return;
00312 
00313    //Point to the underlying network interface
00314    interface = context->settings.interface;
00315    //Point to the router configuration variables
00316    settings = &context->settings;
00317 
00318    //Get current time
00319    time = osGetSystemTime();
00320 
00321    //Make sure that the link is up and the service is running
00322    if(interface->linkState && context->running)
00323    {
00324       //Make sure that a valid link-local address has been assigned to the interface
00325       if(ipv6GetLinkLocalAddrState(interface) == IPV6_ADDR_STATE_PREFERRED)
00326       {
00327          //Check current time
00328          if(timeCompare(time, context->timestamp + context->timeout) >= 0)
00329          {
00330             //Send an unsolicited Router Advertisement
00331             ndpSendRouterAdv(context, context->settings.defaultLifetime);
00332 
00333             //Save the time at which the message was sent
00334             context->timestamp = time;
00335 
00336             //Whenever a multicast advertisement is sent from an interface, the
00337             //timer is reset to a uniformly distributed random value between
00338             //MinRtrAdvInterval and MaxRtrAdvInterval
00339             context->timeout = netGetRandRange(settings->minRtrAdvInterval,
00340                settings->maxRtrAdvInterval);
00341 
00342             //First Router Advertisements to be sent from this interface?
00343             if(context->routerAdvCount < NDP_MAX_INITIAL_RTR_ADVERTISEMENTS)
00344             {
00345                //For the first few advertisements sent from an interface when it
00346                //becomes an advertising interface, the randomly chosen interval
00347                //should not be greater than MAX_INITIAL_RTR_ADVERT_INTERVAL
00348                context->timeout = MIN(context->timeout, NDP_MAX_INITIAL_RTR_ADVERT_INTERVAL);
00349             }
00350 
00351             //Increment counter
00352             context->routerAdvCount++;
00353          }
00354       }
00355    }
00356 }
00357 
00358 
00359 /**
00360  * @brief Callback function for link change event
00361  * @param[in] context Pointer to the RA service context
00362  **/
00363 
00364 void ndpRouterAdvLinkChangeEvent(NdpRouterAdvContext *context)
00365 {
00366    NetInterface *interface;
00367 
00368    //Make sure the RA service has been properly instantiated
00369    if(context == NULL)
00370       return;
00371 
00372    //Point to the underlying network interface
00373    interface = context->settings.interface;
00374 
00375    //Reset variables
00376    context->timestamp = osGetSystemTime();
00377    context->timeout = 0;
00378    context->routerAdvCount = 0;
00379 
00380    //Default Hop Limit value
00381    if(context->settings.curHopLimit != 0)
00382       interface->ipv6Context.curHopLimit = context->settings.curHopLimit;
00383 
00384    //The time a node assumes a neighbor is reachable
00385    if(context->settings.reachableTime != 0)
00386       interface->ndpContext.reachableTime = context->settings.reachableTime;
00387 
00388    //The time between retransmissions of NS messages
00389    if(context->settings.retransTimer != 0)
00390       interface->ndpContext.retransTimer = context->settings.retransTimer;
00391 }
00392 
00393 
00394 /**
00395  * @brief Router Solicitation message processing
00396  * @param[in] interface Underlying network interface
00397  * @param[in] pseudoHeader IPv6 pseudo header
00398  * @param[in] buffer Multi-part buffer containing the Router Advertisement message
00399  * @param[in] offset Offset to the first byte of the message
00400  * @param[in] hopLimit Hop Limit field from IPv6 header
00401  **/
00402 
00403 void ndpProcessRouterSol(NetInterface *interface, Ipv6PseudoHeader *pseudoHeader,
00404    const NetBuffer *buffer, size_t offset, uint8_t hopLimit)
00405 {
00406    error_t error;
00407    uint_t n;
00408    size_t length;
00409    systime_t time;
00410    systime_t delay;
00411    NdpRouterAdvContext *context;
00412    NdpRouterSolMessage *message;
00413    NdpLinkLayerAddrOption *option;
00414    NdpNeighborCacheEntry *entry;
00415 
00416    //Point to the RA service context
00417    context = interface->ndpRouterAdvContext;
00418 
00419    //A host must silently discard any received Router Solicitation
00420    if(context == NULL)
00421       return;
00422 
00423    //Get current time
00424    time = osGetSystemTime();
00425 
00426    //Retrieve the length of the message
00427    length = netBufferGetLength(buffer) - offset;
00428 
00429    //Check the length of the Router Solicitation message
00430    if(length < sizeof(NdpRouterSolMessage))
00431       return;
00432 
00433    //Point to the beginning of the message
00434    message = netBufferAt(buffer, offset);
00435    //Sanity check
00436    if(message == NULL)
00437       return;
00438 
00439    //Debug message
00440    TRACE_INFO("Router Solicitation message received (%" PRIuSIZE " bytes)...\r\n", length);
00441    //Dump message contents for debugging purpose
00442    ndpDumpRouterSolMessage(message);
00443 
00444    //The IPv6 Hop Limit field must have a value of 255 to ensure
00445    //that the packet has not been forwarded by a router
00446    if(hopLimit != NDP_HOP_LIMIT)
00447       return;
00448 
00449    //ICMPv6 Code must be 0
00450    if(message->code)
00451       return;
00452 
00453    //Calculate the length of the Options field
00454    length -= sizeof(NdpRouterSolMessage);
00455 
00456    //Parse Options field
00457    error = ndpCheckOptions(message->options, length);
00458    //All included options must have a length that is greater than zero
00459    if(error)
00460       return;
00461 
00462    //Search for the Source Link-Layer Address option
00463    option = ndpGetOption(message->options,
00464       length, NDP_OPT_SOURCE_LINK_LAYER_ADDR);
00465 
00466    //Source Link-Layer Address option found?
00467    if(option != NULL && option->length == 1)
00468    {
00469       //Debug message
00470       TRACE_DEBUG("  Source Link-Layer Address = %s\r\n",
00471          macAddrToString(&option->linkLayerAddr, NULL));
00472 
00473       //The Source Link-Layer Address option must not be included when the
00474       //source IP address is the unspecified address
00475       if(ipv6CompAddr(&pseudoHeader->srcAddr, &IPV6_UNSPECIFIED_ADDR))
00476          return;
00477 
00478       //Search the Neighbor Cache for the source address of the solicitation
00479       entry = ndpFindNeighborCacheEntry(interface, &pseudoHeader->srcAddr);
00480 
00481       //No matching entry has been found?
00482       if(!entry)
00483       {
00484          //Create an entry
00485          entry = ndpCreateNeighborCacheEntry(interface);
00486 
00487          //Neighbor Cache entry successfully created?
00488          if(entry)
00489          {
00490             //Record the IPv6 and the corresponding MAC address
00491             entry->ipAddr = pseudoHeader->srcAddr;
00492             entry->macAddr = option->linkLayerAddr;
00493             //The IsRouter flag must be set to FALSE
00494             entry->isRouter = FALSE;
00495             //Save current time
00496             entry->timestamp = time;
00497             //Enter the STALE state
00498             entry->state = NDP_STATE_STALE;
00499          }
00500       }
00501       else
00502       {
00503          //If a Neighbor Cache entry for the solicitation's sender exists
00504          //the entry's IsRouter flag must be set to FALSE
00505          entry->isRouter = FALSE;
00506 
00507          //INCOMPLETE state?
00508          if(entry->state == NDP_STATE_INCOMPLETE)
00509          {
00510             //Record link-layer address
00511             entry->macAddr = option->linkLayerAddr;
00512             //Send all the packets that are pending for transmission
00513             n = ndpSendQueuedPackets(interface, entry);
00514             //Save current time
00515             entry->timestamp = time;
00516 
00517             //Check whether any packets have been sent
00518             if(n > 0)
00519             {
00520                //Start delay timer
00521                entry->timeout = NDP_DELAY_FIRST_PROBE_TIME;
00522                //Switch to the DELAY state
00523                entry->state = NDP_STATE_DELAY;
00524             }
00525             else
00526             {
00527                //Enter the STALE state
00528                entry->state = NDP_STATE_STALE;
00529             }
00530          }
00531          //REACHABLE, STALE, DELAY or PROBE state?
00532          else
00533          {
00534             //Different link-layer address than cached?
00535             if(!macCompAddr(&entry->macAddr, &option->linkLayerAddr))
00536             {
00537                //Update link-layer address
00538                entry->macAddr = option->linkLayerAddr;
00539                //Save current time
00540                entry->timestamp = time;
00541                //Enter the STALE state
00542                entry->state = NDP_STATE_STALE;
00543             }
00544          }
00545       }
00546    }
00547 
00548    //Upon receipt of a Router Solicitation, compute a random delay within the
00549    //range 0 through MAX_RA_DELAY_TIME
00550    delay = netGetRandRange(0, NDP_MAX_RA_DELAY_TIME);
00551 
00552    //If the computed value corresponds to a time later than the time the next
00553    //multicast Router Advertisement is scheduled to be sent, ignore the random
00554    //delay and send the advertisement at the already-scheduled time
00555    if(timeCompare(time + delay, context->timestamp + context->timeout) > 0)
00556       return;
00557 
00558    //Check whether the router sent a multicast Router Advertisement (solicited
00559    //or unsolicited) within the last MIN_DELAY_BETWEEN_RAS seconds
00560    if(timeCompare(time, context->timestamp + NDP_MIN_DELAY_BETWEEN_RAS) < 0)
00561    {
00562       //Schedule the advertisement to be sent at a time corresponding to
00563       //MIN_DELAY_BETWEEN_RAS plus the random value after the previous
00564       //advertisement was sent. This ensures that the multicast Router
00565       //Advertisements are rate limited
00566       context->timeout = NDP_MIN_DELAY_BETWEEN_RAS + delay;
00567    }
00568    else
00569    {
00570       //Schedule the sending of a Router Advertisement at the time given
00571       //by the random value
00572       context->timeout = time + delay - context->timestamp;
00573    }
00574 }
00575 
00576 
00577 /**
00578  * @brief Send a Router Advertisement message
00579  * @param[in] context Pointer to the RA service context
00580  * @param[in] routerLifetime Router Lifetime field
00581  * @return Error code
00582  **/
00583 
00584 error_t ndpSendRouterAdv(NdpRouterAdvContext *context, uint16_t routerLifetime)
00585 {
00586    error_t error;
00587    uint_t i;
00588    uint32_t n;
00589    size_t offset;
00590    size_t length;
00591    NetBuffer *buffer;
00592    NetInterface *interface;
00593    NdpRouterAdvMessage *message;
00594    NdpRouterAdvSettings *settings;
00595    Ipv6PseudoHeader pseudoHeader;
00596 
00597    //Point to the underlying network interface
00598    interface = context->settings.interface;
00599    //Point to the router configuration variables
00600    settings = &context->settings;
00601 
00602    //The destination address is typically the all-nodes multicast address
00603    pseudoHeader.destAddr = IPV6_LINK_LOCAL_ALL_NODES_ADDR;
00604 
00605    //Routers must use their link-local address as the source for Router
00606    //Advertisement messages so that hosts can uniquely identify routers
00607    error = ipv6SelectSourceAddr(&interface,
00608       &pseudoHeader.destAddr, &pseudoHeader.srcAddr);
00609 
00610    //No link-local address assigned to the interface?
00611    if(error)
00612       return error;
00613 
00614    //Compute the maximum size of the Router Advertisement message
00615    length = sizeof(NdpRouterAdvMessage) +
00616       sizeof(NdpLinkLayerAddrOption) + sizeof(NdpMtuOption) +
00617       settings->prefixListLength * sizeof(NdpPrefixInfoOption) +
00618       settings->routeListLength * sizeof(NdpRouteInfoOption) +
00619       settings->contextListLength * sizeof(NdpContextOption);
00620 
00621    //Sanity check
00622    if((length + sizeof(Ipv6Header)) > IPV6_DEFAULT_MTU)
00623       return ERROR_FAILURE;
00624 
00625    //Allocate a memory buffer to hold the Router Advertisement message
00626    buffer = ipAllocBuffer(length, &offset);
00627    //Failed to allocate memory?
00628    if(buffer == NULL)
00629       return ERROR_OUT_OF_MEMORY;
00630 
00631    //Point to the beginning of the message
00632    message = netBufferAt(buffer, offset);
00633 
00634    //Format Router Advertisement message
00635    message->type = ICMPV6_TYPE_ROUTER_ADV;
00636    message->code = 0;
00637    message->checksum = 0;
00638    message->curHopLimit = settings->curHopLimit;
00639    message->m = settings->managedFlag;
00640    message->o = settings->otherConfigFlag;
00641    message->h = settings->homeAgentFlag;
00642    message->prf = settings->preference;
00643    message->p = settings->proxyFlag;
00644    message->reserved = 0;
00645    message->routerLifetime = htons(routerLifetime);
00646    message->reachableTime = htonl(settings->reachableTime);
00647    message->retransTimer = htonl(settings->retransTimer);
00648 
00649    //If the Router Lifetime is zero, the preference value must be
00650    //set to zero by the sender
00651    if(routerLifetime == 0)
00652       message->prf = NDP_ROUTER_SEL_PREFERENCE_MEDIUM;
00653 
00654    //Length of the message, excluding any option
00655    length = sizeof(NdpRouterAdvMessage);
00656 
00657 #if (ETH_SUPPORT == ENABLED)
00658    //Check whether a MAC address has been assigned to the interface
00659    if(!macCompAddr(&interface->macAddr, &MAC_UNSPECIFIED_ADDR))
00660    {
00661       //Add Source Link-Layer Address option
00662       ndpAddOption(message, &length, NDP_OPT_SOURCE_LINK_LAYER_ADDR,
00663          &interface->macAddr, sizeof(MacAddr));
00664    }
00665 #endif
00666 
00667    //A value of zero indicates that no MTU option is sent
00668    if(settings->linkMtu > 0)
00669    {
00670       NdpMtuOption mtuOption;
00671 
00672       //The MTU option specifies the recommended MTU for the link
00673       mtuOption.reserved = 0;
00674       mtuOption.mtu = htonl(settings->linkMtu);
00675 
00676       //Add MTU option
00677       ndpAddOption(message, &length, NDP_OPT_MTU,
00678          (uint8_t *) &mtuOption + sizeof(NdpOption),
00679          sizeof(NdpMtuOption) - sizeof(NdpOption));
00680    }
00681 
00682    //Loop through the list of IPv6 prefixes
00683    for(i = 0; i < settings->prefixListLength; i++)
00684    {
00685       NdpPrefixInfoOption prefixInfoOption;
00686 
00687       //The Prefix Information option provide hosts with on-link
00688       //prefixes and prefixes for Address Autoconfiguration
00689       prefixInfoOption.prefixLength = settings->prefixList[i].length;
00690       prefixInfoOption.l = settings->prefixList[i].onLinkFlag;
00691       prefixInfoOption.a = settings->prefixList[i].autonomousFlag;
00692       prefixInfoOption.reserved1 = 0;
00693       prefixInfoOption.validLifetime = htonl(settings->prefixList[i].validLifetime);
00694       prefixInfoOption.preferredLifetime = htonl(settings->prefixList[i].preferredLifetime);
00695       prefixInfoOption.reserved2 = 0;
00696       prefixInfoOption.prefix = settings->prefixList[i].prefix;
00697 
00698       //Add Prefix Information option (PIO)
00699       ndpAddOption(message, &length, NDP_OPT_PREFIX_INFORMATION,
00700          (uint8_t *) &prefixInfoOption + sizeof(NdpOption),
00701          sizeof(NdpPrefixInfoOption) - sizeof(NdpOption));
00702    }
00703 
00704    //Loop through the list of routes
00705    for(i = 0; i < settings->routeListLength; i++)
00706    {
00707       NdpRouteInfoOption routeInfoOption;
00708 
00709       //The Route Information option specifies prefixes that are
00710       //reachable via the router
00711       routeInfoOption.prefixLength = settings->routeList[i].length;
00712       routeInfoOption.reserved1 = 0;
00713       routeInfoOption.prf = settings->routeList[i].preference;
00714       routeInfoOption.reserved2 = 0;
00715       routeInfoOption.routeLifetime = htonl(settings->routeList[i].routeLifetime);
00716       routeInfoOption.prefix = settings->routeList[i].prefix;
00717 
00718       //Add Route Information option (RIO)
00719       ndpAddOption(message, &length, NDP_OPT_ROUTE_INFORMATION,
00720          (uint8_t *) &routeInfoOption + sizeof(NdpOption),
00721          sizeof(NdpRouteInfoOption) - sizeof(NdpOption));
00722    }
00723 
00724    //Loop through the list of 6LoWPAN compression contexts
00725    for(i = 0; i < settings->contextListLength; i++)
00726    {
00727       NdpContextOption contextOption;
00728 
00729       //The 6LoWPAN Context option (6CO) carries prefix information for
00730       //LoWPAN header compression
00731       contextOption.contextLength = settings->contextList[i].length;
00732       contextOption.reserved1 = 0;
00733       contextOption.c = settings->contextList[i].compression;
00734       contextOption.cid = settings->contextList[i].cid;
00735       contextOption.reserved2 = 0;
00736       contextOption.validLifetime = htons(settings->contextList[i].validLifetime);
00737       contextOption.contextPrefix = settings->contextList[i].prefix;
00738 
00739       //Calculate the length of the option in bytes
00740       n = sizeof(NdpContextOption) - sizeof(Ipv6Addr) + (contextOption.contextLength / 8);
00741 
00742       //Add 6LoWPAN Context option (6CO)
00743       ndpAddOption(message, &length, NDP_OPT_6LOWPAN_CONTEXT,
00744          (uint8_t *) &contextOption + sizeof(NdpOption), n - sizeof(NdpOption));
00745    }
00746 
00747    //Adjust the length of the multi-part buffer
00748    netBufferSetLength(buffer, offset + length);
00749 
00750    //Format IPv6 pseudo header
00751    pseudoHeader.length = htonl(length);
00752    pseudoHeader.reserved = 0;
00753    pseudoHeader.nextHeader = IPV6_ICMPV6_HEADER;
00754 
00755    //Calculate ICMPv6 header checksum
00756    message->checksum = ipCalcUpperLayerChecksumEx(&pseudoHeader,
00757       sizeof(Ipv6PseudoHeader), buffer, offset, length);
00758 
00759    //Debug message
00760    TRACE_INFO("Sending Router Advertisement message (%" PRIuSIZE " bytes)...\r\n", length);
00761    //Dump message contents for debugging purpose
00762    ndpDumpRouterAdvMessage(message);
00763 
00764    //Send Router Advertisement message
00765    error = ipv6SendDatagram(interface, &pseudoHeader, buffer, offset, NDP_HOP_LIMIT);
00766 
00767    //Free previously allocated memory
00768    netBufferFree(buffer);
00769    //Return status code
00770    return error;
00771 }
00772 
00773 #endif
00774