Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
ipv6_routing.c
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
Generated on Tue Jul 12 2022 17:10:14 by
