Webserver+3d print

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ndp.c Source File

ndp.c

Go to the documentation of this file.
00001 /**
00002  * @file ndp.c
00003  * @brief NDP (Neighbor Discovery Protocol)
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  * The Neighbor Discovery Protocol is responsible for address autoconfiguration
00028  * of nodes, discovery of the link-layer addresses of other nodes, duplicate
00029  * address detection, finding available routers and address prefix discovery.
00030  * Refer to RFC 4861 for more details
00031  *
00032  * @author Oryx Embedded SARL (www.oryx-embedded.com)
00033  * @version 1.7.6
00034  **/
00035 
00036 //Switch to the appropriate trace level
00037 #define TRACE_LEVEL NDP_TRACE_LEVEL
00038 
00039 //Dependencies
00040 #include <limits.h>
00041 #include <string.h>
00042 #include "core/net.h"
00043 #include "ipv6/ipv6.h"
00044 #include "ipv6/ipv6_misc.h"
00045 #include "ipv6/icmpv6.h"
00046 #include "ipv6/ndp.h"
00047 #include "ipv6/ndp_cache.h"
00048 #include "ipv6/ndp_misc.h"
00049 #include "ipv6/slaac.h"
00050 #include "debug.h"
00051 
00052 //Check TCP/IP stack configuration
00053 #if (IPV6_SUPPORT == ENABLED && NDP_SUPPORT == ENABLED)
00054 
00055 //Tick counter to handle periodic operations
00056 systime_t ndpTickCounter;
00057 
00058 
00059 /**
00060  * @brief Neighbor cache initialization
00061  * @param[in] interface Underlying network interface
00062  * @return Error code
00063  **/
00064 
00065 error_t ndpInit(NetInterface *interface)
00066 {
00067    NdpContext *context;
00068 
00069    //Point to the NDP context
00070    context = &interface->ndpContext;
00071 
00072    //Clear the NDP context
00073    memset(context, 0, sizeof(NdpContext));
00074 
00075    //Initialize interface specific variables
00076    context->reachableTime = NDP_REACHABLE_TIME;
00077    context->retransTimer = NDP_RETRANS_TIMER;
00078    context->dupAddrDetectTransmits = NDP_DUP_ADDR_DETECT_TRANSMITS;
00079    context->minRtrSolicitationDelay = NDP_MIN_RTR_SOLICITATION_DELAY;
00080    context->maxRtrSolicitationDelay = NDP_MAX_RTR_SOLICITATION_DELAY;
00081    context->rtrSolicitationInterval = NDP_RTR_SOLICITATION_INTERVAL;
00082    context->maxRtrSolicitations = NDP_MAX_RTR_SOLICITATIONS;
00083 
00084    //Successful initialization
00085    return NO_ERROR;
00086 }
00087 
00088 
00089 /**
00090  * @brief Address resolution using Neighbor Discovery protocol
00091  * @param[in] interface Underlying network interface
00092  * @param[in] ipAddr IPv6 address
00093  * @param[in] macAddr Physical address matching the specified IPv6 address
00094  * @return Error code
00095  **/
00096 
00097 error_t ndpResolve(NetInterface *interface, const Ipv6Addr *ipAddr, MacAddr *macAddr)
00098 {
00099    error_t error;
00100    NdpNeighborCacheEntry *entry;
00101 
00102    //Search the ndpCacheMutex cache for the specified IPv6 address
00103    entry = ndpFindNeighborCacheEntry(interface, ipAddr);
00104 
00105    //Check whether a matching entry has been found
00106    if(entry != NULL)
00107    {
00108       //Check the state of the Neighbor cache entry
00109       if(entry->state == NDP_STATE_INCOMPLETE)
00110       {
00111          //The address resolution is already in progress
00112          error = ERROR_IN_PROGRESS;
00113       }
00114       else if(entry->state == NDP_STATE_STALE)
00115       {
00116          //Copy the MAC address associated with the specified IPv6 address
00117          *macAddr = entry->macAddr;
00118 
00119          //Start delay timer
00120          entry->timestamp = osGetSystemTime();
00121          //Delay before sending the first probe
00122          entry->timeout = NDP_DELAY_FIRST_PROBE_TIME;
00123          //Switch to the DELAY state
00124          entry->state = NDP_STATE_DELAY;
00125 
00126          //Successful address resolution
00127          error = NO_ERROR;
00128       }
00129       else
00130       {
00131          //Copy the MAC address associated with the specified IPv6 address
00132          *macAddr = entry->macAddr;
00133 
00134          //Successful address resolution
00135          error = NO_ERROR;
00136       }
00137    }
00138    else
00139    {
00140       //If no entry exists, then create a new one
00141       entry = ndpCreateNeighborCacheEntry(interface);
00142 
00143       //Neighbor Cache entry successfully created?
00144       if(entry != NULL)
00145       {
00146          //Record the IPv6 address whose MAC address is unknown
00147          entry->ipAddr = *ipAddr;
00148 
00149          //Reset retransmission counter
00150          entry->retransmitCount = 0;
00151          //No packet are pending in the transmit queue
00152          entry->queueSize = 0;
00153 
00154          //Send a multicast Neighbor Solicitation message
00155          ndpSendNeighborSol(interface, ipAddr, TRUE);
00156 
00157          //Save the time at which the message was sent
00158          entry->timestamp = osGetSystemTime();
00159          //Set timeout value
00160          entry->timeout = interface->ndpContext.retransTimer;
00161          //Enter INCOMPLETE state
00162          entry->state = NDP_STATE_INCOMPLETE;
00163 
00164          //The address resolution is in progress
00165          error = ERROR_IN_PROGRESS;
00166       }
00167       else
00168       {
00169          //Failed to create Neighbor Cache entry...
00170          error = ERROR_OUT_OF_RESOURCES;
00171       }
00172    }
00173 
00174    //Return status code
00175    return error;
00176 }
00177 
00178 
00179 /**
00180  * @brief Enqueue an IPv6 packet waiting for address resolution
00181  * @param[in] srcInterface Interface from which the packet has been received
00182  * @param[in] destInterface Interface on which the packet should be sent
00183  * @param[in] ipAddr IPv6 address of the destination host
00184  * @param[in] buffer Multi-part buffer containing the packet to be enqueued
00185  * @param[in] offset Offset to the first byte of the packet
00186  * @return Error code
00187  **/
00188 
00189 error_t ndpEnqueuePacket(NetInterface *srcInterface, NetInterface *destInterface,
00190    const Ipv6Addr *ipAddr, NetBuffer *buffer, size_t offset)
00191 {
00192    error_t error;
00193    uint_t i;
00194    size_t length;
00195    NdpNeighborCacheEntry *entry;
00196 
00197    //Retrieve the length of the multi-part buffer
00198    length = netBufferGetLength(buffer);
00199 
00200    //Search the Neighbor cache for the specified IPv6 address
00201    entry = ndpFindNeighborCacheEntry(destInterface, ipAddr);
00202 
00203    //Check whether a matching entry exists
00204    if(entry != NULL)
00205    {
00206       //Check current state
00207       if(entry->state == NDP_STATE_INCOMPLETE)
00208       {
00209          //Check whether the packet queue is full
00210          if(entry->queueSize >= NDP_MAX_PENDING_PACKETS)
00211          {
00212             //When the queue overflows, the new arrival should replace the oldest entry
00213             netBufferFree(entry->queue[0].buffer);
00214 
00215             //Make room for the new packet
00216             for(i = 1; i < NDP_MAX_PENDING_PACKETS; i++)
00217                entry->queue[i - 1] = entry->queue[i];
00218 
00219             //Adjust the number of pending packets
00220             entry->queueSize--;
00221          }
00222 
00223          //Index of the entry to be filled in
00224          i = entry->queueSize;
00225          //Allocate a memory buffer to store the packet
00226          entry->queue[i].buffer = netBufferAlloc(length);
00227 
00228          //Successful memory allocation?
00229          if(entry->queue[i].buffer != NULL)
00230          {
00231             //If the IPv6 packet has been forwarded, record the network
00232             //interface from which the packet has been received
00233             entry->queue[i].srcInterface = srcInterface;
00234 
00235             //Copy the contents of the IPv6 packet
00236             netBufferCopy(entry->queue[i].buffer, 0, buffer, 0, length);
00237             //Offset to the first byte of the IPv6 header
00238             entry->queue[i].offset = offset;
00239 
00240             //Increment the number of queued packets
00241             entry->queueSize++;
00242             //The packet was successfully enqueued
00243             error = NO_ERROR;
00244          }
00245          else
00246          {
00247             //Failed to allocate memory
00248             error = ERROR_OUT_OF_MEMORY;
00249          }
00250       }
00251       else
00252       {
00253          //The address is already resolved
00254          error = ERROR_UNEXPECTED_STATE;
00255       }
00256    }
00257    else
00258    {
00259       //No matching entry in Neighbor Cache
00260       error = ERROR_NOT_FOUND;
00261    }
00262 
00263    //Return status code
00264    return error;
00265 }
00266 
00267 
00268 /**
00269  * @brief NDP timer handler
00270  * @param[in] interface Underlying network interface
00271  **/
00272 
00273 void ndpTick(NetInterface *interface)
00274 {
00275    systime_t time;
00276    NdpContext *context;
00277 
00278    //Point to the NDP context
00279    context = &interface->ndpContext;
00280 
00281    //Get current time
00282    time = osGetSystemTime();
00283 
00284    //When an interface becomes enabled, a host may send some Router
00285    //Solicitation messages to obtain Router Advertisements quickly
00286    if(interface->linkState && !interface->ipv6Context.isRouter)
00287    {
00288       //Make sure that a valid link-local address has been assigned to the interface
00289       if(ipv6GetLinkLocalAddrState(interface) == IPV6_ADDR_STATE_PREFERRED)
00290       {
00291          //The host should transmit up to MAX_RTR_SOLICITATIONS Router
00292          //Solicitation messages
00293          if(context->rtrSolicitationCount == 0)
00294          {
00295             //Set time stamp
00296             context->timestamp = time;
00297 
00298             //Check whether the host has already performed Duplicate Address
00299             //Detection for the link-local address
00300             if(context->dupAddrDetectTransmits > 0)
00301             {
00302                //If a host has already performed a random delay since the interface
00303                //became enabled, there is no need to delay again before sending the
00304                //first Router Solicitation message
00305                context->timeout = 0;
00306             }
00307             else
00308             {
00309                //Before a host sends an initial solicitation, it should delay the
00310                //transmission for a random amount of time in order to alleviate
00311                //congestion when many hosts start up on a link at the same time
00312                context->timeout = netGetRandRange(context->minRtrSolicitationDelay,
00313                   context->maxRtrSolicitationDelay);
00314             }
00315 
00316             //Prepare to send the first Router Solicitation message
00317             context->rtrSolicitationCount = 1;
00318          }
00319          else if(context->rtrSolicitationCount <= context->maxRtrSolicitations)
00320          {
00321             //Once the host sends a Router Solicitation, and receives a valid
00322             //Router Advertisement with a non-zero Router Lifetime, the host must
00323             //desist from sending additional solicitations on that interface
00324             if(!context->rtrAdvReceived)
00325             {
00326                //Check current time
00327                if(timeCompare(time, context->timestamp + context->timeout) >= 0)
00328                {
00329                   //Send Router Solicitation message
00330                   ndpSendRouterSol(interface);
00331 
00332                   //Save the time at which the message was sent
00333                   context->timestamp = time;
00334                   //Set timeout value
00335                   context->timeout = context->rtrSolicitationInterval;
00336                   //Increment retransmission counter
00337                   context->rtrSolicitationCount++;
00338                }
00339             }
00340          }
00341       }
00342    }
00343 
00344    //Periodically update the Neighbor Cache
00345    ndpUpdateNeighborCache(interface);
00346 
00347    //Manage the lifetime of IPv6 addresses
00348    ndpUpdateAddrList(interface);
00349 
00350    //Periodically update the Prefix List
00351    ndpUpdatePrefixList(interface);
00352 
00353    //Periodically update the Default Router List
00354    ndpUpdateDefaultRouterList(interface);
00355 }
00356 
00357 
00358 /**
00359  * @brief Callback function for link change event
00360  * @param[in] interface Underlying network interface
00361  **/
00362 
00363 void ndpLinkChangeEvent(NetInterface *interface)
00364 {
00365    NdpContext *context;
00366 
00367    //Point to the NDP context
00368    context = &interface->ndpContext;
00369 
00370    //Restore default parameters
00371    context->reachableTime = NDP_REACHABLE_TIME;
00372    context->retransTimer = NDP_RETRANS_TIMER;
00373    context->dupAddrDetectTransmits = NDP_DUP_ADDR_DETECT_TRANSMITS;
00374    context->minRtrSolicitationDelay = NDP_MIN_RTR_SOLICITATION_DELAY;
00375    context->maxRtrSolicitationDelay = NDP_MAX_RTR_SOLICITATION_DELAY;
00376    context->rtrSolicitationInterval = NDP_RTR_SOLICITATION_INTERVAL;
00377    context->maxRtrSolicitations = NDP_MAX_RTR_SOLICITATIONS;
00378 
00379    //Reset retransmission counter for RS messages
00380    context->rtrSolicitationCount = 0;
00381    //Valid RA message not yet received
00382    context->rtrAdvReceived = FALSE;
00383 
00384    //Flush the Neighbor Cache
00385    ndpFlushNeighborCache(interface);
00386    //Flush the Destination Cache
00387    ndpFlushDestCache(interface);
00388 }
00389 
00390 
00391 /**
00392  * @brief Router Advertisement message processing
00393  * @param[in] interface Underlying network interface
00394  * @param[in] pseudoHeader IPv6 pseudo header
00395  * @param[in] buffer Multi-part buffer containing the Router Advertisement message
00396  * @param[in] offset Offset to the first byte of the message
00397  * @param[in] hopLimit Hop Limit field from IPv6 header
00398  **/
00399 
00400 void ndpProcessRouterAdv(NetInterface *interface, Ipv6PseudoHeader *pseudoHeader,
00401    const NetBuffer *buffer, size_t offset, uint8_t hopLimit)
00402 {
00403    error_t error;
00404    uint32_t n;
00405    size_t length;
00406    NdpRouterAdvMessage *message;
00407    NdpMtuOption *mtuOption;
00408    NdpPrefixInfoOption *prefixInfoOption;
00409 #if (ETH_SUPPORT == ENABLED)
00410    NdpLinkLayerAddrOption *linkLayerAddrOption;
00411    NdpNeighborCacheEntry *entry;
00412 #endif
00413 
00414    //Retrieve the length of the message
00415    length = netBufferGetLength(buffer) - offset;
00416 
00417    //Check the length of the Router Advertisement message
00418    if(length < sizeof(NdpRouterAdvMessage))
00419       return;
00420 
00421    //Point to the beginning of the message
00422    message = netBufferAt(buffer, offset);
00423    //Sanity check
00424    if(message == NULL)
00425       return;
00426 
00427    //Debug message
00428    TRACE_INFO("Router Advertisement message received (%" PRIuSIZE " bytes)...\r\n", length);
00429    //Dump message contents for debugging purpose
00430    ndpDumpRouterAdvMessage(message);
00431 
00432    //Routers must use their link-local address as the source for the
00433    //Router Advertisement so that hosts can uniquely identify routers
00434    if(!ipv6IsLinkLocalUnicastAddr(&pseudoHeader->srcAddr))
00435       return;
00436 
00437    //The IPv6 Hop Limit field must have a value of 255 to ensure
00438    //that the packet has not been forwarded by a router
00439    if(hopLimit != NDP_HOP_LIMIT)
00440       return;
00441 
00442    //ICMPv6 Code must be 0. An advertisement that passes the validity
00443    //checks is called a valid advertisement
00444    if(message->code)
00445       return;
00446 
00447    //Calculate the length of the Options field
00448    length -= sizeof(NdpRouterAdvMessage);
00449 
00450    //Parse Options field
00451    error = ndpCheckOptions(message->options, length);
00452    //All included options must have a length that is greater than zero
00453    if(error)
00454       return;
00455 
00456    //Check the Router Lifetime value
00457    if(ntohs(message->routerLifetime) != 0)
00458    {
00459       //Add a new entry in the Default Router List
00460       ipv6AddDefaultRouter(interface, &pseudoHeader->srcAddr,
00461          ntohs(message->routerLifetime));
00462 
00463       //The host should send at least one solicitation in the case where
00464       //an advertisement is received prior to having sent a solicitation
00465       if(interface->ndpContext.rtrSolicitationCount > 1)
00466       {
00467          //Once the host sends a Router Solicitation, and receives a valid
00468          //Router Advertisement with a non-zero Router Lifetime, the host must
00469          //desist from sending additional solicitations on that interface
00470          interface->ndpContext.rtrAdvReceived = TRUE;
00471       }
00472    }
00473    else
00474    {
00475       //Immediately time-out the entry
00476       ipv6RemoveDefaultRouter(interface, &pseudoHeader->srcAddr);
00477    }
00478 
00479    //6LoWPAN interface?
00480    if(interface->nicDriver->type == NIC_TYPE_6LOWPAN)
00481    {
00482       //In all cases, the Router Solicitation retransmissions are terminated
00483       //when a Router Advertisement is received (refer to RFC 6675 5.3)
00484       interface->ndpContext.rtrAdvReceived = TRUE;
00485    }
00486 
00487    //A Router Advertisement field (Cur Hop Limit, Reachable Time, and
00488    //Retrans Timer) may contain a value denoting that it is unspecified.
00489    //In such cases, the parameter should be ignored and the host should
00490    //continue using whatever value it is already using
00491    if(message->curHopLimit != 0)
00492    {
00493       //Get the default value that should be placed in the Hop Count
00494       //field of the IP header for outgoing IP packets
00495       interface->ipv6Context.curHopLimit = message->curHopLimit;
00496    }
00497 
00498    //A value of zero means unspecified...
00499    if(message->reachableTime != 0)
00500    {
00501       //The Reachable Time field holds the time, in milliseconds, that
00502       //a node assumes a neighbor is reachable after having received a
00503       //reachability confirmation
00504       interface->ndpContext.reachableTime = ntohl(message->reachableTime);
00505    }
00506 
00507    //A value of zero means unspecified...
00508    if(message->retransTimer != 0)
00509    {
00510       //The Retrans Timer field holds the time, in milliseconds,
00511       //between retransmitted Neighbor Solicitation messages
00512       interface->ndpContext.retransTimer = ntohl(message->retransTimer);
00513    }
00514 
00515 #if (ETH_SUPPORT == ENABLED)
00516    //Search for the Source Link-Layer Address option
00517    linkLayerAddrOption = ndpGetOption(message->options,
00518       length, NDP_OPT_SOURCE_LINK_LAYER_ADDR);
00519 
00520    //Source Link-Layer Address option found?
00521    if(linkLayerAddrOption != NULL && linkLayerAddrOption->length == 1)
00522    {
00523       //Debug message
00524       TRACE_DEBUG("  Source Link-Layer Address = %s\r\n",
00525          macAddrToString(&linkLayerAddrOption->linkLayerAddr, NULL));
00526    }
00527    else
00528    {
00529       //No valid Source Link-Layer Address option...
00530       linkLayerAddrOption = NULL;
00531    }
00532 
00533    //Search the Neighbor cache for the router
00534    entry = ndpFindNeighborCacheEntry(interface, &pseudoHeader->srcAddr);
00535 
00536    //No matching entry has been found?
00537    if(!entry)
00538    {
00539       //If the advertisement contains a Source Link-Layer Address option,
00540       //the link-layer address should be recorded in the Neighbor cache
00541       if(linkLayerAddrOption)
00542       {
00543          //Create an entry for the router
00544          entry = ndpCreateNeighborCacheEntry(interface);
00545 
00546          //Neighbor cache entry successfully created?
00547          if(entry)
00548          {
00549             //Record the IPv6 address and the corresponding MAC address
00550             entry->ipAddr = pseudoHeader->srcAddr;
00551             entry->macAddr = linkLayerAddrOption->linkLayerAddr;
00552             //The IsRouter flag must be set to TRUE
00553             entry->isRouter = TRUE;
00554             //Save current time
00555             entry->timestamp = osGetSystemTime();
00556             //The reachability state must be set to STALE
00557             entry->state = NDP_STATE_STALE;
00558          }
00559       }
00560    }
00561    else
00562    {
00563       //The sender of a Router Advertisement is implicitly assumed to be a router
00564       entry->isRouter = TRUE;
00565 
00566       //Check if the advertisement contains a Source Link-Layer Address option
00567       if(linkLayerAddrOption)
00568       {
00569          //INCOMPLETE state?
00570          if(entry->state == NDP_STATE_INCOMPLETE)
00571          {
00572             //Record link-layer address
00573             entry->macAddr = linkLayerAddrOption->linkLayerAddr;
00574             //Send all the packets that are pending for transmission
00575             n = ndpSendQueuedPackets(interface, entry);
00576             //Save current time
00577             entry->timestamp = osGetSystemTime();
00578 
00579             //Check whether any packets have been sent
00580             if(n > 0)
00581             {
00582                //Start delay timer
00583                entry->timeout = NDP_DELAY_FIRST_PROBE_TIME;
00584                //Switch to the DELAY state
00585                entry->state = NDP_STATE_DELAY;
00586             }
00587             else
00588             {
00589                //Enter the STALE state
00590                entry->state = NDP_STATE_STALE;
00591             }
00592          }
00593          //REACHABLE, STALE, DELAY or PROBE state?
00594          else
00595          {
00596             //Different link-layer address than cached?
00597             if(!macCompAddr(&entry->macAddr, &linkLayerAddrOption->linkLayerAddr))
00598             {
00599                //Update link-layer address
00600                entry->macAddr = linkLayerAddrOption->linkLayerAddr;
00601                //Save current time
00602                entry->timestamp = osGetSystemTime();
00603                //The reachability state must be set to STALE
00604                entry->state = NDP_STATE_STALE;
00605             }
00606          }
00607       }
00608    }
00609 #endif
00610 
00611    //Search for the MTU option
00612    mtuOption = ndpGetOption(message->options, length, NDP_OPT_MTU);
00613 
00614    //MTU option found?
00615    if(mtuOption != NULL && mtuOption->length == 1)
00616    {
00617       //This option specifies the recommended MTU for the link
00618       n = ntohl(mtuOption->mtu);
00619 
00620       //The host should copy the option's value so long as the value is greater
00621       //than or equal to the minimum IPv6 MTU and does not exceed the maximum
00622       //MTU of the interface
00623       if(n >= IPV6_DEFAULT_MTU && n <= interface->nicDriver->mtu)
00624       {
00625          //Save the MTU value
00626          interface->ipv6Context.linkMtu = n;
00627       }
00628    }
00629 
00630    //Point to the beginning of the Options field
00631    n = 0;
00632 
00633    //Parse Options field
00634    while(1)
00635    {
00636       //Search the Options field for any Prefix Information options
00637       prefixInfoOption = ndpGetOption(message->options + n,
00638          length - n, NDP_OPT_PREFIX_INFORMATION);
00639 
00640       //No more option of the specified type?
00641       if(prefixInfoOption == NULL)
00642          break;
00643 
00644       //Hosts use the advertised on-link prefixes to build and maintain
00645       //a list that is used in deciding when a packet's destination is
00646       //on-link or beyond a router
00647       ndpParsePrefixInfoOption(interface, prefixInfoOption);
00648 
00649       //Retrieve the offset to the current position
00650       n = (uint8_t *) prefixInfoOption - message->options;
00651       //Jump to the next option
00652       n += prefixInfoOption->length * 8;
00653    }
00654 
00655 #if (SLAAC_SUPPORT == ENABLED)
00656    //Stateless Address Autoconfiguration is currently used?
00657    if(interface->slaacContext != NULL)
00658    {
00659       //Process the valid advertisement
00660       slaacParseRouterAdv(interface->slaacContext, message,
00661          length + sizeof(NdpRouterAdvMessage));
00662    }
00663 #endif
00664 }
00665 
00666 
00667 /**
00668  * @brief Neighbor Solicitation message processing
00669  * @param[in] interface Underlying network interface
00670  * @param[in] pseudoHeader IPv6 pseudo header
00671  * @param[in] buffer Multi-part buffer containing the Neighbor Solicitation message
00672  * @param[in] offset Offset to the first byte of the message
00673  * @param[in] hopLimit Hop Limit field from IPv6 header
00674  **/
00675 
00676 void ndpProcessNeighborSol(NetInterface *interface, Ipv6PseudoHeader *pseudoHeader,
00677    const NetBuffer *buffer, size_t offset, uint8_t hopLimit)
00678 {
00679 #if (ETH_SUPPORT == ENABLED)
00680    error_t error;
00681    uint_t i;
00682    uint_t n;
00683    size_t length;
00684    bool_t validTarget;
00685    NdpNeighborSolMessage *message;
00686    NdpLinkLayerAddrOption *option;
00687    NdpNeighborCacheEntry *neighborCacheEntry;
00688    Ipv6AddrEntry *addrEntry;
00689 
00690    //Retrieve the length of the message
00691    length = netBufferGetLength(buffer) - offset;
00692 
00693    //Check the length of the Neighbor Solicitation message
00694    if(length < sizeof(NdpNeighborSolMessage))
00695       return;
00696 
00697    //Point to the beginning of the message
00698    message = netBufferAt(buffer, offset);
00699    //Sanity check
00700    if(message == NULL)
00701       return;
00702 
00703    //Debug message
00704    TRACE_INFO("Neighbor Solicitation message received (%" PRIuSIZE " bytes)...\r\n", length);
00705    //Dump message contents for debugging purpose
00706    ndpDumpNeighborSolMessage(message);
00707 
00708    //The IPv6 Hop Limit field must have a value of 255 to ensure
00709    //that the packet has not been forwarded by a router
00710    if(hopLimit != NDP_HOP_LIMIT)
00711       return;
00712 
00713    //ICMPv6 Code must be 0
00714    if(message->code)
00715       return;
00716 
00717    //If the IP source address is the unspecified address, the IP
00718    //destination address must be a solicited-node multicast address
00719    if(ipv6CompAddr(&pseudoHeader->srcAddr, &IPV6_UNSPECIFIED_ADDR) &&
00720       !ipv6IsSolicitedNodeAddr(&pseudoHeader->destAddr))
00721    {
00722       //Debug message
00723       TRACE_WARNING("Destination address must be a solicited-node address!\r\n");
00724       //Exit immediately
00725       return;
00726    }
00727 
00728    //Calculate the length of the Options field
00729    length -= sizeof(NdpNeighborSolMessage);
00730 
00731    //Parse Options field
00732    error = ndpCheckOptions(message->options, length);
00733    //All included options must have a length that is greater than zero
00734    if(error)
00735       return;
00736 
00737    //Search for the Source Link-Layer Address option
00738    option = ndpGetOption(message->options,
00739       length, NDP_OPT_SOURCE_LINK_LAYER_ADDR);
00740 
00741    //The target address must a valid unicast or anycast address assigned to
00742    //the interface or a tentative address on which DAD is being performed
00743    validTarget = FALSE;
00744 
00745    //Loop through the IPv6 addresses assigned to the interface
00746    for(i = 0; i < IPV6_ADDR_LIST_SIZE; i++)
00747    {
00748       //Point to the current entry
00749       addrEntry = &interface->ipv6Context.addrList[i];
00750 
00751       //Compare target address
00752       if(ipv6CompAddr(&addrEntry->addr, &message->targetAddr))
00753       {
00754          //Check address state
00755          if(addrEntry->state == IPV6_ADDR_STATE_TENTATIVE)
00756          {
00757             //If the source address of the Neighbor Solicitation is the
00758             //unspecified address, the solicitation is from a node
00759             //performing Duplicate Address Detection
00760             if(ipv6CompAddr(&pseudoHeader->srcAddr, &IPV6_UNSPECIFIED_ADDR))
00761             {
00762                //The source link-layer address must not be included when the
00763                //source IP address is the unspecified address...
00764                if(option == NULL)
00765                {
00766                   //Debug message
00767                   TRACE_WARNING("The tentative address %s is a duplicate!\r\n",
00768                      ipv6AddrToString(&addrEntry->addr, NULL));
00769 
00770                   //The tentative address is a duplicate and should not be used
00771                   addrEntry->duplicate = TRUE;
00772                }
00773             }
00774 
00775             //In all cases, a node must not respond to a Neighbor Solicitation
00776             //for a tentative address
00777             return;
00778          }
00779          else if(addrEntry->state != IPV6_ADDR_STATE_INVALID)
00780          {
00781             //The target address is a valid address assigned to the interface
00782             validTarget = TRUE;
00783             //We are done
00784             break;
00785          }
00786       }
00787    }
00788 
00789    //Invalid target address?
00790    if(!validTarget)
00791    {
00792       //The Neighbor Solicitation must be discarded if the target address
00793       //is not a valid anycast address assigned to the interface
00794       if(!ipv6IsAnycastAddr(interface, &message->targetAddr))
00795       {
00796          //Debug message
00797          TRACE_WARNING("Wrong target address!\r\n");
00798          //Exit immediately
00799          return;
00800       }
00801    }
00802 
00803    //Source Link-Layer Address option found?
00804    if(option != NULL && option->length == 1)
00805    {
00806       //Debug message
00807       TRACE_DEBUG("  Source Link-Layer Address = %s\r\n",
00808          macAddrToString(&option->linkLayerAddr, NULL));
00809 
00810       //The Source Link-Layer Address option must not be included when the
00811       //source IP address is the unspecified address
00812       if(ipv6CompAddr(&pseudoHeader->srcAddr, &IPV6_UNSPECIFIED_ADDR))
00813          return;
00814 
00815       //Search the Neighbor Cache for the source address of the solicitation
00816       neighborCacheEntry = ndpFindNeighborCacheEntry(interface, &pseudoHeader->srcAddr);
00817 
00818       //No matching entry has been found?
00819       if(!neighborCacheEntry)
00820       {
00821          //Create an entry
00822          neighborCacheEntry = ndpCreateNeighborCacheEntry(interface);
00823 
00824          //Neighbor Cache entry successfully created?
00825          if(neighborCacheEntry)
00826          {
00827             //Record the IPv6 and the corresponding MAC address
00828             neighborCacheEntry->ipAddr = pseudoHeader->srcAddr;
00829             neighborCacheEntry->macAddr = option->linkLayerAddr;
00830             //Save current time
00831             neighborCacheEntry->timestamp = osGetSystemTime();
00832             //Enter the STALE state
00833             neighborCacheEntry->state = NDP_STATE_STALE;
00834          }
00835       }
00836       else
00837       {
00838          //INCOMPLETE state?
00839          if(neighborCacheEntry->state == NDP_STATE_INCOMPLETE)
00840          {
00841             //Record link-layer address
00842             neighborCacheEntry->macAddr = option->linkLayerAddr;
00843             //Send all the packets that are pending for transmission
00844             n = ndpSendQueuedPackets(interface, neighborCacheEntry);
00845             //Save current time
00846             neighborCacheEntry->timestamp = osGetSystemTime();
00847 
00848             //Check whether any packets have been sent
00849             if(n > 0)
00850             {
00851                //Start delay timer
00852                neighborCacheEntry->timeout = NDP_DELAY_FIRST_PROBE_TIME;
00853                //Switch to the DELAY state
00854                neighborCacheEntry->state = NDP_STATE_DELAY;
00855             }
00856             else
00857             {
00858                //Enter the STALE state
00859                neighborCacheEntry->state = NDP_STATE_STALE;
00860             }
00861          }
00862          //REACHABLE, STALE, DELAY or PROBE state?
00863          else
00864          {
00865             //Different link-layer address than cached?
00866             if(!macCompAddr(&neighborCacheEntry->macAddr, &option->linkLayerAddr))
00867             {
00868                //Update link-layer address
00869                neighborCacheEntry->macAddr = option->linkLayerAddr;
00870                //Save current time
00871                neighborCacheEntry->timestamp = osGetSystemTime();
00872                //Enter the STALE state
00873                neighborCacheEntry->state = NDP_STATE_STALE;
00874             }
00875          }
00876       }
00877    }
00878    //Source Link-Layer Address option not found?
00879    else
00880    {
00881       //The Source Link-Layer Address option must not be included when the
00882       //source IP address is the unspecified address. Otherwise, this option
00883       //must be included in multicast solicitations
00884       if(!ipv6CompAddr(&pseudoHeader->srcAddr, &IPV6_UNSPECIFIED_ADDR) &&
00885          ipv6IsMulticastAddr(&pseudoHeader->destAddr))
00886       {
00887          //Debug message
00888          TRACE_WARNING("The Source Link-Layer Address must be included!\r\n");
00889          //Exit immediately
00890          return;
00891       }
00892    }
00893 
00894    //After any updates to the Neighbor cache, the node sends a Neighbor
00895    //Advertisement response as described in RFC 4861 7.2.4
00896    ndpSendNeighborAdv(interface, &message->targetAddr, &pseudoHeader->srcAddr);
00897 #endif
00898 }
00899 
00900 
00901 /**
00902  * @brief Neighbor Advertisement message processing
00903  * @param[in] interface Underlying network interface
00904  * @param[in] pseudoHeader IPv6 pseudo header
00905  * @param[in] buffer Multi-part buffer containing the Neighbor Advertisement message
00906  * @param[in] offset Offset to the first byte of the message
00907  * @param[in] hopLimit Hop Limit field from IPv6 header
00908  **/
00909 
00910 void ndpProcessNeighborAdv(NetInterface *interface, Ipv6PseudoHeader *pseudoHeader,
00911    const NetBuffer *buffer, size_t offset, uint8_t hopLimit)
00912 {
00913 #if (ETH_SUPPORT == ENABLED)
00914    error_t error;
00915    uint_t i;
00916    uint_t n;
00917    size_t length;
00918    bool_t differentLinkLayerAddr;
00919    NdpNeighborAdvMessage *message;
00920    NdpLinkLayerAddrOption *option;
00921    NdpNeighborCacheEntry *neighborCacheEntry;
00922    Ipv6AddrEntry *addrEntry;
00923 
00924    //Retrieve the length of the message
00925    length = netBufferGetLength(buffer) - offset;
00926 
00927    //Check the length of the Neighbor Advertisement message
00928    if(length < sizeof(NdpNeighborAdvMessage))
00929       return;
00930 
00931    //Point to the beginning of the message
00932    message = netBufferAt(buffer, offset);
00933    //Sanity check
00934    if(message == NULL)
00935       return;
00936 
00937    //Debug message
00938    TRACE_INFO("Neighbor Advertisement message received (%" PRIuSIZE " bytes)...\r\n", length);
00939    //Dump message contents for debugging purpose
00940    ndpDumpNeighborAdvMessage(message);
00941 
00942    //The IPv6 Hop Limit field must have a value of 255 to ensure
00943    //that the packet has not been forwarded by a router
00944    if(hopLimit != NDP_HOP_LIMIT)
00945       return;
00946 
00947    //ICMPv6 Code must be 0
00948    if(message->code)
00949       return;
00950 
00951    //The target address must not be a multicast address
00952    if(ipv6IsMulticastAddr(&message->targetAddr))
00953    {
00954       //Debug message
00955       TRACE_WARNING("Target address must not be a multicast address!\r\n");
00956       //Exit immediately
00957       return;
00958    }
00959 
00960    //If the destination address is a multicast address
00961    //then the Solicited flag must be zero
00962    if(ipv6IsMulticastAddr(&pseudoHeader->destAddr) && message->s)
00963    {
00964       //Debug message
00965       TRACE_WARNING("Solicited flag must be zero!\r\n");
00966       //Exit immediately
00967       return;
00968    }
00969 
00970    //Calculate the length of the Options field
00971    length -= sizeof(NdpNeighborAdvMessage);
00972 
00973    //Parse Options field
00974    error = ndpCheckOptions(message->options, length);
00975    //All included options must have a length that is greater than zero
00976    if(error)
00977       return;
00978 
00979    //Duplicate address detection
00980    for(i = 0; i < IPV6_ADDR_LIST_SIZE; i++)
00981    {
00982       //Point to the current entry
00983       addrEntry = &interface->ipv6Context.addrList[i];
00984 
00985       //Valid entry?
00986       if(addrEntry->state != IPV6_ADDR_STATE_INVALID)
00987       {
00988          //Check whether the target address is tentative or matches
00989          //a unicast address assigned to the interface
00990          if(ipv6CompAddr(&addrEntry->addr, &message->targetAddr))
00991          {
00992             //Debug message
00993             TRACE_WARNING("The address %s is a duplicate!\r\n",
00994                ipv6AddrToString(&addrEntry->addr, NULL));
00995 
00996             //The address is a duplicate and should not be used
00997             addrEntry->duplicate = TRUE;
00998             //Exit immediately
00999             return;
01000          }
01001       }
01002    }
01003 
01004    //Search the Neighbor cache for the specified target address
01005    neighborCacheEntry = ndpFindNeighborCacheEntry(interface, &message->targetAddr);
01006 
01007    //If no entry exists, the advertisement should be silently discarded
01008    if(neighborCacheEntry)
01009    {
01010       //This flag tells whether the supplied link-layer
01011       //address differs from that in the cache
01012       differentLinkLayerAddr = FALSE;
01013 
01014       //Search for the Target Link-Layer Address option
01015       option = ndpGetOption(message->options,
01016          length, NDP_OPT_TARGET_LINK_LAYER_ADDR);
01017 
01018       //Target Link-Layer Address option found?
01019       if(option != NULL && option->length == 1)
01020       {
01021          //Debug message
01022          TRACE_DEBUG("  Target Link-Layer Address = %s\r\n",
01023             macAddrToString(&option->linkLayerAddr, NULL));
01024 
01025          //Different link-layer address than cached?
01026          if(!macCompAddr(&neighborCacheEntry->macAddr, &option->linkLayerAddr))
01027             differentLinkLayerAddr = TRUE;
01028       }
01029 
01030       //INCOMPLETE state?
01031       if(neighborCacheEntry->state == NDP_STATE_INCOMPLETE)
01032       {
01033          //If no Target Link-Layer Address option is included, the receiving
01034          //node should silently discard the received advertisement
01035          if(option != NULL && option->length == 1)
01036          {
01037             //Record the link-layer address
01038             neighborCacheEntry->macAddr = option->linkLayerAddr;
01039             //Send all the packets that are pending for transmission
01040             n = ndpSendQueuedPackets(interface, neighborCacheEntry);
01041             //Save current time
01042             neighborCacheEntry->timestamp = osGetSystemTime();
01043 
01044             //Solicited flag is set?
01045             if(message->s)
01046             {
01047                //Computing the random ReachableTime value
01048                neighborCacheEntry->timeout = interface->ndpContext.reachableTime;
01049                //Switch to the REACHABLE state
01050                neighborCacheEntry->state = NDP_STATE_REACHABLE;
01051             }
01052             else
01053             {
01054                //Check whether any packets have been sent
01055                if(n > 0)
01056                {
01057                   //Start delay timer
01058                   neighborCacheEntry->timeout = NDP_DELAY_FIRST_PROBE_TIME;
01059                   //Switch to the DELAY state
01060                   neighborCacheEntry->state = NDP_STATE_DELAY;
01061                }
01062                else
01063                {
01064                   //Enter the STALE state
01065                   neighborCacheEntry->state = NDP_STATE_STALE;
01066                }
01067             }
01068          }
01069       }
01070       //REACHABLE, STALE, DELAY or PROBE state?
01071       else
01072       {
01073          //Check whether the Override flag is clear and the supplied
01074          //link-layer address differs from that in the cache
01075          if(!message->o && differentLinkLayerAddr)
01076          {
01077             //REACHABLE state?
01078             if(neighborCacheEntry->state == NDP_STATE_REACHABLE)
01079             {
01080                //Save current time
01081                neighborCacheEntry->timestamp = osGetSystemTime();
01082                //Enter the STALE state
01083                neighborCacheEntry->state = NDP_STATE_STALE;
01084             }
01085          }
01086          else
01087          {
01088             //Solicited flag is set?
01089             if(message->s)
01090             {
01091                //Different link-layer address than cached?
01092                if(differentLinkLayerAddr)
01093                {
01094                   //The link-layer address must be inserted in the cache
01095                   neighborCacheEntry->macAddr = option->linkLayerAddr;
01096                }
01097 
01098                //Save current time
01099                neighborCacheEntry->timestamp = osGetSystemTime();
01100                //Computing the random ReachableTime value
01101                neighborCacheEntry->timeout = interface->ndpContext.reachableTime;
01102                //Switch to the REACHABLE state
01103                neighborCacheEntry->state = NDP_STATE_REACHABLE;
01104             }
01105             else
01106             {
01107                //Different link-layer address than cached?
01108                if(differentLinkLayerAddr)
01109                {
01110                   //The link-layer address must be inserted in the cache
01111                   neighborCacheEntry->macAddr = option->linkLayerAddr;
01112                   //Save current time
01113                   neighborCacheEntry->timestamp = osGetSystemTime();
01114                   //The state must be set to STALE
01115                   neighborCacheEntry->state = NDP_STATE_STALE;
01116                }
01117             }
01118          }
01119       }
01120 
01121       //The IsRouter flag in the cache entry must be set based
01122       //on the Router flag in the received advertisement
01123       if(message->r)
01124       {
01125          //The neighbor is a router
01126          neighborCacheEntry->isRouter = TRUE;
01127       }
01128       else
01129       {
01130          //Check whether the IsRouter flag changes from TRUE to FALSE
01131          //as a result of this update
01132          if(neighborCacheEntry->isRouter)
01133          {
01134             //The node must remove that router from the Default Router list
01135             //and update the Destination cache entries for all destinations
01136             //using that neighbor as a router
01137             ipv6RemoveDefaultRouter(interface, &neighborCacheEntry->ipAddr);
01138          }
01139 
01140          //The neighbor is a host
01141          neighborCacheEntry->isRouter = FALSE;
01142       }
01143    }
01144 #endif
01145 }
01146 
01147 
01148 /**
01149  * @brief Redirect message processing
01150  * @param[in] interface Underlying network interface
01151  * @param[in] pseudoHeader IPv6 pseudo header
01152  * @param[in] buffer Multi-part buffer containing the Redirect message
01153  * @param[in] offset Offset to the first byte of the message
01154  * @param[in] hopLimit Hop Limit field from IPv6 header
01155  **/
01156 
01157 void ndpProcessRedirect(NetInterface *interface, Ipv6PseudoHeader *pseudoHeader,
01158    const NetBuffer *buffer, size_t offset, uint8_t hopLimit)
01159 {
01160 #if (ETH_SUPPORT == ENABLED)
01161    error_t error;
01162    uint_t n;
01163    size_t length;
01164    NdpRedirectMessage *message;
01165    NdpLinkLayerAddrOption *option;
01166    NdpNeighborCacheEntry *neighborCacheEntry;
01167    NdpDestCacheEntry *destCacheEntry;
01168 
01169    //Retrieve the length of the message
01170    length = netBufferGetLength(buffer) - offset;
01171 
01172    //Check the length of the Redirect message
01173    if(length < sizeof(NdpRedirectMessage))
01174       return;
01175 
01176    //Point to the beginning of the message
01177    message = netBufferAt(buffer, offset);
01178    //Sanity check
01179    if(message == NULL)
01180       return;
01181 
01182    //Debug message
01183    TRACE_INFO("Redirect message received (%" PRIuSIZE " bytes)...\r\n", length);
01184    //Dump message contents for debugging purpose
01185    ndpDumpRedirectMessage(message);
01186 
01187    //The IPv6 Hop Limit field must have a value of 255 to ensure
01188    //that the packet has not been forwarded by a router
01189    if(hopLimit != NDP_HOP_LIMIT)
01190       return;
01191 
01192    //ICMPv6 Code must be 0
01193    if(message->code)
01194       return;
01195 
01196    //Routers must use their link-local address as the source for Redirect
01197    //messages so that hosts can uniquely identify routers
01198    if(!ipv6IsLinkLocalUnicastAddr(&pseudoHeader->srcAddr))
01199       return;
01200 
01201    //The IP source address of the Redirect must be the same as the current
01202    //first-hop router for the specified Destination address
01203    if(!ndpIsFirstHopRouter(interface, &message->destAddr, &pseudoHeader->srcAddr))
01204       return;
01205 
01206    //The Destination Address field in the Redirect message must not
01207    //contain a multicast address
01208    if(ipv6IsMulticastAddr(&message->destAddr))
01209       return;
01210 
01211    //The Target Address must be either a link-local address (when redirected
01212    //to a router) or the same as the Destination Address (when redirected to
01213    //the on-link destination)
01214    if(!ipv6IsLinkLocalUnicastAddr(&message->targetAddr) &&
01215       !ipv6CompAddr(&message->targetAddr, &message->destAddr))
01216    {
01217       //Silently discard the received Redirect message
01218       return;
01219    }
01220 
01221    //Calculate the length of the Options field
01222    length -= sizeof(NdpNeighborAdvMessage);
01223 
01224    //Parse Options field
01225    error = ndpCheckOptions(message->options, length);
01226    //All included options must have a length that is greater than zero
01227    if(error)
01228       return;
01229 
01230    //Search the Destination cache for the specified address
01231    destCacheEntry = ndpFindDestCacheEntry(interface, &message->destAddr);
01232 
01233    //Check whether a corresponding Destination cache entry exists
01234    if(destCacheEntry)
01235    {
01236       //The entry is updated with information learned from Redirect messages
01237       destCacheEntry->nextHop = message->targetAddr;
01238       //Save current time
01239       destCacheEntry->timestamp = osGetSystemTime();
01240    }
01241    else
01242    {
01243       //If no Destination Cache entry exists for the destination, an
01244       //implementation should create such an entry
01245       destCacheEntry = ndpCreateDestCacheEntry(interface);
01246 
01247       //Destination cache entry successfully created?
01248       if(destCacheEntry)
01249       {
01250          //Destination address
01251          destCacheEntry->destAddr = message->destAddr;
01252          //Address of the next hop
01253          destCacheEntry->nextHop = message->targetAddr;
01254 
01255          //Initially, the PMTU value for a path is assumed to be
01256          //the MTU of the first-hop link
01257          destCacheEntry->pathMtu = interface->ipv6Context.linkMtu;
01258 
01259          //Save current time
01260          destCacheEntry->timestamp = osGetSystemTime();
01261       }
01262    }
01263 
01264    //Search for the Target Link-Layer Address option
01265    option = ndpGetOption(message->options,
01266       length, NDP_OPT_TARGET_LINK_LAYER_ADDR);
01267 
01268    //If the Redirect contains a Target Link-Layer Address option, the host
01269    //either creates or updates the Neighbor Cache entry for the target
01270    if(option != NULL && option->length == 1)
01271    {
01272       //Debug message
01273       TRACE_DEBUG("  Target Link-Layer Address = %s\r\n",
01274          macAddrToString(&option->linkLayerAddr, NULL));
01275 
01276       //Search the Neighbor cache for the specified target address
01277       neighborCacheEntry = ndpFindNeighborCacheEntry(interface, &message->targetAddr);
01278 
01279       //No matching entry has been found?
01280       if(!neighborCacheEntry)
01281       {
01282          //Create an entry for the target
01283          neighborCacheEntry = ndpCreateNeighborCacheEntry(interface);
01284 
01285          //Neighbor cache entry successfully created?
01286          if(neighborCacheEntry)
01287          {
01288             //Record the Target address
01289             neighborCacheEntry->ipAddr = message->targetAddr;
01290             //The cached link-layer address is copied from the option
01291             neighborCacheEntry->macAddr = option->linkLayerAddr;
01292             //Newly created Neighbor Cache entries should set the IsRouter flag to FALSE
01293             neighborCacheEntry->isRouter = FALSE;
01294             //Save current time
01295             neighborCacheEntry->timestamp = osGetSystemTime();
01296             //The reachability state must be set to STALE
01297             neighborCacheEntry->state = NDP_STATE_STALE;
01298          }
01299       }
01300       else
01301       {
01302          //If the Target Address is not the same as the Destination Address,
01303          //the host must set IsRouter to TRUE for the target
01304          if(!ipv6CompAddr(&message->targetAddr, &message->destAddr))
01305             neighborCacheEntry->isRouter = TRUE;
01306 
01307          //INCOMPLETE state?
01308          if(neighborCacheEntry->state == NDP_STATE_INCOMPLETE)
01309          {
01310             //Record link-layer address
01311             neighborCacheEntry->macAddr = option->linkLayerAddr;
01312             //Send all the packets that are pending for transmission
01313             n = ndpSendQueuedPackets(interface, neighborCacheEntry);
01314             //Save current time
01315             neighborCacheEntry->timestamp = osGetSystemTime();
01316 
01317             //Check whether any packets have been sent
01318             if(n > 0)
01319             {
01320                //Start delay timer
01321                neighborCacheEntry->timeout = NDP_DELAY_FIRST_PROBE_TIME;
01322                //Switch to the DELAY state
01323                neighborCacheEntry->state = NDP_STATE_DELAY;
01324             }
01325             else
01326             {
01327                //Enter the STALE state
01328                neighborCacheEntry->state = NDP_STATE_STALE;
01329             }
01330          }
01331          //REACHABLE, STALE, DELAY or PROBE state?
01332          else
01333          {
01334             //Different link-layer address than cached?
01335             if(!macCompAddr(&neighborCacheEntry->macAddr, &option->linkLayerAddr))
01336             {
01337                //Update link-layer address
01338                neighborCacheEntry->macAddr = option->linkLayerAddr;
01339                //Save current time
01340                neighborCacheEntry->timestamp = osGetSystemTime();
01341                //The reachability state must be set to STALE
01342                neighborCacheEntry->state = NDP_STATE_STALE;
01343             }
01344          }
01345       }
01346    }
01347 #endif
01348 }
01349 
01350 
01351 /**
01352  * @brief Send a Router Solicitation message
01353  * @param[in] interface Underlying network interface
01354  * @return Error code
01355  **/
01356 
01357 error_t ndpSendRouterSol(NetInterface *interface)
01358 {
01359    error_t error;
01360    size_t offset;
01361    size_t length;
01362    NetBuffer *buffer;
01363    NdpRouterSolMessage *message;
01364    Ipv6PseudoHeader pseudoHeader;
01365 
01366    //The destination address is typically the all-routers multicast address
01367    pseudoHeader.destAddr = IPV6_LINK_LOCAL_ALL_ROUTERS_ADDR;
01368 
01369    //Select the most appropriate source address to be used when
01370    //sending the Router Solicitation message
01371    error = ipv6SelectSourceAddr(&interface,
01372       &pseudoHeader.destAddr, &pseudoHeader.srcAddr);
01373 
01374    //No address assigned to the interface?
01375    if(error)
01376    {
01377       //Use the unspecified address if no address is assigned
01378       //to the sending interface
01379       pseudoHeader.srcAddr = IPV6_UNSPECIFIED_ADDR;
01380    }
01381 
01382    //The only defined option that may appear in a Router Solicitation
01383    //message is the Source Link-Layer Address option
01384    length = sizeof(NdpRouterSolMessage) + sizeof(NdpLinkLayerAddrOption);
01385 
01386    //Allocate a memory buffer to hold the Router Solicitation message
01387    buffer = ipAllocBuffer(length, &offset);
01388    //Failed to allocate memory?
01389    if(buffer == NULL)
01390       return ERROR_OUT_OF_MEMORY;
01391 
01392    //Point to the beginning of the message
01393    message = netBufferAt(buffer, offset);
01394 
01395    //Format Router Solicitation message
01396    message->type = ICMPV6_TYPE_ROUTER_SOL;
01397    message->code = 0;
01398    message->checksum = 0;
01399    message->reserved = 0;
01400 
01401    //Length of the message, excluding any option
01402    length = sizeof(NdpRouterSolMessage);
01403 
01404    //The Source Link-Layer Address option must not be included
01405    //when the source IPv6 address is the unspecified address
01406    if(!ipv6CompAddr(&pseudoHeader.srcAddr, &IPV6_UNSPECIFIED_ADDR))
01407    {
01408 #if (ETH_SUPPORT == ENABLED)
01409       //Check whether a MAC address has been assigned to the interface
01410       if(!macCompAddr(&interface->macAddr, &MAC_UNSPECIFIED_ADDR))
01411       {
01412          //Add Source Link-Layer Address option
01413          ndpAddOption(message, &length, NDP_OPT_SOURCE_LINK_LAYER_ADDR,
01414             &interface->macAddr, sizeof(MacAddr));
01415       }
01416 #endif
01417    }
01418 
01419    //Adjust the length of the multi-part buffer
01420    netBufferSetLength(buffer, offset + length);
01421 
01422    //Format IPv6 pseudo header
01423    pseudoHeader.length = htonl(length);
01424    pseudoHeader.reserved = 0;
01425    pseudoHeader.nextHeader = IPV6_ICMPV6_HEADER;
01426 
01427    //Calculate ICMPv6 header checksum
01428    message->checksum = ipCalcUpperLayerChecksumEx(&pseudoHeader,
01429       sizeof(Ipv6PseudoHeader), buffer, offset, length);
01430 
01431    //Debug message
01432    TRACE_INFO("Sending Router Solicitation message (%" PRIuSIZE " bytes)...\r\n", length);
01433    //Dump message contents for debugging purpose
01434    ndpDumpRouterSolMessage(message);
01435 
01436    //Send Router Solicitation message
01437    error = ipv6SendDatagram(interface, &pseudoHeader, buffer, offset, NDP_HOP_LIMIT);
01438 
01439    //Free previously allocated memory
01440    netBufferFree(buffer);
01441    //Return status code
01442    return error;
01443 }
01444 
01445 
01446 /**
01447  * @brief Send a Neighbor Solicitation message
01448  * @param[in] interface Underlying network interface
01449  * @param[in] targetIpAddr Target IPv6 address
01450  * @param[in] multicast Unicast or unicast Neighbor Solicitation message
01451  * @return Error code
01452  **/
01453 
01454 error_t ndpSendNeighborSol(NetInterface *interface,
01455    const Ipv6Addr *targetIpAddr, bool_t multicast)
01456 {
01457    error_t error;
01458    size_t offset;
01459    size_t length;
01460    NetBuffer *buffer;
01461    NdpNeighborSolMessage *message;
01462    Ipv6PseudoHeader pseudoHeader;
01463 
01464    //Multicast Neighbor Solicitation message?
01465    if(multicast)
01466    {
01467       //Compute the solicited-node multicast address that
01468       //corresponds to the target IPv6 address
01469       ipv6ComputeSolicitedNodeAddr(targetIpAddr, &pseudoHeader.destAddr);
01470    }
01471    else
01472    {
01473       //Unicast Neighbor Solicitation message
01474       pseudoHeader.destAddr = *targetIpAddr;
01475    }
01476 
01477    //Check whether the target address is a tentative address
01478    if(ipv6IsTentativeAddr(interface, targetIpAddr))
01479    {
01480       //The IPv6 source is set to the unspecified address
01481       pseudoHeader.srcAddr = IPV6_UNSPECIFIED_ADDR;
01482    }
01483    else
01484    {
01485       //Select the most appropriate source address to be used
01486       //when sending the Neighbor Solicitation message
01487       error = ipv6SelectSourceAddr(&interface,
01488          targetIpAddr, &pseudoHeader.srcAddr);
01489 
01490       //No address assigned to the interface?
01491       if(error)
01492          return error;
01493    }
01494 
01495    //The only defined option that may appear in a Neighbor Solicitation
01496    //message is the Source Link-Layer Address option
01497    length = sizeof(NdpNeighborSolMessage) + sizeof(NdpLinkLayerAddrOption);
01498 
01499    //Allocate a memory buffer to hold the Neighbor Solicitation message
01500    buffer = ipAllocBuffer(length, &offset);
01501    //Failed to allocate memory?
01502    if(buffer == NULL)
01503       return ERROR_OUT_OF_MEMORY;
01504 
01505    //Point to the beginning of the message
01506    message = netBufferAt(buffer, offset);
01507 
01508    //Format Neighbor Solicitation message
01509    message->type = ICMPV6_TYPE_NEIGHBOR_SOL;
01510    message->code = 0;
01511    message->checksum = 0;
01512    message->reserved = 0;
01513    message->targetAddr = *targetIpAddr;
01514 
01515    //Length of the message, excluding any option
01516    length = sizeof(NdpNeighborSolMessage);
01517 
01518    //The Source Link-Layer Address option must not be included
01519    //when the source IPv6 address is the unspecified address
01520    if(!ipv6CompAddr(&pseudoHeader.srcAddr, &IPV6_UNSPECIFIED_ADDR))
01521    {
01522 #if (ETH_SUPPORT == ENABLED)
01523       //Add Source Link-Layer Address option
01524       ndpAddOption(message, &length, NDP_OPT_SOURCE_LINK_LAYER_ADDR,
01525          &interface->macAddr, sizeof(MacAddr));
01526 #endif
01527    }
01528 
01529    //Adjust the length of the multi-part buffer
01530    netBufferSetLength(buffer, offset + length);
01531 
01532    //Format IPv6 pseudo header
01533    pseudoHeader.length = htonl(length);
01534    pseudoHeader.reserved = 0;
01535    pseudoHeader.nextHeader = IPV6_ICMPV6_HEADER;
01536 
01537    //Calculate ICMPv6 header checksum
01538    message->checksum = ipCalcUpperLayerChecksumEx(&pseudoHeader,
01539       sizeof(Ipv6PseudoHeader), buffer, offset, length);
01540 
01541    //Debug message
01542    TRACE_INFO("Sending Neighbor Solicitation message (%" PRIuSIZE " bytes)...\r\n", length);
01543    //Dump message contents for debugging purpose
01544    ndpDumpNeighborSolMessage(message);
01545 
01546    //Send Neighbor Solicitation message
01547    error = ipv6SendDatagram(interface, &pseudoHeader, buffer, offset, NDP_HOP_LIMIT);
01548 
01549    //Free previously allocated memory
01550    netBufferFree(buffer);
01551    //Return status code
01552    return error;
01553 }
01554 
01555 
01556 /**
01557  * @brief Send a Neighbor Advertisement message
01558  * @param[in] interface Underlying network interface
01559  * @param[in] targetIpAddr Target IPv6 address
01560  * @param[in] destIpAddr Destination IPv6 address
01561  * @return Error code
01562  **/
01563 
01564 error_t ndpSendNeighborAdv(NetInterface *interface,
01565    const Ipv6Addr *targetIpAddr, const Ipv6Addr *destIpAddr)
01566 {
01567    error_t error;
01568    size_t offset;
01569    size_t length;
01570    NetBuffer *buffer;
01571    NdpNeighborAdvMessage *message;
01572    Ipv6PseudoHeader pseudoHeader;
01573 
01574    //Destination IP address is the unspecified address?
01575    if(ipv6CompAddr(destIpAddr, &IPV6_UNSPECIFIED_ADDR))
01576    {
01577       //If the destination is the unspecified address, the node must
01578       //multicast the advertisement to the all-nodes address
01579       pseudoHeader.destAddr = IPV6_LINK_LOCAL_ALL_NODES_ADDR;
01580    }
01581    else
01582    {
01583       //Otherwise, the node must unicast the advertisement to
01584       //the destination IP address
01585       pseudoHeader.destAddr = *destIpAddr;
01586    }
01587 
01588    //Check whether the target address is a valid anycast address
01589    //assigned to the interface
01590    if(ipv6IsAnycastAddr(interface, targetIpAddr))
01591    {
01592       //Select the most appropriate source address to be used
01593       //when sending the Neighbor Advertisement message
01594       error = ipv6SelectSourceAddr(&interface,
01595          targetIpAddr, &pseudoHeader.srcAddr);
01596 
01597       //No address assigned to the interface?
01598       if(error)
01599          return error;
01600    }
01601    else
01602    {
01603       //Set the source IP address
01604       pseudoHeader.srcAddr = *targetIpAddr;
01605    }
01606 
01607    //The only defined option that may appear in a Neighbor Advertisement
01608    //message is the Target Link-Layer Address option
01609    length = sizeof(NdpNeighborAdvMessage) + sizeof(NdpLinkLayerAddrOption);
01610 
01611    //Allocate a memory buffer to hold the Neighbor Advertisement message
01612    buffer = ipAllocBuffer(length, &offset);
01613    //Failed to allocate memory?
01614    if(buffer == NULL)
01615       return ERROR_OUT_OF_MEMORY;
01616 
01617    //Point to the beginning of the message
01618    message = netBufferAt(buffer, offset);
01619 
01620    //Format Neighbor Advertisement message
01621    message->type = ICMPV6_TYPE_NEIGHBOR_ADV;
01622    message->code = 0;
01623    message->checksum = 0;
01624    message->reserved1 = 0;
01625    message->reserved2 = 0;
01626    message->targetAddr = *targetIpAddr;
01627 
01628    //The Router flag indicates that the sender is a router
01629    if(interface->ipv6Context.isRouter)
01630       message->r = TRUE;
01631    else
01632       message->r = FALSE;
01633 
01634    //If the destination is the unspecified address, the node must set
01635    //the Solicited flag to zero
01636    if(ipv6CompAddr(destIpAddr, &IPV6_UNSPECIFIED_ADDR))
01637       message->s = FALSE;
01638    else
01639       message->s = TRUE;
01640 
01641    //The Override flag should not be set in solicited advertisements
01642    //for anycast addresses
01643    if(ipv6IsAnycastAddr(interface, targetIpAddr))
01644       message->o = FALSE;
01645    else
01646       message->o = TRUE;
01647 
01648    //Length of the message, excluding any option
01649    length = sizeof(NdpNeighborAdvMessage);
01650 
01651 #if (ETH_SUPPORT == ENABLED)
01652    //Add Target Link-Layer Address option
01653    ndpAddOption(message, &length, NDP_OPT_TARGET_LINK_LAYER_ADDR,
01654       &interface->macAddr, sizeof(MacAddr));
01655 #endif
01656 
01657    //Adjust the length of the multi-part buffer
01658    netBufferSetLength(buffer, offset + length);
01659 
01660    //Format IPv6 pseudo header
01661    pseudoHeader.length = htonl(length);
01662    pseudoHeader.reserved = 0;
01663    pseudoHeader.nextHeader = IPV6_ICMPV6_HEADER;
01664 
01665    //Calculate ICMPv6 header checksum
01666    message->checksum = ipCalcUpperLayerChecksumEx(&pseudoHeader,
01667       sizeof(Ipv6PseudoHeader), buffer, offset, length);
01668 
01669    //Debug message
01670    TRACE_INFO("Sending Neighbor Advertisement message (%" PRIuSIZE " bytes)...\r\n", length);
01671    //Dump message contents for debugging purpose
01672    ndpDumpNeighborAdvMessage(message);
01673 
01674    //Send Neighbor Advertisement message
01675    error = ipv6SendDatagram(interface, &pseudoHeader, buffer, offset, NDP_HOP_LIMIT);
01676 
01677    //Free previously allocated memory
01678    netBufferFree(buffer);
01679    //Return status code
01680    return error;
01681 }
01682 
01683 
01684 /**
01685  * @brief Send a Redirect message
01686  * @param[in] interface Underlying network interface
01687  * @param[in] targetAddr IPv6 address that is a better first hop to use
01688  *   for the destination address
01689  * @param[in] ipPacket Multi-part buffer that holds the IPv6 packet that
01690  *   triggered the sending of the Redirect
01691  * @param[in] ipPacketOffset Offset to the first byte of the IPv6 packet
01692  * @return Error code
01693  **/
01694 
01695 error_t ndpSendRedirect(NetInterface *interface, const Ipv6Addr *targetAddr,
01696    const NetBuffer *ipPacket, size_t ipPacketOffset)
01697 {
01698    error_t error;
01699    size_t offset;
01700    size_t length;
01701    size_t ipPacketLength;
01702    size_t optionLength;
01703    size_t paddingLength;
01704    NetBuffer *buffer;
01705    NdpRedirectMessage *message;
01706    NdpRedirectedHeaderOption *option;
01707    NdpNeighborCacheEntry *entry;
01708    Ipv6Header *ipHeader;
01709    Ipv6PseudoHeader pseudoHeader;
01710    uint8_t padding[8];
01711 
01712    //Retrieve the length of the forwarded IPv6 packet
01713    ipPacketLength = netBufferGetLength(ipPacket) - ipPacketOffset;
01714 
01715    //Check the length of the IPv6 packet
01716    if(ipPacketLength < sizeof(Ipv6Header))
01717       return ERROR_INVALID_LENGTH;
01718 
01719    //Point to the header of the invoking packet
01720    ipHeader = netBufferAt(ipPacket, ipPacketOffset);
01721    //Sanity check
01722    if(ipHeader == NULL)
01723       return ERROR_FAILURE;
01724 
01725    //The only defined options that may appear in a Redirect message are the
01726    //Target Link-Layer Address option and the Redirected Header option
01727    length = sizeof(NdpRedirectMessage) + sizeof(NdpLinkLayerAddrOption) +
01728       sizeof(NdpRedirectedHeaderOption);
01729 
01730    //Allocate a memory buffer to hold the Redirect message
01731    buffer = ipAllocBuffer(length, &offset);
01732    //Failed to allocate memory?
01733    if(buffer == NULL)
01734       return ERROR_OUT_OF_MEMORY;
01735 
01736    //Point to the beginning of the message
01737    message = netBufferAt(buffer, offset);
01738 
01739    //Format Redirect message
01740    message->type = ICMPV6_TYPE_REDIRECT;
01741    message->code = 0;
01742    message->checksum = 0;
01743    message->reserved = 0;
01744    message->targetAddr = *targetAddr;
01745    message->destAddr = ipHeader->destAddr;
01746 
01747    //Length of the message, excluding any option
01748    length = sizeof(NdpRedirectMessage);
01749 
01750    //Search the Neighbor cache for the specified target address
01751    entry = ndpFindNeighborCacheEntry(interface, targetAddr);
01752 
01753    //Include the link-layer address of the target, if known
01754    if(entry != NULL)
01755    {
01756       //Add Target Link-Layer Address option
01757       ndpAddOption(message, &length, NDP_OPT_TARGET_LINK_LAYER_ADDR,
01758          &entry->macAddr, sizeof(MacAddr));
01759    }
01760 
01761    //Retrieve the length of the IPv6 packet that triggered the sending
01762    //of the Redirect
01763    ipPacketLength = netBufferGetLength(ipPacket) - ipPacketOffset;
01764 
01765    //Return as much of the forwarded IPv6 packet as can fit without
01766    //the redirect packet exceeding the minimum IPv6 MTU
01767    ipPacketLength = MIN(ipPacketLength, IPV6_DEFAULT_MTU -
01768       sizeof(NdpRedirectedHeaderOption) - length);
01769 
01770    //Length of the Redirected Header option in units of 8 bytes including
01771    //the type and length fields
01772    optionLength = (ipPacketLength + sizeof(NdpOption) + 7) / 8;
01773 
01774    //Add Redirected Header option
01775    option = (NdpRedirectedHeaderOption *) ((uint8_t *) message + length);
01776 
01777    //Format Redirected Header option
01778    option->type = NDP_OPT_REDIRECTED_HEADER;
01779    option->length = (uint8_t) optionLength;
01780    option->reserved1 = 0;
01781    option->reserved2 = 0;
01782 
01783    //Update the length of Redirect message
01784    length += sizeof(NdpRedirectedHeaderOption);
01785 
01786    //Adjust the length of the multi-part buffer
01787    netBufferSetLength(buffer, offset + length);
01788 
01789    //Copy the contents of the forwarded IPv6 packet
01790    error = netBufferConcat(buffer, ipPacket, ipPacketOffset, ipPacketLength);
01791 
01792    //Check status code
01793    if(!error)
01794    {
01795       //Options should be padded when necessary to ensure that they end on
01796       //their natural 64-bit boundaries
01797       if((ipPacketLength + sizeof(NdpRedirectedHeaderOption)) < (optionLength * 8))
01798       {
01799          //Determine the amount of padding data to append
01800          paddingLength = (optionLength * 8) - ipPacketLength -
01801             sizeof(NdpRedirectedHeaderOption);
01802 
01803          //Prepare padding data
01804          memset(padding, 0, paddingLength);
01805          //Append padding bytes
01806          error = netBufferAppend(buffer, padding, paddingLength);
01807       }
01808    }
01809 
01810    //Check status code
01811    if(!error)
01812    {
01813       //Get the length of the resulting message
01814       length = netBufferGetLength(buffer) - offset;
01815 
01816       //Format IPv6 pseudo header
01817       pseudoHeader.srcAddr = interface->ipv6Context.addrList[0].addr;
01818       pseudoHeader.destAddr = ipHeader->srcAddr;
01819       pseudoHeader.length = htonl(length);
01820       pseudoHeader.reserved = 0;
01821       pseudoHeader.nextHeader = IPV6_ICMPV6_HEADER;
01822 
01823       //Message checksum calculation
01824       message->checksum = ipCalcUpperLayerChecksumEx(&pseudoHeader,
01825          sizeof(Ipv6PseudoHeader), buffer, offset, length);
01826 
01827       //Debug message
01828       TRACE_INFO("Sending Redirect message (%" PRIuSIZE " bytes)...\r\n", length);
01829       //Dump message contents for debugging purpose
01830       ndpDumpRedirectMessage(message);
01831 
01832       //Send Redirect message
01833       error = ipv6SendDatagram(interface, &pseudoHeader, buffer, offset, NDP_HOP_LIMIT);
01834    }
01835 
01836    //Free previously allocated memory
01837    netBufferFree(buffer);
01838 
01839    //Return status code
01840    return error;
01841 }
01842 
01843 
01844 /**
01845  * @brief Dump Router Solicitation message for debugging purpose
01846  * @param[in] message Router Solicitation message
01847  **/
01848 
01849 void ndpDumpRouterSolMessage(const NdpRouterSolMessage *message)
01850 {
01851    //Dump Router Solicitation message
01852    TRACE_DEBUG("  Type = %" PRIu8 "\r\n", message->type);
01853    TRACE_DEBUG("  Code = %" PRIu8 "\r\n", message->code);
01854    TRACE_DEBUG("  Checksum = 0x%04" PRIX16 "\r\n", ntohs(message->checksum));
01855 }
01856 
01857 
01858 /**
01859  * @brief Dump Router Advertisement message for debugging purpose
01860  * @param[in] message Router Advertisement message
01861  **/
01862 
01863 void ndpDumpRouterAdvMessage(const NdpRouterAdvMessage *message)
01864 {
01865    //Dump Router Advertisement message
01866    TRACE_DEBUG("  Type = %" PRIu8 "\r\n", message->type);
01867    TRACE_DEBUG("  Code = %" PRIu8 "\r\n", message->code);
01868    TRACE_DEBUG("  Checksum = 0x%04" PRIX16 "\r\n", ntohs(message->checksum));
01869    TRACE_DEBUG("  Cur Hop Limit = %" PRIu8 "\r\n", message->curHopLimit);
01870    TRACE_DEBUG("  M = %" PRIu8 "\r\n", message->m);
01871    TRACE_DEBUG("  O = %" PRIu8 "\r\n", message->o);
01872    TRACE_DEBUG("  Router Lifetime = %" PRIu16 "\r\n", ntohs(message->routerLifetime));
01873    TRACE_DEBUG("  Reachable Time = %" PRIu32 "\r\n", ntohl(message->reachableTime));
01874    TRACE_DEBUG("  Retrans Timer = %" PRIu32 "\r\n", ntohl(message->retransTimer));
01875 }
01876 
01877 
01878 /**
01879  * @brief Dump Neighbor Solicitation message for debugging purpose
01880  * @param[in] message Neighbor Solicitation message
01881  **/
01882 
01883 void ndpDumpNeighborSolMessage(const NdpNeighborSolMessage *message)
01884 {
01885    //Dump Neighbor Solicitation message
01886    TRACE_DEBUG("  Type = %" PRIu8 "\r\n", message->type);
01887    TRACE_DEBUG("  Code = %" PRIu8 "\r\n", message->code);
01888    TRACE_DEBUG("  Checksum = 0x%04" PRIX16 "\r\n", ntohs(message->checksum));
01889    TRACE_DEBUG("  Target Address = %s\r\n", ipv6AddrToString(&message->targetAddr, NULL));
01890 }
01891 
01892 
01893 /**
01894  * @brief Dump Neighbor Advertisement message for debugging purpose
01895  * @param[in] message Neighbor Advertisement message
01896  **/
01897 
01898 void ndpDumpNeighborAdvMessage(const NdpNeighborAdvMessage *message)
01899 {
01900    //Dump Neighbor Advertisement message
01901    TRACE_DEBUG("  Type = %" PRIu8 "\r\n", message->type);
01902    TRACE_DEBUG("  Code = %" PRIu8 "\r\n", message->code);
01903    TRACE_DEBUG("  Checksum = 0x%04" PRIX16 "\r\n", ntohs(message->checksum));
01904    TRACE_DEBUG("  R = %" PRIu8 "\r\n", message->r);
01905    TRACE_DEBUG("  S = %" PRIu8 "\r\n", message->s);
01906    TRACE_DEBUG("  O = %" PRIu8 "\r\n", message->o);
01907    TRACE_DEBUG("  Target Address = %s\r\n", ipv6AddrToString(&message->targetAddr, NULL));
01908 }
01909 
01910 
01911 /**
01912  * @brief Dump Redirect message for debugging purpose
01913  * @param[in] message Redirect message
01914  **/
01915 
01916 void ndpDumpRedirectMessage(const NdpRedirectMessage *message)
01917 {
01918    //Dump Neighbor Advertisement message
01919    TRACE_DEBUG("  Type = %" PRIu8 "\r\n", message->type);
01920    TRACE_DEBUG("  Code = %" PRIu8 "\r\n", message->code);
01921    TRACE_DEBUG("  Checksum = 0x%04" PRIX16 "\r\n", ntohs(message->checksum));
01922    TRACE_DEBUG("  Target Address = %s\r\n", ipv6AddrToString(&message->targetAddr, NULL));
01923    TRACE_DEBUG("  Destination Address = %s\r\n", ipv6AddrToString(&message->destAddr, NULL));
01924 }
01925 
01926 #endif
01927