Sergey Pastor / 1

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ipv6_routing.c Source File

ipv6_routing.c

Go to the documentation of this file.
00001 /**
00002  * @file ipv6_routing.c
00003  * @brief IPv6 routing
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 IPV6_TRACE_LEVEL
00031 
00032 //Dependencies
00033 #include <limits.h>
00034 #include "core/net.h"
00035 #include "core/ip.h"
00036 #include "ipv6/ipv6.h"
00037 #include "ipv6/ipv6_misc.h"
00038 #include "ipv6/ipv6_routing.h"
00039 #include "ipv6/icmpv6.h"
00040 #include "ipv6/ndp.h"
00041 #include "debug.h"
00042 
00043 //Check TCP/IP stack configuration
00044 #if (IPV6_SUPPORT == ENABLED && IPV6_ROUTING_SUPPORT == ENABLED)
00045 
00046 //IPv6 routing table
00047 static Ipv6RoutingTableEntry ipv6RoutingTable[IPV6_ROUTING_TABLE_SIZE];
00048 
00049 
00050 /**
00051  * @brief Initialize IPv6 routing table
00052  * @return Error code
00053  **/
00054 
00055 error_t ipv6InitRouting(void)
00056 {
00057    //Clear the routing table
00058    memset(ipv6RoutingTable, 0, sizeof(ipv6RoutingTable));
00059 
00060    //Successful initialization
00061    return NO_ERROR;
00062 }
00063 
00064 
00065 /**
00066  * @brief Enable routing for the specified interface
00067  * @param[in] interface Underlying network interface
00068  * @param[in] enable When the flag is set to TRUE, routing is enabled on the
00069  *   interface and the router can forward packets to or from the interface
00070  * @return Error code
00071  **/
00072 
00073 error_t ipv6EnableRouting(NetInterface *interface, bool_t enable)
00074 {
00075    //Check parameters
00076    if(interface == NULL)
00077       return ERROR_INVALID_PARAMETER;
00078 
00079    //Get exclusive access
00080    osAcquireMutex(&netMutex);
00081    //Enable or disable routing
00082    interface->ipv6Context.isRouter = enable;
00083    //Release exclusive access
00084    osReleaseMutex(&netMutex);
00085 
00086    //Successful processing
00087    return NO_ERROR;
00088 }
00089 
00090 
00091 /**
00092  * @brief Add a new entry in the IPv6 routing table
00093  * @param[in] prefix Network destination
00094  * @param[in] prefixLength Length of the prefix, in bits
00095  * @param[in] interface Network interface where to forward the packet
00096  * @param[in] nextHop IPv6 address of the next hop
00097  * @param[in] metric Metric value
00098  * @return Error code
00099  **/
00100 
00101 error_t ipv6AddRoute(const Ipv6Addr *prefix, uint_t prefixLength,
00102    NetInterface *interface, const Ipv6Addr *nextHop, uint_t metric)
00103 {
00104    error_t error;
00105    uint_t i;
00106    Ipv6RoutingTableEntry *entry;
00107    Ipv6RoutingTableEntry *firstFreeEntry;
00108 
00109    //Check parameters
00110    if(prefix == NULL || interface == NULL)
00111       return ERROR_INVALID_PARAMETER;
00112 
00113    //Keep track of the first free entry
00114    firstFreeEntry = NULL;
00115 
00116    //Get exclusive access
00117    osAcquireMutex(&netMutex);
00118 
00119    //Loop through routing table entries
00120    for(i = 0; i < IPV6_ROUTING_TABLE_SIZE; i++)
00121    {
00122       //Point to the current entry
00123       entry = &ipv6RoutingTable[i];
00124 
00125       //Valid entry?
00126       if(entry->valid)
00127       {
00128          //Check prefix length
00129          if(entry->prefixLength == prefixLength)
00130          {
00131             //Check whether the current entry matches the specified destination
00132             if(ipv6CompPrefix(&entry->prefix, prefix, prefixLength))
00133                break;
00134          }
00135       }
00136       else
00137       {
00138          //Keep track of the first free entry
00139          if(firstFreeEntry == NULL)
00140             firstFreeEntry = entry;
00141       }
00142    }
00143 
00144    //If the routing table does not contain the specified destination,
00145    //then a new entry should be created
00146    if(i >= IPV6_ROUTING_TABLE_SIZE)
00147       entry = firstFreeEntry;
00148 
00149    //Check whether the routing table runs out of space
00150    if(entry != NULL)
00151    {
00152       //Network destination
00153       entry->prefix = *prefix;
00154       entry->prefixLength = prefixLength;
00155 
00156       //Interface where to forward the packet
00157       entry->interface = interface;
00158 
00159       //Address of the next hop
00160       if(nextHop != NULL)
00161          entry->nextHop = *nextHop;
00162       else
00163          entry->nextHop = IPV6_UNSPECIFIED_ADDR;
00164 
00165       //Metric value
00166       entry->metric = metric;
00167       //The entry is now valid
00168       entry->valid = TRUE;
00169 
00170       //Sucessful processing
00171       error = NO_ERROR;
00172    }
00173    else
00174    {
00175       //The routing table is full
00176       error = ERROR_FAILURE;
00177    }
00178 
00179    //Release exclusive access
00180    osReleaseMutex(&netMutex);
00181 
00182    //Return status code
00183    return error;
00184 }
00185 
00186 
00187 /**
00188  * @brief Remove an entry from the IPv6 routing table
00189  * @param[in] prefix Network destination
00190  * @param[in] prefixLength Length of the prefix, in bits
00191  * @return Error code
00192  **/
00193 
00194 error_t ipv6DeleteRoute(const Ipv6Addr *prefix, uint_t prefixLength)
00195 {
00196    error_t error;
00197    uint_t i;
00198    Ipv6RoutingTableEntry *entry;
00199 
00200    //Initialize status code
00201    error = ERROR_NOT_FOUND;
00202 
00203    //Get exclusive access
00204    osAcquireMutex(&netMutex);
00205 
00206    //Loop through routing table entries
00207    for(i = 0; i < IPV6_ROUTING_TABLE_SIZE; i++)
00208    {
00209       //Point to the current entry
00210       entry = &ipv6RoutingTable[i];
00211 
00212       //Valid entry?
00213       if(entry->valid)
00214       {
00215          //Check prefix length
00216          if(entry->prefixLength == prefixLength)
00217          {
00218             //Check whether the current entry matches the specified destination
00219             if(ipv6CompPrefix(&entry->prefix, prefix, prefixLength))
00220             {
00221                //Delete current entry
00222                entry->valid = FALSE;
00223                //The route was successfully deleted from the routing table
00224                error = NO_ERROR;
00225             }
00226          }
00227       }
00228    }
00229 
00230    //Release exclusive access
00231    osReleaseMutex(&netMutex);
00232 
00233    //Return status code
00234    return error;
00235 }
00236 
00237 
00238 /**
00239  * @brief Delete all routes from the IPv6 routing table
00240  * @return Error code
00241  **/
00242 
00243 error_t ipv6DeleteAllRoutes(void)
00244 {
00245    //Get exclusive access
00246    osAcquireMutex(&netMutex);
00247    //Clear the routing table
00248    memset(ipv6RoutingTable, 0, sizeof(ipv6RoutingTable));
00249    //Release exclusive access
00250    osReleaseMutex(&netMutex);
00251 
00252    //Successful processing
00253    return NO_ERROR;
00254 }
00255 
00256 
00257 /**
00258  * @brief Forward an IPv6 packet
00259  * @param[in] srcInterface Network interface on which the packet was received
00260  * @param[in] ipPacket Multi-part buffer that holds the IPv6 packet to forward
00261  * @param[in] ipPacketOffset Offset to the first byte of the IPv6 packet
00262  * @return Error code
00263  **/
00264 
00265 error_t ipv6ForwardPacket(NetInterface *srcInterface,
00266    NetBuffer *ipPacket, size_t ipPacketOffset)
00267 {
00268    error_t error;
00269    uint_t i;
00270    uint_t metric;
00271    uint_t prefixLength;
00272    bool_t match;
00273    size_t length;
00274    size_t destOffset;
00275    NetInterface *destInterface;
00276    NetBuffer *destBuffer;
00277    Ipv6Header *ipHeader;
00278    Ipv6RoutingTableEntry *entry;
00279    Ipv6Addr destIpAddr;
00280 
00281    //Silently drop any IP packets received on an interface that has
00282    //not been assigned a valid link-local address
00283    if(ipv6GetLinkLocalAddrState(srcInterface) != IPV6_ADDR_STATE_PREFERRED)
00284       return ERROR_NOT_CONFIGURED;
00285 
00286    //If routing is not enabled on the interface, then the router cannot
00287    //forward packets from the interface
00288    if(!srcInterface->ipv6Context.isRouter)
00289       return ERROR_FAILURE;
00290 
00291    //Calculate the length of the IPv6 packet
00292    length = netBufferGetLength(ipPacket) - ipPacketOffset;
00293 
00294    //Ensure the packet length is greater than 40 bytes
00295    if(length < sizeof(Ipv6Header))
00296       return ERROR_INVALID_LENGTH;
00297 
00298    //Point to the IPv6 header
00299    ipHeader = netBufferAt(ipPacket, ipPacketOffset);
00300 
00301    //Sanity check
00302    if(ipHeader == NULL)
00303       return ERROR_FAILURE;
00304 
00305    //An IPv6 packet with a source address of unspecified must never be
00306    //forwarded by an IPv6 router (refer to RFC section 3513 2.5.2)
00307    if(ipv6CompAddr(&ipHeader->srcAddr, &IPV6_UNSPECIFIED_ADDR))
00308       return ERROR_INVALID_ADDRESS;
00309 
00310    //The unspecified address must not be used as the destination address
00311    //of IPv6 packets (refer to RFC section 3513 2.5.2)
00312    if(ipv6CompAddr(&ipHeader->destAddr, &IPV6_UNSPECIFIED_ADDR))
00313       return ERROR_INVALID_ADDRESS;
00314 
00315    //An IPv6 packet with a destination address of loopback must never be
00316    //forwarded by an IPv6 router (refer to RFC 3513 section 2.5.3)
00317    if(ipv6CompAddr(&ipHeader->destAddr, &IPV6_LOOPBACK_ADDR))
00318       return ERROR_INVALID_ADDRESS;
00319 
00320    //Check whether the destination address is a link-local address
00321    if(ipv6IsLinkLocalUnicastAddr(&ipHeader->destAddr))
00322    {
00323       //Forward the packet on the same network interface
00324       destInterface = srcInterface;
00325       //Next hop
00326       destIpAddr = ipHeader->destAddr;
00327    }
00328    else
00329    {
00330       //Lowest metric value
00331       metric = UINT_MAX;
00332       //Longest prefix length
00333       prefixLength = 0;
00334       //Outgoing network interface
00335       destInterface = NULL;
00336 
00337       //Route determination process
00338       for(i = 0; i < IPV6_ROUTING_TABLE_SIZE; i++)
00339       {
00340          //Point to the current entry
00341          entry = &ipv6RoutingTable[i];
00342 
00343          //Valid entry?
00344          if(entry->valid && entry->interface != NULL)
00345          {
00346             //Clear flag
00347             match = FALSE;
00348 
00349             //Do not forward any IP packets to an interface that has not
00350             //been assigned a valid link-local address...
00351             if(ipv6GetLinkLocalAddrState(entry->interface) == IPV6_ADDR_STATE_PREFERRED)
00352             {
00353                //If routing is enabled on the interface, then the router
00354                //can forward packets to the interface
00355                if(entry->interface->ipv6Context.isRouter)
00356                {
00357                   //Compare the destination address with the current entry for a match
00358                   if(ipv6CompPrefix(&ipHeader->destAddr, &entry->prefix, entry->prefixLength))
00359                   {
00360                      //The longest matching route is the most specific route to the
00361                      //destination IPv6 address...
00362                      if(entry->prefixLength > prefixLength)
00363                      {
00364                         //Give the current route the higher precedence
00365                         match = TRUE;
00366                      }
00367                      else if(entry->prefixLength == prefixLength)
00368                      {
00369                         //If multiple entries with the longest match are found, the
00370                         //router uses the lowest metric to select the best route
00371                         if(entry->metric < metric)
00372                         {
00373                            //Give the current route the higher precedence
00374                            match = TRUE;
00375                         }
00376                      }
00377                   }
00378                }
00379             }
00380 
00381             //Matching entry?
00382             if(match)
00383             {
00384                //Select the current route
00385                metric = entry->metric;
00386                prefixLength = entry->prefixLength;
00387 
00388                //Outgoing interface on which to forward the packet
00389                destInterface = entry->interface;
00390 
00391                //Next hop
00392                if(!ipv6CompAddr(&entry->nextHop, &IPV6_UNSPECIFIED_ADDR))
00393                   destIpAddr = entry->nextHop;
00394                else
00395                   destIpAddr = ipHeader->destAddr;
00396             }
00397          }
00398       }
00399    }
00400 
00401    //No route to the destination?
00402    if(destInterface == NULL)
00403    {
00404       //A Destination Unreachable message should be generated by a router
00405       //in response to a packet that cannot be delivered
00406       icmpv6SendErrorMessage(srcInterface, ICMPV6_TYPE_DEST_UNREACHABLE,
00407          ICMPV6_CODE_NO_ROUTE_TO_DEST, 0, ipPacket, ipPacketOffset);
00408 
00409       //Exit immediately
00410       return ERROR_NO_ROUTE;
00411    }
00412 
00413    //Check whether the length of the IPv6 packet is larger than the link MTU
00414    if(length > destInterface->ipv6Context.linkMtu)
00415    {
00416       //A Packet Too Big must be sent by a router in response to a packet
00417       //that it cannot forward because the packet is larger than the MTU
00418       //of the outgoing link
00419       icmpv6SendErrorMessage(srcInterface, ICMPV6_TYPE_PACKET_TOO_BIG,
00420          0, destInterface->ipv6Context.linkMtu, ipPacket, ipPacketOffset);
00421 
00422       //Exit immediately
00423       return ERROR_INVALID_LENGTH;
00424    }
00425 
00426    //Check whether the packet is explicitly addressed to the router itself
00427    if(!ipv6CheckDestAddr(destInterface, &ipHeader->destAddr))
00428    {
00429       //Valid unicast address?
00430       if(!ipv6IsMulticastAddr(&ipHeader->destAddr))
00431       {
00432          //Process IPv6 packet
00433          //ipv6ProcessPacket(destInterface, ipPacket, ipPacketOffset);
00434          //Exit immediately
00435          return NO_ERROR;
00436       }
00437    }
00438 
00439    //Check whether the IPv6 packet is about to be sent out the interface
00440    //on which it was received
00441    if(destInterface == srcInterface)
00442    {
00443 #if (NDP_SUPPORT == ENABLED)
00444       //A router should send a Redirect message whenever it forwards a packet
00445       //that is not explicitly addressed to itself in which the source address
00446       //identifies a neighbor, and
00447       if(ipv6IsOnLink(srcInterface, &ipHeader->srcAddr))
00448       {
00449          //The router determines that a better first-hop node resides on the
00450          //same link as the sending node for the destination address of the
00451          //packet being forwarded, and
00452          if(ipv6IsOnLink(destInterface, &destIpAddr))
00453          {
00454             //The destination address of the packet is not a multicast address
00455             if(!ipv6IsMulticastAddr(&ipHeader->destAddr))
00456             {
00457                //Transmit a Redirect message
00458                ndpSendRedirect(srcInterface, &destIpAddr, ipPacket, ipPacketOffset);
00459             }
00460          }
00461       }
00462 #endif
00463    }
00464    else
00465    {
00466       //Check whether the scope of the source address is smaller than the
00467       //scope of the destination address
00468       if(ipv6GetAddrScope(&ipHeader->srcAddr) < ipv6GetAddrScope(&ipHeader->destAddr))
00469       {
00470          //A Destination Unreachable message should be generated by a router
00471          //in response to a packet that cannot be delivered without leaving
00472          //the scope of the source address
00473          icmpv6SendErrorMessage(srcInterface, ICMPV6_TYPE_DEST_UNREACHABLE,
00474             ICMPV6_CODE_BEYOND_SCOPE_OF_SRC_ADDR, 0, ipPacket, ipPacketOffset);
00475 
00476          //Exit immediately
00477          return ERROR_INVALID_ADDRESS;
00478       }
00479    }
00480 
00481    //Hop Limit exceeded in transit?
00482    if(ipHeader->hopLimit <= 1)
00483    {
00484       //If a router receives a packet with a Hop Limit of zero, or if a router
00485       //decrements a packet's Hop Limit to zero, it must discard the packet
00486       //and originate an ICMPv6 Time Exceeded message
00487       icmpv6SendErrorMessage(srcInterface, ICMPV6_TYPE_TIME_EXCEEDED,
00488          ICMPV6_CODE_HOP_LIMIT_EXCEEDED, 0, ipPacket, ipPacketOffset);
00489 
00490       //Exit immediately
00491       return ERROR_FAILURE;
00492    }
00493 
00494    //The Hop-by-Hop Options header, when present, must immediately follow
00495    //the IPv6 header. Its presence is indicated by the value zero in the
00496    //Next Header field of the IPv6 header
00497    if(ipHeader->nextHeader == IPV6_HOP_BY_HOP_OPT_HEADER)
00498    {
00499       //Point to the extension header
00500       size_t headerOffset = ipPacketOffset + sizeof(Ipv6Header);
00501 
00502       //Calculate the offset of the Next Header field
00503       size_t nextHeaderOffset = ipPacketOffset +
00504          &ipHeader->nextHeader - (uint8_t *) ipHeader;
00505 
00506       //The Hop-by-Hop Options header is used to carry optional information
00507       //that must be examined by every node along a packet's delivery path
00508       error = ipv6ParseHopByHopOptHeader(srcInterface,
00509          ipPacket, ipPacketOffset, &headerOffset, &nextHeaderOffset);
00510 
00511       //Any error while processing the extension header?
00512       if(error)
00513          return error;
00514    }
00515 
00516    //Allocate a buffer to hold the IPv6 packet
00517    destBuffer = ethAllocBuffer(length, &destOffset);
00518 
00519    //Successful memory allocation?
00520    if(destBuffer != NULL)
00521    {
00522       //Copy IPv6 header
00523       error = netBufferCopy(destBuffer, destOffset,
00524          ipPacket, ipPacketOffset, length);
00525 
00526       //Check status code
00527       if(!error)
00528       {
00529          //Point to the IPv6 header
00530          ipHeader = netBufferAt(destBuffer, destOffset);
00531          //Every time a router forwards a packet, it decrements the Hop Limit field
00532          ipHeader->hopLimit--;
00533 
00534 #if (ETH_SUPPORT == ENABLED)
00535          //Ethernet interface?
00536          if(destInterface->nicDriver->type == NIC_TYPE_ETHERNET)
00537          {
00538             MacAddr destMacAddr;
00539 
00540             //Destination IPv6 address
00541             if(ipv6CompAddr(&destIpAddr, &IPV6_UNSPECIFIED_ADDR))
00542                destIpAddr = ipHeader->destAddr;
00543 
00544             //Check whether the destination IPv6 address is a multicast address?
00545             if(ipv6IsMulticastAddr(&destIpAddr))
00546             {
00547                //Map IPv6 multicast address to MAC-layer multicast address
00548                error = ipv6MapMulticastAddrToMac(&destIpAddr, &destMacAddr);
00549             }
00550             else
00551             {
00552                //Resolve host address using Neighbor Discovery protocol
00553                error = ndpResolve(destInterface, &destIpAddr, &destMacAddr);
00554             }
00555 
00556             //Successful address resolution?
00557             if(!error)
00558             {
00559                //Debug message
00560                TRACE_INFO("Forwarding IPv6 packet to %s (%" PRIuSIZE " bytes)...\r\n",
00561                   destInterface->name, length);
00562                //Dump IP header contents for debugging purpose
00563                ipv6DumpHeader(ipHeader);
00564 
00565                //Send Ethernet frame
00566                error = ethSendFrame(destInterface, &destMacAddr,
00567                   destBuffer, destOffset, ETH_TYPE_IPV6);
00568             }
00569             //Address resolution is in progress?
00570             else if(error == ERROR_IN_PROGRESS)
00571             {
00572                //Debug message
00573                TRACE_INFO("Enqueuing IPv6 packet (%" PRIuSIZE " bytes)...\r\n", length);
00574                //Dump IP header contents for debugging purpose
00575                ipv6DumpHeader(ipHeader);
00576 
00577                //Enqueue packets waiting for address resolution
00578                error = ndpEnqueuePacket(srcInterface, destInterface,
00579                   &destIpAddr, destBuffer, destOffset);
00580             }
00581             //Address resolution failed?
00582             else
00583             {
00584                //Debug message
00585                TRACE_WARNING("Cannot map IPv6 address to Ethernet address!\r\n");
00586             }
00587          }
00588          else
00589 #endif
00590 #if (PPP_SUPPORT == ENABLED)
00591          //PPP interface?
00592          if(destInterface->nicDriver->type == NIC_TYPE_PPP)
00593          {
00594             //Debug message
00595             TRACE_INFO("Forwarding IPv6 packet to %s (%" PRIuSIZE " bytes)...\r\n",
00596                destInterface->name, length);
00597             //Dump IP header contents for debugging purpose
00598             ipv6DumpHeader(ipHeader);
00599 
00600             //Send PPP frame
00601             error = pppSendFrame(destInterface, destBuffer, destOffset, PPP_PROTOCOL_IPV6);
00602          }
00603          else
00604 #endif
00605          //6LoWPAN interface?
00606          if(destInterface->nicDriver->type == NIC_TYPE_6LOWPAN)
00607          {
00608             //Debug message
00609             TRACE_INFO("Forwarding IPv6 packet to %s (%" PRIuSIZE " bytes)...\r\n",
00610                destInterface->name, length);
00611             //Dump IP header contents for debugging purpose
00612             ipv6DumpHeader(ipHeader);
00613 
00614             //Send the packet over the specified link
00615             error = nicSendPacket(destInterface, destBuffer, destOffset);
00616          }
00617          else
00618          //Unknown interface type?
00619          {
00620             //Report an error
00621             error = ERROR_INVALID_INTERFACE;
00622          }
00623       }
00624 
00625       //Free previously allocated memory
00626       netBufferFree(destBuffer);
00627    }
00628    else
00629    {
00630       //Failed to allocate memory
00631       error = ERROR_OUT_OF_MEMORY;
00632    }
00633 
00634    //Return status code
00635    return error;
00636 }
00637 
00638 #endif
00639