Webserver+3d print

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ipv6.c Source File

ipv6.c

Go to the documentation of this file.
00001 /**
00002  * @file ipv6.c
00003  * @brief IPv6 (Internet Protocol Version 6)
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  * IP version 6 (IPv6) is a new version of the Internet Protocol, designed
00028  * as the successor to IP version 4 (IPv4). Refer to RFC 2460
00029  *
00030  * @author Oryx Embedded SARL (www.oryx-embedded.com)
00031  * @version 1.7.6
00032  **/
00033 
00034 //Switch to the appropriate trace level
00035 #define TRACE_LEVEL IPV6_TRACE_LEVEL
00036 
00037 //Dependencies
00038 #include <string.h>
00039 #include <ctype.h>
00040 #include "core/net.h"
00041 #include "ipv6/ipv6.h"
00042 #include "ipv6/ipv6_frag.h"
00043 #include "ipv6/ipv6_misc.h"
00044 #include "ipv6/ipv6_pmtu.h"
00045 #include "ipv6/ipv6_routing.h"
00046 #include "ipv6/icmpv6.h"
00047 #include "ipv6/mld.h"
00048 #include "ipv6/ndp.h"
00049 #include "ipv6/ndp_cache.h"
00050 #include "ipv6/ndp_misc.h"
00051 #include "ipv6/ndp_router_adv.h"
00052 #include "ipv6/slaac.h"
00053 #include "dhcpv6/dhcpv6_client.h"
00054 #include "core/udp.h"
00055 #include "core/tcp_fsm.h"
00056 #include "core/raw_socket.h"
00057 #include "debug.h"
00058 
00059 //Check TCP/IP stack configuration
00060 #if (IPV6_SUPPORT == ENABLED)
00061 
00062 //Unspecified IPv6 address
00063 const Ipv6Addr IPV6_UNSPECIFIED_ADDR =
00064    IPV6_ADDR(0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000);
00065 
00066 //Loopback IPv6 address
00067 const Ipv6Addr IPV6_LOOPBACK_ADDR =
00068    IPV6_ADDR(0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001);
00069 
00070 //Link-local All-Nodes IPv6 address
00071 const Ipv6Addr IPV6_LINK_LOCAL_ALL_NODES_ADDR =
00072    IPV6_ADDR(0xFF02, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001);
00073 
00074 //Link-local All-Routers IPv6 address
00075 const Ipv6Addr IPV6_LINK_LOCAL_ALL_ROUTERS_ADDR =
00076    IPV6_ADDR(0xFF02, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0002);
00077 
00078 //Link-local IPv6 address prefix
00079 const Ipv6Addr IPV6_LINK_LOCAL_ADDR_PREFIX =
00080    IPV6_ADDR(0xFE80, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000);
00081 
00082 //Solicited-node IPv6 address prefix
00083 const Ipv6Addr IPV6_SOLICITED_NODE_ADDR_PREFIX =
00084    IPV6_ADDR(0xFF02, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0xFF00, 0x0000);
00085 
00086 
00087 /**
00088  * @brief IPv6 related initialization
00089  * @param[in] interface Underlying network interface
00090  * @return Error code
00091  **/
00092 
00093 error_t ipv6Init(NetInterface *interface)
00094 {
00095    Ipv6Context *context;
00096 
00097    //Point to the IPv6 context
00098    context = &interface->ipv6Context;
00099 
00100    //Clear the IPv6 context
00101    memset(context, 0, sizeof(Ipv6Context));
00102 
00103    //Initialize interface specific variables
00104    context->linkMtu = interface->nicDriver->mtu;
00105    context->isRouter = FALSE;
00106    context->curHopLimit = IPV6_DEFAULT_HOP_LIMIT;
00107 
00108    //Multicast ICMPv6 Echo Request messages are allowed by default
00109    context->enableMulticastEchoReq = TRUE;
00110 
00111    //Initialize the list of IPv6 addresses assigned to the interface
00112    memset(context->addrList, 0, sizeof(context->addrList));
00113    //Initialize the Prefix List
00114    memset(context->prefixList, 0, sizeof(context->prefixList));
00115    //Initialize the Default Router List
00116    memset(context->routerList, 0, sizeof(context->routerList));
00117    //Initialize the list of DNS servers
00118    memset(context->dnsServerList, 0, sizeof(context->dnsServerList));
00119    //Initialize the multicast filter table
00120    memset(context->multicastFilter, 0, sizeof(context->multicastFilter));
00121 
00122 #if (IPV6_FRAG_SUPPORT == ENABLED)
00123    //Identification field is used to identify fragments of an original IP datagram
00124    context->identification = 0;
00125    //Initialize the reassembly queue
00126    memset(context->fragQueue, 0, sizeof(context->fragQueue));
00127 #endif
00128 
00129    //Successful initialization
00130    return NO_ERROR;
00131 }
00132 
00133 
00134 /**
00135  * @brief Change the MTU of a network interface
00136  * @param[in] interface Pointer to the desired network interface
00137  * @param[in] mtu Maximum transmit unit
00138  * @return Error code
00139  **/
00140 
00141 error_t ipv6SetMtu(NetInterface *interface, size_t mtu)
00142 {
00143    error_t error;
00144 
00145    //Check parameters
00146    if(interface == NULL)
00147       return ERROR_INVALID_PARAMETER;
00148 
00149    //Get exclusive access
00150    osAcquireMutex(&netMutex);
00151 
00152    //Make sure the specified MTU is greater than or equal to the minimum
00153    //IPv6 MTU and does not exceed the maximum MTU of the interface
00154    if(mtu >= IPV6_DEFAULT_MTU && mtu <= interface->nicDriver->mtu)
00155    {
00156       //Set the MTU to be used
00157       interface->ipv6Context.linkMtu = mtu;
00158       //Successful processing
00159       error = NO_ERROR;
00160    }
00161    else
00162    {
00163       //The specified MTU is not valid
00164       error = ERROR_OUT_OF_RANGE;
00165    }
00166 
00167    //Release exclusive access
00168    osReleaseMutex(&netMutex);
00169 
00170    //Return status code
00171    return error;
00172 }
00173 
00174 
00175 /**
00176  * @brief Retrieve the MTU for the specified interface
00177  * @param[in] interface Pointer to the desired network interface
00178  * @param[out] mtu Maximum transmit unit
00179  * @return Error code
00180  **/
00181 
00182 error_t ipv6GetMtu(NetInterface *interface, size_t *mtu)
00183 {
00184    //Check parameters
00185    if(interface == NULL || mtu == NULL)
00186       return ERROR_INVALID_PARAMETER;
00187 
00188    //Get exclusive access
00189    osAcquireMutex(&netMutex);
00190    //Return the current MTU value
00191    *mtu = interface->ipv6Context.linkMtu;
00192    //Release exclusive access
00193    osReleaseMutex(&netMutex);
00194 
00195    //Successful processing
00196    return NO_ERROR;
00197 }
00198 
00199 
00200 /**
00201  * @brief Assign link-local address
00202  * @param[in] interface Pointer to the desired network interface
00203  * @param[in] addr Link-local address
00204  * @return Error code
00205  **/
00206 
00207 error_t ipv6SetLinkLocalAddr(NetInterface *interface, const Ipv6Addr *addr)
00208 {
00209    error_t error;
00210 
00211    //Get exclusive access
00212    osAcquireMutex(&netMutex);
00213 
00214 #if (NDP_SUPPORT == ENABLED)
00215    //Check whether Duplicate Address Detection should be performed
00216    if(interface->ndpContext.dupAddrDetectTransmits > 0)
00217    {
00218       //Use the link-local address as a tentative address
00219       error = ipv6SetAddr(interface, 0, addr, IPV6_ADDR_STATE_TENTATIVE,
00220          NDP_INFINITE_LIFETIME, NDP_INFINITE_LIFETIME, TRUE);
00221    }
00222    else
00223 #endif
00224    {
00225       //The use of the link-local address is now unrestricted
00226       error = ipv6SetAddr(interface, 0, addr, IPV6_ADDR_STATE_PREFERRED,
00227          NDP_INFINITE_LIFETIME, NDP_INFINITE_LIFETIME, TRUE);
00228    }
00229 
00230    //Release exclusive access
00231    osReleaseMutex(&netMutex);
00232 
00233    //Return status code
00234    return error;
00235 }
00236 
00237 
00238 /**
00239  * @brief Retrieve link-local address
00240  * @param[in] interface Pointer to the desired network interface
00241  * @param[out] addr link-local address
00242  * @return Error code
00243  **/
00244 
00245 error_t ipv6GetLinkLocalAddr(NetInterface *interface, Ipv6Addr *addr)
00246 {
00247    Ipv6AddrEntry *entry;
00248 
00249    //Check parameters
00250    if(interface == NULL || addr == NULL)
00251       return ERROR_INVALID_PARAMETER;
00252 
00253    //Get exclusive access
00254    osAcquireMutex(&netMutex);
00255 
00256    //Point to the corresponding address entry
00257    entry = &interface->ipv6Context.addrList[0];
00258 
00259    //Check whether the IPv6 address is valid
00260    if(entry->state == IPV6_ADDR_STATE_PREFERRED ||
00261       entry->state == IPV6_ADDR_STATE_DEPRECATED)
00262    {
00263       //Get IPv6 address
00264       *addr = entry->addr;
00265    }
00266    else
00267    {
00268       //Return the unspecified address when no address has been assigned
00269       *addr = IPV6_UNSPECIFIED_ADDR;
00270    }
00271 
00272    //Release exclusive access
00273    osReleaseMutex(&netMutex);
00274 
00275    //Successful processing
00276    return NO_ERROR;
00277 }
00278 
00279 
00280 /**
00281  * @brief Assign global address
00282  * @param[in] interface Pointer to the desired network interface
00283  * @param[in] index Zero-based index
00284  * @param[in] addr Global address
00285  * @return Error code
00286  **/
00287 
00288 error_t ipv6SetGlobalAddr(NetInterface *interface, uint_t index, const Ipv6Addr *addr)
00289 {
00290    error_t error;
00291 
00292    //Get exclusive access
00293    osAcquireMutex(&netMutex);
00294 
00295 #if (NDP_SUPPORT == ENABLED)
00296    //Check whether Duplicate Address Detection should be performed
00297    if(interface->ndpContext.dupAddrDetectTransmits > 0)
00298    {
00299       //Use the global address as a tentative address
00300       error = ipv6SetAddr(interface, index + 1, addr, IPV6_ADDR_STATE_TENTATIVE,
00301          NDP_INFINITE_LIFETIME, NDP_INFINITE_LIFETIME, TRUE);
00302    }
00303    else
00304 #endif
00305    {
00306       //The use of the global address is now unrestricted
00307       error = ipv6SetAddr(interface, index + 1, addr, IPV6_ADDR_STATE_PREFERRED,
00308          NDP_INFINITE_LIFETIME, NDP_INFINITE_LIFETIME, TRUE);
00309    }
00310 
00311    //Release exclusive access
00312    osReleaseMutex(&netMutex);
00313 
00314    //Return status code
00315    return error;
00316 }
00317 
00318 
00319 /**
00320  * @brief Retrieve global address
00321  * @param[in] interface Pointer to the desired network interface
00322  * @param[in] index Zero-based index
00323  * @param[out] addr Global address
00324  * @return Error code
00325  **/
00326 
00327 error_t ipv6GetGlobalAddr(NetInterface *interface, uint_t index, Ipv6Addr *addr)
00328 {
00329    Ipv6AddrEntry *entry;
00330 
00331    //Check parameters
00332    if(interface == NULL || addr == NULL)
00333       return ERROR_INVALID_PARAMETER;
00334 
00335    //Make sure that the index is valid
00336    if((index + 1) >= IPV6_ADDR_LIST_SIZE)
00337    {
00338       //Return the unspecified address when the index is out of range
00339       *addr = IPV6_UNSPECIFIED_ADDR;
00340       //Report an error
00341       return ERROR_OUT_OF_RANGE;
00342    }
00343 
00344    //Get exclusive access
00345    osAcquireMutex(&netMutex);
00346 
00347    //Point to the corresponding address entry
00348    entry = &interface->ipv6Context.addrList[index + 1];
00349 
00350    //Check whether the IPv6 address is valid
00351    if(entry->state == IPV6_ADDR_STATE_PREFERRED ||
00352       entry->state == IPV6_ADDR_STATE_DEPRECATED)
00353    {
00354       //Get IPv6 address
00355       *addr = entry->addr;
00356    }
00357    else
00358    {
00359       //Return the unspecified address when no address has been assigned
00360       *addr = IPV6_UNSPECIFIED_ADDR;
00361    }
00362 
00363    //Release exclusive access
00364    osReleaseMutex(&netMutex);
00365 
00366    //Successful processing
00367    return NO_ERROR;
00368 }
00369 
00370 
00371 /**
00372  * @brief Assign anycast address
00373  * @param[in] interface Pointer to the desired network interface
00374  * @param[in] index Zero-based index
00375  * @param[in] addr Anycast address
00376  * @return Error code
00377  **/
00378 
00379 error_t ipv6SetAnycastAddr(NetInterface *interface, uint_t index, const Ipv6Addr *addr)
00380 {
00381    error_t error;
00382    Ipv6Addr *anycastAddrList;
00383    Ipv6Addr solicitedNodeAddr;
00384 
00385    //Check parameters
00386    if(interface == NULL || addr == NULL)
00387       return ERROR_INVALID_PARAMETER;
00388 
00389    //Make sure that the index is valid
00390    if(index >= IPV6_ANYCAST_ADDR_LIST_SIZE)
00391       return ERROR_OUT_OF_RANGE;
00392 
00393    //The IPv6 address must be a valid unicast address
00394    if(ipv6IsMulticastAddr(addr))
00395       return ERROR_INVALID_ADDRESS;
00396 
00397    //Initialize status code
00398    error = NO_ERROR;
00399 
00400    //Get exclusive access
00401    osAcquireMutex(&netMutex);
00402 
00403    //Point to the list of anycast addresses assigned to the interface
00404    anycastAddrList = interface->ipv6Context.anycastAddrList;
00405 
00406    //Check whether an anycast address is already assigned
00407    if(!ipv6CompAddr(&anycastAddrList[index], &IPV6_UNSPECIFIED_ADDR))
00408    {
00409       //Ethernet interface?
00410       if(interface->nicDriver->type == NIC_TYPE_ETHERNET)
00411       {
00412          //Form the Solicited-Node address
00413          ipv6ComputeSolicitedNodeAddr(&anycastAddrList[index], &solicitedNodeAddr);
00414          //Leave the Solicited-Node multicast group
00415          ipv6LeaveMulticastGroup(interface, &solicitedNodeAddr);
00416       }
00417    }
00418 
00419    //Assign the specified anycast address to the interface
00420    anycastAddrList[index] = *addr;
00421 
00422    //Check whether the anycast address is valid
00423    if(!ipv6CompAddr(addr, &IPV6_UNSPECIFIED_ADDR))
00424    {
00425       //Ethernet interface?
00426       if(interface->nicDriver->type == NIC_TYPE_ETHERNET)
00427       {
00428          //Form the Solicited-Node address for the link-local address
00429          ipv6ComputeSolicitedNodeAddr(addr, &solicitedNodeAddr);
00430          //Join the Solicited-Node multicast group for each assigned address
00431          error = ipv6JoinMulticastGroup(interface, &solicitedNodeAddr);
00432       }
00433    }
00434 
00435    //Release exclusive access
00436    osReleaseMutex(&netMutex);
00437 
00438    //Return status code
00439    return error;
00440 }
00441 
00442 
00443 /**
00444  * @brief Retrieve anycast address
00445  * @param[in] interface Pointer to the desired network interface
00446  * @param[in] index Zero-based index
00447  * @param[out] addr Anycast address
00448  * @return Error code
00449  **/
00450 
00451 error_t ipv6GetAnycastAddr(NetInterface *interface, uint_t index, Ipv6Addr *addr)
00452 {
00453    //Check parameters
00454    if(interface == NULL || addr == NULL)
00455       return ERROR_INVALID_PARAMETER;
00456 
00457    //Make sure that the index is valid
00458    if(index >= IPV6_ANYCAST_ADDR_LIST_SIZE)
00459    {
00460       //Return the unspecified address when the index is out of range
00461       *addr = IPV6_UNSPECIFIED_ADDR;
00462       //Report an error
00463       return ERROR_OUT_OF_RANGE;
00464    }
00465 
00466    //Get exclusive access
00467    osAcquireMutex(&netMutex);
00468    //Return the corresponding address entry
00469    *addr = interface->ipv6Context.anycastAddrList[index];
00470    //Release exclusive access
00471    osReleaseMutex(&netMutex);
00472 
00473    //Successful processing
00474    return NO_ERROR;
00475 }
00476 
00477 
00478 /**
00479  * @brief Configure IPv6 prefix
00480  * @param[in] interface Pointer to the desired network interface
00481  * @param[in] index Zero-based index
00482  * @param[in] prefix IPv6 prefix
00483  * @param[in] length The number of leading bits in the prefix that are valid
00484  **/
00485 
00486 error_t ipv6SetPrefix(NetInterface *interface,
00487    uint_t index, const Ipv6Addr *prefix, uint_t length)
00488 {
00489    Ipv6PrefixEntry *entry;
00490 
00491    //Check parameters
00492    if(interface == NULL || prefix == NULL)
00493       return ERROR_INVALID_PARAMETER;
00494 
00495    //Make sure that the index is valid
00496    if(index >= IPV6_PREFIX_LIST_SIZE)
00497       return ERROR_OUT_OF_RANGE;
00498 
00499    //Make sure the prefix length is valid
00500    if(length >= 128)
00501       return ERROR_INVALID_PARAMETER;
00502 
00503    //Get exclusive access
00504    osAcquireMutex(&netMutex);
00505 
00506    //Point to the corresponding entry
00507    entry = &interface->ipv6Context.prefixList[index];
00508 
00509    //Set up IPv6 prefix
00510    entry->prefix = *prefix;
00511    entry->prefixLength = length;
00512 
00513    //Check prefix length
00514    if(length > 0)
00515    {
00516       //Manually assigned prefixes have infinite lifetime
00517       entry->validLifetime = INFINITE_DELAY;
00518       entry->preferredLifetime = INFINITE_DELAY;
00519       entry->permanent = TRUE;
00520    }
00521    else
00522    {
00523       //Immediately time-out the entry
00524       entry->validLifetime = 0;
00525       entry->preferredLifetime = 0;
00526       entry->permanent = FALSE;
00527    }
00528 
00529    //Release exclusive access
00530    osReleaseMutex(&netMutex);
00531 
00532    //Successful processing
00533    return NO_ERROR;
00534 }
00535 
00536 
00537 /**
00538  * @brief Retrieve IPv6 prefix
00539  * @param[in] interface Pointer to the desired network interface
00540  * @param[in] index Zero-based index
00541  * @param[out] prefix IPv6 prefix
00542  * @param[out] length The number of leading bits in the prefix that are valid
00543  * @return Error code
00544  **/
00545 
00546 error_t ipv6GetPrefix(NetInterface *interface,
00547    uint_t index, Ipv6Addr *prefix, uint_t *length)
00548 {
00549    Ipv6PrefixEntry *entry;
00550 
00551    //Check parameters
00552    if(interface == NULL || prefix == NULL)
00553       return ERROR_INVALID_PARAMETER;
00554 
00555    //Make sure that the index is valid
00556    if(index >= IPV6_PREFIX_LIST_SIZE)
00557    {
00558       //Return the ::/0 prefix when the index is out of range
00559       *prefix = IPV6_UNSPECIFIED_ADDR;
00560       *length = 0;
00561       //Report an error
00562       return ERROR_OUT_OF_RANGE;
00563    }
00564 
00565    //Get exclusive access
00566    osAcquireMutex(&netMutex);
00567 
00568    //Point to the corresponding entry
00569    entry = &interface->ipv6Context.prefixList[index];
00570 
00571    //Check whether the prefix is valid
00572    if(entry->validLifetime > 0)
00573    {
00574       //Get IPv6 prefix
00575       *prefix = entry->prefix;
00576       *length = entry->prefixLength;
00577    }
00578    else
00579    {
00580       //Return the ::/0 prefix when the valid lifetime has expired
00581       *prefix = IPV6_UNSPECIFIED_ADDR;
00582       *length = 0;
00583    }
00584 
00585    //Release exclusive access
00586    osReleaseMutex(&netMutex);
00587 
00588    //Successful processing
00589    return NO_ERROR;
00590 }
00591 
00592 
00593 /**
00594  * @brief Configure default router
00595  * @param[in] interface Pointer to the desired network interface
00596  * @param[in] index Zero-based index
00597  * @param[in] addr Default router address
00598  * @return Error code
00599  **/
00600 
00601 error_t ipv6SetDefaultRouter(NetInterface *interface, uint_t index, const Ipv6Addr *addr)
00602 {
00603    Ipv6RouterEntry *entry;
00604 
00605    //Check parameters
00606    if(interface == NULL || addr == NULL)
00607       return ERROR_INVALID_PARAMETER;
00608 
00609    //Make sure that the index is valid
00610    if(index >= IPV6_ROUTER_LIST_SIZE)
00611       return ERROR_OUT_OF_RANGE;
00612 
00613    //The IPv6 address must be a valid unicast address
00614    if(ipv6IsMulticastAddr(addr))
00615       return ERROR_INVALID_ADDRESS;
00616 
00617    //Get exclusive access
00618    osAcquireMutex(&netMutex);
00619 
00620    //Point to the corresponding entry
00621    entry = &interface->ipv6Context.routerList[index];
00622 
00623    //Set up router address
00624    entry->addr = *addr;
00625 
00626    //Valid IPv6 address?
00627    if(!ipv6CompAddr(addr, &IPV6_UNSPECIFIED_ADDR))
00628    {
00629       //Manually assigned routers have infinite lifetime
00630       entry->lifetime = INFINITE_DELAY;
00631       entry->permanent = TRUE;
00632    }
00633    else
00634    {
00635       //Immediately time-out the entry
00636       entry->lifetime = 0;
00637       entry->permanent = FALSE;
00638    }
00639 
00640    //Release exclusive access
00641    osReleaseMutex(&netMutex);
00642 
00643    //Successful processing
00644    return NO_ERROR;
00645 }
00646 
00647 
00648 /**
00649  * @brief Retrieve default router
00650  * @param[in] interface Pointer to the desired network interface
00651  * @param[in] index Zero-based index
00652  * @param[out] addr Default router address
00653  * @return Error code
00654  **/
00655 
00656 error_t ipv6GetDefaultRouter(NetInterface *interface, uint_t index, Ipv6Addr *addr)
00657 {
00658    Ipv6RouterEntry *entry;
00659 
00660    //Check parameters
00661    if(interface == NULL || addr == NULL)
00662       return ERROR_INVALID_PARAMETER;
00663 
00664    //Make sure that the index is valid
00665    if(index >= IPV6_ROUTER_LIST_SIZE)
00666    {
00667       //Return the unspecified address when the index is out of range
00668       *addr = IPV6_UNSPECIFIED_ADDR;
00669       //Report an error
00670       return ERROR_OUT_OF_RANGE;
00671    }
00672 
00673    //Get exclusive access
00674    osAcquireMutex(&netMutex);
00675 
00676    //Point to the corresponding entry
00677    entry = &interface->ipv6Context.routerList[index];
00678 
00679    //Check the lifetime of the entry
00680    if(entry->lifetime > 0)
00681    {
00682       //Get router address
00683       *addr = entry->addr;
00684    }
00685    else
00686    {
00687       //Return the unspecified address when the lifetime has expired
00688       *addr = IPV6_UNSPECIFIED_ADDR;
00689    }
00690 
00691    //Release exclusive access
00692    osReleaseMutex(&netMutex);
00693 
00694    //Successful processing
00695    return NO_ERROR;
00696 }
00697 
00698 
00699 /**
00700  * @brief Configure DNS server
00701  * @param[in] interface Pointer to the desired network interface
00702  * @param[in] index This parameter selects between the primary and secondary DNS server
00703  * @param[in] addr DNS server address
00704  * @return Error code
00705  **/
00706 
00707 error_t ipv6SetDnsServer(NetInterface *interface, uint_t index, const Ipv6Addr *addr)
00708 {
00709    //Check parameters
00710    if(interface == NULL || addr == NULL)
00711       return ERROR_INVALID_PARAMETER;
00712 
00713    //Make sure that the index is valid
00714    if(index >= IPV6_DNS_SERVER_LIST_SIZE)
00715       return ERROR_OUT_OF_RANGE;
00716 
00717    //The IPv6 address must be a valid unicast address
00718    if(ipv6IsMulticastAddr(addr))
00719       return ERROR_INVALID_ADDRESS;
00720 
00721    //Get exclusive access
00722    osAcquireMutex(&netMutex);
00723    //Set up DNS server address
00724    interface->ipv6Context.dnsServerList[index] = *addr;
00725    //Release exclusive access
00726    osReleaseMutex(&netMutex);
00727 
00728    //Successful processing
00729    return NO_ERROR;
00730 }
00731 
00732 
00733 /**
00734  * @brief Retrieve DNS server
00735  * @param[in] interface Pointer to the desired network interface
00736  * @param[in] index This parameter selects between the primary and secondary DNS server
00737  * @param[out] addr DNS server address
00738  * @return Error code
00739  **/
00740 
00741 error_t ipv6GetDnsServer(NetInterface *interface, uint_t index, Ipv6Addr *addr)
00742 {
00743    //Check parameters
00744    if(interface == NULL || addr == NULL)
00745       return ERROR_INVALID_PARAMETER;
00746 
00747    //Make sure that the index is valid
00748    if(index >= IPV6_DNS_SERVER_LIST_SIZE)
00749    {
00750       //Return the unspecified address when the index is out of range
00751       *addr = IPV6_UNSPECIFIED_ADDR;
00752       //Report an error
00753       return ERROR_OUT_OF_RANGE;
00754    }
00755 
00756    //Get exclusive access
00757    osAcquireMutex(&netMutex);
00758    //Get DNS server address
00759    *addr = interface->ipv6Context.dnsServerList[index];
00760    //Release exclusive access
00761    osReleaseMutex(&netMutex);
00762 
00763    //Successful processing
00764    return NO_ERROR;
00765 }
00766 
00767 
00768 /**
00769  * @brief Callback function for link change event
00770  * @param[in] interface Underlying network interface
00771  **/
00772 
00773 void ipv6LinkChangeEvent(NetInterface *interface)
00774 {
00775    uint_t i;
00776    Ipv6Context *context;
00777    Ipv6AddrEntry *entry;
00778 
00779    //Point to the IPv6 context
00780    context = &interface->ipv6Context;
00781 
00782    //Restore default parameters
00783    context->linkMtu = interface->nicDriver->mtu;
00784    context->curHopLimit = IPV6_DEFAULT_HOP_LIMIT;
00785 
00786    //Clear the list of IPv6 addresses
00787    ipv6FlushAddrList(interface);
00788    //Clear the Prefix List
00789    ipv6FlushPrefixList(interface);
00790    //Clear the Default Router List
00791    ipv6FlushDefaultRouterList(interface);
00792 
00793 #if (IPV6_FRAG_SUPPORT == ENABLED)
00794    //Flush the reassembly queue
00795    ipv6FlushFragQueue(interface);
00796 #endif
00797 
00798 #if (MLD_SUPPORT == ENABLED)
00799    //Notify MLD of link state changes
00800    mldLinkChangeEvent(interface);
00801 #endif
00802 
00803 #if (NDP_SUPPORT == ENABLED)
00804    //Notify NDP of link state changes
00805    ndpLinkChangeEvent(interface);
00806 #endif
00807 
00808 #if (NDP_ROUTER_ADV_SUPPORT == ENABLED)
00809    //Notify the RA service of link state changes
00810    ndpRouterAdvLinkChangeEvent(interface->ndpRouterAdvContext);
00811 #endif
00812 
00813 #if (SLAAC_SUPPORT == ENABLED)
00814    //Notify the SLAAC service of link state changes
00815    slaacLinkChangeEvent(interface->slaacContext);
00816 #endif
00817 
00818 #if (DHCPV6_CLIENT_SUPPORT == ENABLED)
00819    //Notify the DHCPv6 client of link state changes
00820    dhcpv6ClientLinkChangeEvent(interface->dhcpv6ClientContext);
00821 #endif
00822 
00823    //Go through the list of IPv6 addresses
00824    for(i = 0; i < IPV6_ADDR_LIST_SIZE; i++)
00825    {
00826       //Point to the current entry
00827       entry = &context->addrList[i];
00828 
00829       //Check whether the IPv6 address has been manually assigned
00830       if(entry->permanent)
00831       {
00832 #if (NDP_SUPPORT == ENABLED)
00833          //Check whether Duplicate Address Detection should be performed
00834          if(interface->ndpContext.dupAddrDetectTransmits > 0)
00835          {
00836             //Use the IPv6 address as a tentative address
00837             ipv6SetAddr(interface, i, &entry->addr, IPV6_ADDR_STATE_TENTATIVE,
00838                NDP_INFINITE_LIFETIME, NDP_INFINITE_LIFETIME, TRUE);
00839          }
00840          else
00841 #endif
00842          {
00843             //The use of the IPv6 address is now unrestricted
00844             ipv6SetAddr(interface, i, &entry->addr, IPV6_ADDR_STATE_PREFERRED,
00845                NDP_INFINITE_LIFETIME, NDP_INFINITE_LIFETIME, TRUE);
00846          }
00847       }
00848    }
00849 }
00850 
00851 
00852 /**
00853  * @brief Incoming IPv6 packet processing
00854  * @param[in] interface Underlying network interface
00855  * @param[in] ipPacket Multi-part buffer that holds the incoming IPv6 packet
00856  * @param[in] ipPacketOffset Offset to the first byte of the IPv6 packet
00857  **/
00858 
00859 void ipv6ProcessPacket(NetInterface *interface,
00860    NetBuffer *ipPacket, size_t ipPacketOffset)
00861 {
00862    error_t error;
00863    size_t i;
00864    size_t length;
00865    size_t nextHeaderOffset;
00866    uint8_t *type;
00867    Ipv6Header *ipHeader;
00868    IpPseudoHeader pseudoHeader;
00869 
00870    //Retrieve the length of the IPv6 packet
00871    length = netBufferGetLength(ipPacket);
00872 
00873    //Ensure the packet length is greater than 40 bytes
00874    if(length < sizeof(Ipv6Header))
00875       return;
00876 
00877    //Point to the IPv6 header
00878    ipHeader = netBufferAt(ipPacket, ipPacketOffset);
00879    //Sanity check
00880    if(ipHeader == NULL)
00881       return;
00882 
00883    //Debug message
00884    TRACE_INFO("IPv6 packet received (%" PRIuSIZE " bytes)...\r\n", length);
00885    //Dump IPv6 header contents for debugging purpose
00886    ipv6DumpHeader(ipHeader);
00887 
00888    //Check IP version number
00889    if(ipHeader->version != IPV6_VERSION)
00890       return;
00891    //Ensure the payload length is correct before processing the packet
00892    if(ntohs(ipHeader->payloadLength) > (length - sizeof(Ipv6Header)))
00893       return;
00894    //Source address filtering
00895    if(ipv6CheckSourceAddr(interface, &ipHeader->srcAddr))
00896       return;
00897 
00898 #if defined(IPV6_PACKET_FORWARD_HOOK)
00899    IPV6_PACKET_FORWARD_HOOK(interface, ipPacket, ipPacketOffset);
00900 #else
00901    //Destination address filtering
00902    if(ipv6CheckDestAddr(interface, &ipHeader->destAddr))
00903    {
00904 #if(IPV6_ROUTING_SUPPORT == ENABLED)
00905       //Forward the packet according to the routing table
00906       ipv6ForwardPacket(interface, ipPacket, ipPacketOffset);
00907 #endif
00908       //We are done
00909       return;
00910    }
00911 #endif
00912 
00913    //Calculate the effective length of the multi-part buffer
00914    length = ipPacketOffset + sizeof(Ipv6Header) +
00915       ntohs(ipHeader->payloadLength);
00916 
00917    //Adjust the length of the multi-part buffer if necessary
00918    netBufferSetLength(ipPacket, length);
00919 
00920    //Form the IPv6 pseudo header
00921    pseudoHeader.length = sizeof(Ipv6PseudoHeader);
00922    pseudoHeader.ipv6Data.srcAddr = ipHeader->srcAddr;
00923    pseudoHeader.ipv6Data.destAddr = ipHeader->destAddr;
00924    pseudoHeader.ipv6Data.reserved = 0;
00925 
00926    //Keep track of Next Header field
00927    nextHeaderOffset = ipPacketOffset + &ipHeader->nextHeader -
00928       (uint8_t *) ipHeader;
00929 
00930    //Point to the first extension header
00931    i = ipPacketOffset + sizeof(Ipv6Header);
00932 
00933    //Parse extension headers
00934    while(i < length)
00935    {
00936       //Retrieve the Next Header field of preceding header
00937       type = netBufferAt(ipPacket, nextHeaderOffset);
00938       //Sanity check
00939       if(type == NULL)
00940          return;
00941 
00942       //Update IPv6 pseudo header
00943       pseudoHeader.ipv6Data.length = htonl(length - i);
00944       pseudoHeader.ipv6Data.nextHeader = *type;
00945 
00946       //Each extension header is identified by the
00947       //Next Header field of the preceding header
00948       switch(*type)
00949       {
00950       //Hop-by-Hop Options header?
00951       case IPV6_HOP_BY_HOP_OPT_HEADER:
00952          //Parse current extension header
00953          error = ipv6ParseHopByHopOptHeader(interface,
00954             ipPacket, ipPacketOffset, &i, &nextHeaderOffset);
00955          //Continue processing
00956          break;
00957 
00958       //Destination Options header?
00959       case IPV6_DEST_OPT_HEADER:
00960          //Parse current extension header
00961          error = ipv6ParseDestOptHeader(interface,
00962             ipPacket, ipPacketOffset, &i, &nextHeaderOffset);
00963          //Continue processing
00964          break;
00965 
00966       //Routing header?
00967       case IPV6_ROUTING_HEADER:
00968          //Parse current extension header
00969          error = ipv6ParseRoutingHeader(interface,
00970             ipPacket, ipPacketOffset, &i, &nextHeaderOffset);
00971          //Continue processing
00972          break;
00973 
00974       //Fragment header?
00975       case IPV6_FRAGMENT_HEADER:
00976 #if (IPV6_FRAG_SUPPORT == ENABLED)
00977          //Parse current extension header
00978          ipv6ParseFragmentHeader(interface,
00979             ipPacket, ipPacketOffset, i, nextHeaderOffset);
00980 #endif
00981          //Exit immediately
00982          return;
00983 
00984       //Authentication header?
00985       case IPV6_AUTH_HEADER:
00986          //Parse current extension header
00987          error = ipv6ParseAuthHeader(interface,
00988             ipPacket, ipPacketOffset, &i, &nextHeaderOffset);
00989          //Continue processing
00990          break;
00991 
00992       //Encapsulating Security Payload header?
00993       case IPV6_ESP_HEADER:
00994          //Parse current extension header
00995          error = ipv6ParseEspHeader(interface,
00996             ipPacket, ipPacketOffset, &i, &nextHeaderOffset);
00997          //Continue processing
00998          break;
00999 
01000       //ICMPv6 header?
01001       case IPV6_ICMPV6_HEADER:
01002          //Process incoming ICMPv6 message
01003          icmpv6ProcessMessage(interface, &pseudoHeader.ipv6Data,
01004             ipPacket, i, ipHeader->hopLimit);
01005 
01006 #if (RAW_SOCKET_SUPPORT == ENABLED)
01007          //Packets addressed to the tentative address should be silently discarded
01008          if(!ipv6IsTentativeAddr(interface, &ipHeader->destAddr))
01009          {
01010             //Allow raw sockets to process ICMPv6 messages
01011             rawSocketProcessIpPacket(interface, &pseudoHeader, ipPacket, i);
01012          }
01013 #endif
01014          //Exit immediately
01015          return;
01016 
01017 #if (TCP_SUPPORT == ENABLED)
01018       //TCP header?
01019       case IPV6_TCP_HEADER:
01020          //Packets addressed to the tentative address should be silently discarded
01021          if(!ipv6IsTentativeAddr(interface, &ipHeader->destAddr))
01022          {
01023             //Process incoming TCP segment
01024             tcpProcessSegment(interface, &pseudoHeader, ipPacket, i);
01025          }
01026          //Exit immediately
01027          return;
01028 #endif
01029 
01030 #if (UDP_SUPPORT == ENABLED)
01031       //UDP header?
01032       case IPV6_UDP_HEADER:
01033          //Packets addressed to the tentative address should be silently discarded
01034          if(!ipv6IsTentativeAddr(interface, &ipHeader->destAddr))
01035          {
01036             //Process incoming UDP datagram
01037             error = udpProcessDatagram(interface, &pseudoHeader, ipPacket, i);
01038 
01039             //Unreachable port?
01040             if(error == ERROR_PORT_UNREACHABLE)
01041             {
01042                //A destination node should originate a Destination Unreachable
01043                //message with Code 4 in response to a packet for which the
01044                //transport protocol has no listener
01045                icmpv6SendErrorMessage(interface, ICMPV6_TYPE_DEST_UNREACHABLE,
01046                   ICMPV6_CODE_PORT_UNREACHABLE, 0, ipPacket, ipPacketOffset);
01047             }
01048          }
01049          //Exit immediately
01050          return;
01051 #endif
01052 
01053       //No next header?
01054       case IPV6_NO_NEXT_HEADER:
01055          //If the payload length field of the IPv6 header indicates the presence of
01056          //octets past the end of the previous header, these octets must be ignored
01057          return;
01058 
01059       //Unrecognized header type?
01060       default:
01061          //Debug message
01062          TRACE_WARNING("Unrecognized Next Header type\r\n");
01063 
01064          //Packets addressed to the tentative address should be silently discarded
01065          if(!ipv6IsTentativeAddr(interface, &ipHeader->destAddr))
01066          {
01067             //Compute the offset of the unrecognized Next Header field within the packet
01068             size_t n = nextHeaderOffset - ipPacketOffset;
01069 
01070             //Send an ICMP Parameter Problem message
01071             icmpv6SendErrorMessage(interface, ICMPV6_TYPE_PARAM_PROBLEM,
01072                ICMPV6_CODE_UNKNOWN_NEXT_HEADER, n, ipPacket, ipPacketOffset);
01073          }
01074 
01075          //Discard incoming packet
01076          return;
01077       }
01078 
01079       //Any error while processing the current extension header?
01080       if(error)
01081          return;
01082    }
01083 }
01084 
01085 
01086 /**
01087  * @brief Parse Hop-by-Hop Options header
01088  * @param[in] interface Underlying network interface
01089  * @param[in] ipPacket Multi-part buffer containing the IPv6 packet
01090  * @param[in] ipPacketOffset Offset to the first byte of the IPv6 packet
01091  * @param[in,out] headerOffset Offset to the Hop-by-Hop Options header
01092  * @param[in,out] nextHeaderOffset Offset to the Next Header field
01093  * @brief Error code
01094  **/
01095 
01096 error_t ipv6ParseHopByHopOptHeader(NetInterface *interface, const NetBuffer *ipPacket,
01097    size_t ipPacketOffset, size_t *headerOffset, size_t *nextHeaderOffset)
01098 {
01099    error_t error;
01100    size_t n;
01101    size_t length;
01102    size_t headerLength;
01103    Ipv6HopByHopOptHeader *header;
01104 
01105    //Remaining bytes to process in the IPv6 packet
01106    length = netBufferGetLength(ipPacket) - *headerOffset;
01107 
01108    //Make sure the extension header is valid
01109    if(length < sizeof(Ipv6HopByHopOptHeader))
01110       return ERROR_INVALID_HEADER;
01111 
01112    //Point to the Hop-by-Hop Options header
01113    header = netBufferAt(ipPacket, *headerOffset);
01114    //Sanity check
01115    if(header == NULL)
01116       return ERROR_FAILURE;
01117 
01118    //Calculate the length of the entire header
01119    headerLength = (header->hdrExtLen * 8) + 8;
01120 
01121    //Check header length
01122    if(headerLength > length)
01123       return ERROR_INVALID_HEADER;
01124 
01125    //Debug message
01126    TRACE_DEBUG("  Hop-by-Hop Options header\r\n");
01127 
01128    //The Hop-by-Hop Options header, when present, must immediately follow
01129    //the IPv6 header
01130    if(*headerOffset != (ipPacketOffset + sizeof(Ipv6Header)))
01131    {
01132       //Compute the offset of the unrecognized Next Header field within the packet
01133       n = *nextHeaderOffset - ipPacketOffset;
01134 
01135       //Send an ICMP Parameter Problem message to the source of the packet
01136       icmpv6SendErrorMessage(interface, ICMPV6_TYPE_PARAM_PROBLEM,
01137          ICMPV6_CODE_UNKNOWN_NEXT_HEADER, n, ipPacket, ipPacketOffset);
01138 
01139       //Discard incoming packet
01140       return ERROR_INVALID_HEADER;
01141    }
01142 
01143    //Compute the length of the Options field
01144    n = headerLength - sizeof(Ipv6HopByHopOptHeader);
01145 
01146    //Parse options
01147    error = ipv6ParseOptions(interface, ipPacket, ipPacketOffset,
01148       *headerOffset + sizeof(Ipv6HopByHopOptHeader), n);
01149 
01150    //Any error to report?
01151    if(error)
01152       return error;
01153 
01154    //Keep track of Next Header field
01155    *nextHeaderOffset = *headerOffset + &header->nextHeader - (uint8_t *) header;
01156    //Point to the next extension header
01157    *headerOffset += headerLength;
01158 
01159    //Successful processing
01160    return NO_ERROR;
01161 }
01162 
01163 
01164 /**
01165  * @brief Parse Destination Options header
01166  * @param[in] interface Underlying network interface
01167  * @param[in] ipPacket Multi-part buffer containing the IPv6 packet
01168  * @param[in] ipPacketOffset Offset to the first byte of the IPv6 packet
01169  * @param[in,out] headerOffset Offset to the Destination Options header
01170  * @param[in,out] nextHeaderOffset Offset to the Next Header field
01171  * @brief Error code
01172  **/
01173 
01174 error_t ipv6ParseDestOptHeader(NetInterface *interface, const NetBuffer *ipPacket,
01175    size_t ipPacketOffset, size_t *headerOffset, size_t *nextHeaderOffset)
01176 {
01177    error_t error;
01178    size_t n;
01179    size_t length;
01180    size_t headerLength;
01181    Ipv6DestOptHeader *header;
01182 
01183    //Remaining bytes to process in the IPv6 packet
01184    length = netBufferGetLength(ipPacket) - *headerOffset;
01185 
01186    //Make sure the extension header is valid
01187    if(length < sizeof(Ipv6DestOptHeader))
01188       return ERROR_INVALID_HEADER;
01189 
01190    //Point to the Destination Options header
01191    header = netBufferAt(ipPacket, *headerOffset);
01192    //Sanity check
01193    if(header == NULL)
01194       return ERROR_FAILURE;
01195 
01196    //Calculate the length of the entire header
01197    headerLength = (header->hdrExtLen * 8) + 8;
01198 
01199    //Check header length
01200    if(headerLength > length)
01201       return ERROR_INVALID_HEADER;
01202 
01203    //Debug message
01204    TRACE_DEBUG("  Destination Options header\r\n");
01205 
01206    //Compute the length of the Options field
01207    n = headerLength - sizeof(Ipv6DestOptHeader);
01208 
01209    //Parse options
01210    error = ipv6ParseOptions(interface, ipPacket, ipPacketOffset,
01211       *headerOffset + sizeof(Ipv6DestOptHeader), n);
01212 
01213    //Any error to report?
01214    if(error)
01215       return error;
01216 
01217    //Keep track of Next Header field
01218    *nextHeaderOffset = *headerOffset + &header->nextHeader - (uint8_t *) header;
01219    //Point to the next extension header
01220    *headerOffset += headerLength;
01221 
01222    //Successful processing
01223    return NO_ERROR;
01224 }
01225 
01226 
01227 /**
01228  * @brief Parse Routing header
01229  * @param[in] interface Underlying network interface
01230  * @param[in] ipPacket Multi-part buffer containing the IPv6 packet
01231  * @param[in] ipPacketOffset Offset to the first byte of the IPv6 packet
01232  * @param[in,out] headerOffset Offset to the Routing header
01233  * @param[in,out] nextHeaderOffset Offset to the Next Header field
01234  * @brief Error code
01235  **/
01236 
01237 error_t ipv6ParseRoutingHeader(NetInterface *interface, const NetBuffer *ipPacket,
01238    size_t ipPacketOffset, size_t *headerOffset, size_t *nextHeaderOffset)
01239 {
01240    size_t n;
01241    size_t length;
01242    size_t headerLength;
01243    Ipv6RoutingHeader *header;
01244 
01245    //Remaining bytes to process in the IPv6 packet
01246    length = netBufferGetLength(ipPacket) - *headerOffset;
01247 
01248    //Make sure the extension header is valid
01249    if(length < sizeof(Ipv6RoutingHeader))
01250       return ERROR_INVALID_HEADER;
01251 
01252    //Point to the Routing header
01253    header = netBufferAt(ipPacket, *headerOffset);
01254    //Sanity check
01255    if(header == NULL)
01256       return ERROR_FAILURE;
01257 
01258    //Calculate the length of the entire header
01259    headerLength = (header->hdrExtLen * 8) + 8;
01260 
01261    //Check header length
01262    if(headerLength > length)
01263       return ERROR_INVALID_HEADER;
01264 
01265    //Debug message
01266    TRACE_DEBUG("  Routing header\r\n");
01267 
01268    //If, while processing a received packet, a node encounters a Routing
01269    //header with an unrecognized Routing Type value, the required behavior
01270    //of the node depends on the value of the Segments Left field
01271    if(header->segmentsLeft != 0)
01272    {
01273       //Retrieve the offset of the Routing header within the packet
01274       n = *headerOffset - ipPacketOffset;
01275       //Compute the exact offset of the Routing Type field
01276       n += (uint8_t *) &header->routingType - (uint8_t *) header;
01277 
01278       //If Segments Left is non-zero, send an ICMP Parameter Problem,
01279       //Code 0, message to the packet's Source Address, pointing to
01280       //the unrecognized Routing Type
01281       icmpv6SendErrorMessage(interface, ICMPV6_TYPE_PARAM_PROBLEM,
01282          ICMPV6_CODE_INVALID_HEADER_FIELD, n, ipPacket, ipPacketOffset);
01283 
01284       //The node must discard the packet
01285       return ERROR_INVALID_TYPE;
01286    }
01287 
01288    //Keep track of Next Header field
01289    *nextHeaderOffset = *headerOffset + &header->nextHeader - (uint8_t *) header;
01290    //Point to the next extension header
01291    *headerOffset += headerLength;
01292 
01293    //Successful processing
01294    return NO_ERROR;
01295 }
01296 
01297 
01298 /**
01299  * @brief Parse Authentication header
01300  * @param[in] interface Underlying network interface
01301  * @param[in] ipPacket Multi-part buffer containing the IPv6 packet
01302  * @param[in] ipPacketOffset Offset to the first byte of the IPv6 packet
01303  * @param[in,out] headerOffset Offset to the Authentication header
01304  * @param[in,out] nextHeaderOffset Offset to the Next Header field
01305  * @brief Error code
01306  **/
01307 
01308 error_t ipv6ParseAuthHeader(NetInterface *interface, const NetBuffer *ipPacket,
01309    size_t ipPacketOffset, size_t *headerOffset, size_t *nextHeaderOffset)
01310 {
01311    //Debug message
01312    TRACE_DEBUG("  Authentication header\r\n");
01313    //Authentication not supported
01314    return ERROR_FAILURE;
01315 }
01316 
01317 
01318 /**
01319  * @brief Parse Encapsulating Security Payload header
01320  * @param[in] interface Underlying network interface
01321  * @param[in] ipPacket Multi-part buffer containing the IPv6 packet
01322  * @param[in] ipPacketOffset Offset to the first byte of the IPv6 packet
01323  * @param[in,out] headerOffset Offset to the Encapsulating Security Payload header
01324  * @param[in,out] nextHeaderOffset Offset to the Next Header field
01325  * @brief Error code
01326  **/
01327 
01328 error_t ipv6ParseEspHeader(NetInterface *interface, const NetBuffer *ipPacket,
01329    size_t ipPacketOffset, size_t *headerOffset, size_t *nextHeaderOffset)
01330 {
01331    //Debug message
01332    TRACE_DEBUG("  Encapsulating Security Payload header\r\n");
01333    //Authentication not supported
01334    return ERROR_FAILURE;
01335 }
01336 
01337 
01338 /**
01339  * @brief Parse IPv6 options
01340  * @param[in] interface Underlying network interface
01341  * @param[in] ipPacket Multi-part buffer containing the IPv6 packet
01342  * @param[in] ipPacketOffset Offset to the first byte of the IPv6 packet
01343  * @param[in] optOffset Offset to the first byte of the Options field
01344  * @param[in] optLength Length of the Options field
01345  * @brief Error code
01346  **/
01347 
01348 error_t ipv6ParseOptions(NetInterface *interface, const NetBuffer *ipPacket,
01349    size_t ipPacketOffset, size_t optOffset, size_t optLength)
01350 {
01351    size_t i;
01352    size_t n;
01353    uint8_t type;
01354    uint8_t action;
01355    uint8_t *options;
01356    Ipv6Option *option;
01357    Ipv6Header *ipHeader;
01358 
01359    //Point to the first byte of the Options field
01360    options = netBufferAt(ipPacket, optOffset);
01361 
01362    //Sanity check
01363    if(options == NULL)
01364       return ERROR_FAILURE;
01365 
01366    //Parse options
01367    for(i = 0; i < optLength; )
01368    {
01369       //Point to the current option
01370       option = (Ipv6Option *) (options + i);
01371       //Get option type
01372       type = option->type & IPV6_OPTION_TYPE_MASK;
01373 
01374       //Pad1 option?
01375       if(type == IPV6_OPTION_TYPE_PAD1)
01376       {
01377          //Advance data pointer
01378          i++;
01379       }
01380       //PadN option?
01381       else if(type == IPV6_OPTION_TYPE_PADN)
01382       {
01383          //Malformed IPv6 packet?
01384          if((i + sizeof(Ipv6Option)) > optLength)
01385             return ERROR_INVALID_LENGTH;
01386 
01387          //Advance data pointer
01388          i += sizeof(Ipv6Option) + option->length;
01389       }
01390       //Unrecognized option?
01391       else
01392       {
01393          //Point to the IPv6 header
01394          ipHeader = netBufferAt(ipPacket, ipPacketOffset);
01395 
01396          //Sanity check
01397          if(ipHeader == NULL)
01398             return ERROR_FAILURE;
01399 
01400          //Get the value of the highest-order two bits
01401          action = option->type & IPV6_ACTION_MASK;
01402 
01403          //The highest-order two bits specify the action that must be taken
01404          //if the processing IPv6 node does not recognize the option type
01405          if(action == IPV6_ACTION_SKIP_OPTION)
01406          {
01407             //Skip over this option and continue processing the header
01408          }
01409          else if(action == IPV6_ACTION_DISCARD_PACKET)
01410          {
01411             //Discard the packet
01412             return ERROR_INVALID_OPTION;
01413          }
01414          else if(action == IPV6_ACTION_SEND_ICMP_ERROR_ALL)
01415          {
01416             //Calculate the octet offset within the invoking packet
01417             //where the error was detected
01418             n = optOffset + i - ipPacketOffset;
01419 
01420             //Send an ICMP Parameter Problem message to the source of the
01421             //packet, regardless of whether or not the destination address
01422             //was a multicast address
01423             icmpv6SendErrorMessage(interface, ICMPV6_TYPE_PARAM_PROBLEM,
01424                ICMPV6_CODE_UNKNOWN_IPV6_OPTION, n, ipPacket, ipPacketOffset);
01425 
01426             //Discard the packet
01427             return ERROR_INVALID_OPTION;
01428          }
01429          else if(action == IPV6_ACTION_SEND_ICMP_ERROR_UNI)
01430          {
01431             //Send an ICMP Parameter Problem message to the source of the
01432             //packet, only if the destination address was not a multicast
01433             //address
01434             if(!ipv6IsMulticastAddr(&ipHeader->destAddr))
01435             {
01436                //Calculate the octet offset within the invoking packet
01437                //where the error was detected
01438                n = optOffset + i - ipPacketOffset;
01439 
01440                //Send the ICMP Parameter Problem message
01441                icmpv6SendErrorMessage(interface, ICMPV6_TYPE_PARAM_PROBLEM,
01442                   ICMPV6_CODE_UNKNOWN_IPV6_OPTION, n, ipPacket, ipPacketOffset);
01443             }
01444 
01445             //Discard the packet
01446             return ERROR_INVALID_OPTION;
01447          }
01448 
01449          //Malformed IPv6 packet?
01450          if((i + sizeof(Ipv6Option)) > optLength)
01451             return ERROR_INVALID_LENGTH;
01452 
01453          //Advance data pointer
01454          i += sizeof(Ipv6Option) + option->length;
01455       }
01456    }
01457 
01458    //Successful processing
01459    return NO_ERROR;
01460 }
01461 
01462 
01463 /**
01464  * @brief Send an IPv6 datagram
01465  * @param[in] interface Underlying network interface
01466  * @param[in] pseudoHeader IPv6 pseudo header
01467  * @param[in] buffer Multi-part buffer containing the payload
01468  * @param[in] offset Offset to the first byte of the payload
01469  * @param[in] hopLimit Hop Limit value. Default value is used when this parameter is zero
01470  * @return Error code
01471  **/
01472 
01473 error_t ipv6SendDatagram(NetInterface *interface, Ipv6PseudoHeader *pseudoHeader,
01474    NetBuffer *buffer, size_t offset, uint8_t hopLimit)
01475 {
01476    error_t error;
01477    size_t length;
01478    size_t pathMtu;
01479 
01480    //Retrieve the length of payload
01481    length = netBufferGetLength(buffer) - offset;
01482 
01483    //Check whether the Hop Limit value is zero
01484    if(hopLimit == 0)
01485    {
01486       //Use default Hop Limit value
01487       hopLimit = interface->ipv6Context.curHopLimit;
01488    }
01489 
01490 #if (IPV6_PMTU_SUPPORT == ENABLED)
01491    //Retrieve the PMTU for the specified destination address
01492    pathMtu = ipv6GetPathMtu(interface, &pseudoHeader->destAddr);
01493 
01494    //The PMTU should not exceed the MTU of the first-hop link
01495    if(pathMtu > interface->ipv6Context.linkMtu)
01496       pathMtu = interface->ipv6Context.linkMtu;
01497 #else
01498    //The PMTU value for the path is assumed to be the MTU of the first-hop link
01499    pathMtu = interface->ipv6Context.linkMtu;
01500 #endif
01501 
01502    //If the payload is smaller than the PMTU then no fragmentation is needed
01503    if((length + sizeof(Ipv6Header)) <= pathMtu)
01504    {
01505       //Send data as is
01506       error = ipv6SendPacket(interface, pseudoHeader,
01507          0, 0, buffer, offset, hopLimit);
01508    }
01509    //If the payload length exceeds the PMTU then the device must fragment the data
01510    else
01511    {
01512 #if (IPV6_FRAG_SUPPORT == ENABLED)
01513       //Fragment IP datagram into smaller packets
01514       error = ipv6FragmentDatagram(interface, pseudoHeader,
01515          buffer, offset, pathMtu, hopLimit);
01516 #else
01517       //Fragmentation is not supported
01518       error = ERROR_MESSAGE_TOO_LONG;
01519 #endif
01520    }
01521 
01522    //Return status code
01523    return error;
01524 }
01525 
01526 
01527 /**
01528  * @brief Send an IPv6 packet
01529  * @param[in] interface Underlying network interface
01530  * @param[in] pseudoHeader IPv6 pseudo header
01531  * @param[in] fragId Fragment identification field
01532  * @param[in] fragOffset Fragment offset field
01533  * @param[in] buffer Multi-part buffer containing the payload
01534  * @param[in] offset Offset to the first byte of the payload
01535  * @param[in] hopLimit Hop Limit value
01536  * @return Error code
01537  **/
01538 
01539 error_t ipv6SendPacket(NetInterface *interface, Ipv6PseudoHeader *pseudoHeader,
01540    uint32_t fragId, size_t fragOffset, NetBuffer *buffer, size_t offset, uint8_t hopLimit)
01541 {
01542    error_t error;
01543    size_t length;
01544    Ipv6Header *packet;
01545 
01546    //Calculate the length of the payload
01547    length = netBufferGetLength(buffer) - offset;
01548 
01549    //Add Fragment header?
01550    if(fragOffset != 0)
01551    {
01552       Ipv6FragmentHeader *header;
01553 
01554       //Is there enough space for the IPv6 header and the Fragment header?
01555       if(offset < (sizeof(Ipv6Header) + sizeof(Ipv6FragmentHeader)))
01556          return ERROR_INVALID_PARAMETER;
01557 
01558       //Make room for the Fragment header
01559       offset -= sizeof(Ipv6FragmentHeader);
01560       length += sizeof(Ipv6FragmentHeader);
01561 
01562       //Point to the Fragment header
01563       header = netBufferAt(buffer, offset);
01564       //Format the Fragment header
01565       header->nextHeader = pseudoHeader->nextHeader;
01566       header->reserved = 0;
01567       header->fragmentOffset = htons(fragOffset);
01568       header->identification = htonl(fragId);
01569 
01570       //Make room for the IPv6 header
01571       offset -= sizeof(Ipv6Header);
01572       length += sizeof(Ipv6Header);
01573 
01574       //Point to the IPv6 header
01575       packet = netBufferAt(buffer, offset);
01576       //Properly set the Next Header field
01577       packet->nextHeader = IPV6_FRAGMENT_HEADER;
01578    }
01579    else
01580    {
01581       //Is there enough space for the IPv6 header?
01582       if(offset < sizeof(Ipv6Header))
01583          return ERROR_INVALID_PARAMETER;
01584 
01585       //Make room for the IPv6 header
01586       offset -= sizeof(Ipv6Header);
01587       length += sizeof(Ipv6Header);
01588 
01589       //Point to the IPv6 header
01590       packet = netBufferAt(buffer, offset);
01591       //Properly set the Next Header field
01592       packet->nextHeader = pseudoHeader->nextHeader;
01593    }
01594 
01595    //Format IPv6 header
01596    packet->version = IPV6_VERSION;
01597    packet->trafficClassH = 0;
01598    packet->trafficClassL = 0;
01599    packet->flowLabelH = 0;
01600    packet->flowLabelL = 0;
01601    packet->payloadLength = htons(length - sizeof(Ipv6Header));
01602    packet->hopLimit = hopLimit;
01603    packet->srcAddr = pseudoHeader->srcAddr;
01604    packet->destAddr = pseudoHeader->destAddr;
01605 
01606    //Check whether the source address is acceptable
01607    error = ipv6CheckSourceAddr(interface, &pseudoHeader->srcAddr);
01608    //Invalid source address?
01609    if(error)
01610       return error;
01611 
01612    //Destination IPv6 address is the unspecified address?
01613    if(ipv6CompAddr(&pseudoHeader->destAddr, &IPV6_UNSPECIFIED_ADDR))
01614    {
01615       //Destination address is not acceptable
01616       return ERROR_INVALID_ADDRESS;
01617    }
01618    //Destination address is the loopback address?
01619    else if(ipv6CompAddr(&pseudoHeader->destAddr, &IPV6_LOOPBACK_ADDR))
01620    {
01621       //Not yet implemented...
01622       return ERROR_NOT_IMPLEMENTED;
01623    }
01624 
01625 #if (ETH_SUPPORT == ENABLED)
01626    //Ethernet interface?
01627    if(interface->nicDriver->type == NIC_TYPE_ETHERNET)
01628    {
01629       Ipv6Addr destIpAddr;
01630       MacAddr destMacAddr;
01631       NdpDestCacheEntry *entry;
01632 
01633       //When the sending node has a packet to send, it first examines
01634       //the Destination Cache
01635       entry = ndpFindDestCacheEntry(interface, &pseudoHeader->destAddr);
01636 
01637       //Check whether a matching entry exists
01638       if(entry != NULL)
01639       {
01640          //Retrieve the address of the next-hop
01641          destIpAddr = entry->nextHop;
01642          //Update timestamp
01643          entry->timestamp = osGetSystemTime();
01644          //No error to report
01645          error = NO_ERROR;
01646       }
01647       else
01648       {
01649          //Perform next-hop determination
01650          error = ndpSelectNextHop(interface,
01651             &pseudoHeader->destAddr, NULL, &destIpAddr);
01652 
01653          //Check status code
01654          if(error == NO_ERROR)
01655          {
01656             //Create a new Destination Cache entry
01657             entry = ndpCreateDestCacheEntry(interface);
01658 
01659             //Destination cache entry successfully created?
01660             if(entry != NULL)
01661             {
01662                //Destination address
01663                entry->destAddr = pseudoHeader->destAddr;
01664                //Address of the next hop
01665                entry->nextHop = destIpAddr;
01666 
01667                //Initially, the PMTU value for a path is assumed to be
01668                //the MTU of the first-hop link
01669                entry->pathMtu = interface->ipv6Context.linkMtu;
01670 
01671                //Set timestamp
01672                entry->timestamp = osGetSystemTime();
01673             }
01674          }
01675       }
01676 
01677       //Successful next-hop determination?
01678       if(error == NO_ERROR)
01679       {
01680          //Destination IPv6 address is a multicast address?
01681          if(ipv6IsMulticastAddr(&destIpAddr))
01682          {
01683             //Map IPv6 multicast address to MAC-layer multicast address
01684             error = ipv6MapMulticastAddrToMac(&destIpAddr, &destMacAddr);
01685          }
01686          else
01687          {
01688             //Resolve host address using Neighbor Discovery protocol
01689             error = ndpResolve(interface, &destIpAddr, &destMacAddr);
01690          }
01691 
01692          //Successful address resolution?
01693          if(error == NO_ERROR)
01694          {
01695             //Debug message
01696             TRACE_INFO("Sending IPv6 packet (%" PRIuSIZE " bytes)...\r\n", length);
01697             //Dump IP header contents for debugging purpose
01698             ipv6DumpHeader(packet);
01699 
01700             //Send Ethernet frame
01701             error = ethSendFrame(interface, &destMacAddr, buffer, offset, ETH_TYPE_IPV6);
01702          }
01703          //Address resolution is in progress?
01704          else if(error == ERROR_IN_PROGRESS)
01705          {
01706             //Debug message
01707             TRACE_INFO("Enqueuing IPv6 packet (%" PRIuSIZE " bytes)...\r\n", length);
01708             //Dump IP header contents for debugging purpose
01709             ipv6DumpHeader(packet);
01710 
01711             //Enqueue packets waiting for address resolution
01712             error = ndpEnqueuePacket(NULL, interface, &destIpAddr, buffer, offset);
01713          }
01714          //Address resolution failed?
01715          else
01716          {
01717             //Debug message
01718             TRACE_WARNING("Cannot map IPv6 address to Ethernet address!\r\n");
01719          }
01720       }
01721    }
01722    else
01723 #endif
01724 #if (PPP_SUPPORT == ENABLED)
01725    //PPP interface?
01726    if(interface->nicDriver->type == NIC_TYPE_PPP)
01727    {
01728       //Debug message
01729       TRACE_INFO("Sending IPv6 packet (%" PRIuSIZE " bytes)...\r\n", length);
01730       //Dump IP header contents for debugging purpose
01731       ipv6DumpHeader(packet);
01732 
01733       //Send PPP frame
01734       error = pppSendFrame(interface, buffer, offset, PPP_PROTOCOL_IPV6);
01735    }
01736    else
01737 #endif
01738    //6LoWPAN interface?
01739    if(interface->nicDriver->type == NIC_TYPE_6LOWPAN)
01740    {
01741       //Debug message
01742       TRACE_INFO("Sending IPv6 packet (%" PRIuSIZE " bytes)...\r\n", length);
01743       //Dump IP header contents for debugging purpose
01744       ipv6DumpHeader(packet);
01745 
01746       //Send the packet over the specified link
01747       error = nicSendPacket(interface, buffer, offset);
01748    }
01749    else
01750    //Unknown interface type?
01751    {
01752       //Report an error
01753       error = ERROR_INVALID_INTERFACE;
01754    }
01755 
01756    //Return status code
01757    return error;
01758 }
01759 
01760 
01761 /**
01762  * @brief Join an IPv6 multicast group
01763  * @param[in] interface Underlying network interface
01764  * @param[in] groupAddr IPv6 Multicast address to join
01765  * @return Error code
01766  **/
01767 
01768 error_t ipv6JoinMulticastGroup(NetInterface *interface, const Ipv6Addr *groupAddr)
01769 {
01770    error_t error;
01771    uint_t i;
01772    Ipv6FilterEntry *entry;
01773    Ipv6FilterEntry *firstFreeEntry;
01774 #if (ETH_SUPPORT == ENABLED)
01775    MacAddr macAddr;
01776 #endif
01777 
01778    //The IPv6 address must be a valid multicast address
01779    if(!ipv6IsMulticastAddr(groupAddr))
01780       return ERROR_INVALID_ADDRESS;
01781 
01782    //Initialize error code
01783    error = NO_ERROR;
01784    //Keep track of the first free entry
01785    firstFreeEntry = NULL;
01786 
01787    //Go through the multicast filter table
01788    for(i = 0; i < IPV6_MULTICAST_FILTER_SIZE; i++)
01789    {
01790       //Point to the current entry
01791       entry = &interface->ipv6Context.multicastFilter[i];
01792 
01793       //Valid entry?
01794       if(entry->refCount > 0)
01795       {
01796          //Check whether the table already contains the specified IPv6 address
01797          if(ipv6CompAddr(&entry->addr, groupAddr))
01798          {
01799             //Increment the reference count
01800             entry->refCount++;
01801             //Successful processing
01802             return NO_ERROR;
01803          }
01804       }
01805       else
01806       {
01807          //Keep track of the first free entry
01808          if(firstFreeEntry == NULL)
01809             firstFreeEntry = entry;
01810       }
01811    }
01812 
01813    //Check whether the multicast filter table is full
01814    if(firstFreeEntry == NULL)
01815    {
01816       //A new entry cannot be added
01817       return ERROR_FAILURE;
01818    }
01819 
01820 #if (ETH_SUPPORT == ENABLED)
01821    //Map the IPv6 multicast address to a MAC-layer address
01822    ipv6MapMulticastAddrToMac(groupAddr, &macAddr);
01823    //Add the corresponding address to the MAC filter table
01824    error = ethAcceptMulticastAddr(interface, &macAddr);
01825 #endif
01826 
01827    //MAC filter table successfully updated?
01828    if(!error)
01829    {
01830       //Now we can safely add a new entry to the table
01831       firstFreeEntry->addr = *groupAddr;
01832       //Initialize the reference count
01833       firstFreeEntry->refCount = 1;
01834 
01835 #if (MLD_SUPPORT == ENABLED)
01836       //Start listening to the multicast address
01837       mldStartListening(interface, firstFreeEntry);
01838 #endif
01839    }
01840 
01841    //Return status code
01842    return error;
01843 }
01844 
01845 
01846 /**
01847  * @brief Leave an IPv6 multicast group
01848  * @param[in] interface Underlying network interface
01849  * @param[in] groupAddr IPv6 multicast address to drop
01850  * @return Error code
01851  **/
01852 
01853 error_t ipv6LeaveMulticastGroup(NetInterface *interface, const Ipv6Addr *groupAddr)
01854 {
01855    uint_t i;
01856    Ipv6FilterEntry *entry;
01857 #if (ETH_SUPPORT == ENABLED)
01858    MacAddr macAddr;
01859 #endif
01860 
01861    //The IPv6 address must be a valid multicast address
01862    if(!ipv6IsMulticastAddr(groupAddr))
01863       return ERROR_INVALID_ADDRESS;
01864 
01865    //Go through the multicast filter table
01866    for(i = 0; i < IPV6_MULTICAST_FILTER_SIZE; i++)
01867    {
01868       //Point to the current entry
01869       entry = &interface->ipv6Context.multicastFilter[i];
01870 
01871       //Valid entry?
01872       if(entry->refCount > 0)
01873       {
01874          //Specified IPv6 address found?
01875          if(ipv6CompAddr(&entry->addr, groupAddr))
01876          {
01877             //Decrement the reference count
01878             entry->refCount--;
01879 
01880             //Remove the entry if the reference count drops to zero
01881             if(entry->refCount == 0)
01882             {
01883 #if (MLD_SUPPORT == ENABLED)
01884                //Stop listening to the multicast address
01885                mldStopListening(interface, entry);
01886 #endif
01887 #if (ETH_SUPPORT == ENABLED)
01888                //Map the IPv6 multicast address to a MAC-layer address
01889                ipv6MapMulticastAddrToMac(groupAddr, &macAddr);
01890                //Drop the corresponding address from the MAC filter table
01891                ethDropMulticastAddr(interface, &macAddr);
01892 #endif
01893                //Remove the multicast address from the list
01894                entry->addr = IPV6_UNSPECIFIED_ADDR;
01895             }
01896 
01897             //Successful processing
01898             return NO_ERROR;
01899          }
01900       }
01901    }
01902 
01903    //The specified IPv6 address does not exist
01904    return ERROR_ADDRESS_NOT_FOUND;
01905 }
01906 
01907 
01908 /**
01909  * @brief Convert a string representation of an IPv6 address to a binary IPv6 address
01910  * @param[in] str NULL-terminated string representing the IPv6 address
01911  * @param[out] ipAddr Binary representation of the IPv6 address
01912  * @return Error code
01913  **/
01914 
01915 error_t ipv6StringToAddr(const char_t *str, Ipv6Addr *ipAddr)
01916 {
01917    error_t error;
01918    int_t i = 0;
01919    int_t j = -1;
01920    int_t k = 0;
01921    int32_t value = -1;
01922 
01923    //Parse input string
01924    while(1)
01925    {
01926       //Hexadecimal digit found?
01927       if(isxdigit((uint8_t) *str))
01928       {
01929          //First digit to be decoded?
01930          if(value < 0)
01931             value = 0;
01932 
01933          //Update the value of the current 16-bit word
01934          if(isdigit((uint8_t) *str))
01935             value = (value * 16) + (*str - '0');
01936          else if(isupper((uint8_t) *str))
01937             value = (value * 16) + (*str - 'A' + 10);
01938          else
01939             value = (value * 16) + (*str - 'a' + 10);
01940 
01941          //Check resulting value
01942          if(value > 0xFFFF)
01943          {
01944             //The conversion failed
01945             error = ERROR_INVALID_SYNTAX;
01946             break;
01947          }
01948       }
01949       //"::" symbol found?
01950       else if(!strncmp(str, "::", 2))
01951       {
01952          //The "::" can only appear once in an IPv6 address
01953          if(j >= 0)
01954          {
01955             //The conversion failed
01956             error = ERROR_INVALID_SYNTAX;
01957             break;
01958          }
01959 
01960          //The "::" symbol is preceded by a number?
01961          if(value >= 0)
01962          {
01963             //Save the current 16-bit word
01964             ipAddr->w[i++] = htons(value);
01965             //Prepare to decode the next 16-bit word
01966             value = -1;
01967          }
01968 
01969          //Save the position of the "::" symbol
01970          j = i;
01971          //Point to the next character
01972          str++;
01973       }
01974       //":" symbol found?
01975       else if(*str == ':' && i < 8)
01976       {
01977          //Each ":" must be preceded by a valid number
01978          if(value < 0)
01979          {
01980             //The conversion failed
01981             error = ERROR_INVALID_SYNTAX;
01982             break;
01983          }
01984 
01985          //Save the current 16-bit word
01986          ipAddr->w[i++] = htons(value);
01987          //Prepare to decode the next 16-bit word
01988          value = -1;
01989       }
01990       //End of string detected?
01991       else if(*str == '\0' && i == 7 && j < 0)
01992       {
01993          //The NULL character must be preceded by a valid number
01994          if(value < 0)
01995          {
01996             //The conversion failed
01997             error = ERROR_INVALID_SYNTAX;
01998          }
01999          else
02000          {
02001             //Save the last 16-bit word of the IPv6 address
02002             ipAddr->w[i] = htons(value);
02003             //The conversion succeeded
02004             error = NO_ERROR;
02005          }
02006 
02007          //We are done
02008          break;
02009       }
02010       else if(*str == '\0' && i < 7 && j >= 0)
02011       {
02012          //Save the last 16-bit word of the IPv6 address
02013          if(value >= 0)
02014             ipAddr->w[i++] = htons(value);
02015 
02016          //Move the part of the address that follows the "::" symbol
02017          for(k = 0; k < (i - j); k++)
02018             ipAddr->w[7 - k] = ipAddr->w[i - 1 - k];
02019          //A sequence of zeroes can now be written in place of "::"
02020          for(k = 0; k < (8 - i); k++)
02021             ipAddr->w[j + k] = 0;
02022 
02023          //The conversion succeeded
02024          error = NO_ERROR;
02025          break;
02026       }
02027       //Invalid character...
02028       else
02029       {
02030          //The conversion failed
02031          error = ERROR_INVALID_SYNTAX;
02032          break;
02033       }
02034 
02035       //Point to the next character
02036       str++;
02037    }
02038 
02039    //Return status code
02040    return error;
02041 }
02042 
02043 
02044 /**
02045  * @brief Convert a binary IPv6 address to a string representation
02046  *
02047  * Call ipv6AddrToString() to convert an IPv6 address to a text representation. The
02048  * implementation of ipv6AddrToString() function follows RFC 5952 recommendations
02049  *
02050  * @param[in] ipAddr Binary representation of the IPv6 address
02051  * @param[out] str NULL-terminated string representing the IPv6 address
02052  * @return Pointer to the formatted string
02053  **/
02054 
02055 char_t *ipv6AddrToString(const Ipv6Addr *ipAddr, char_t *str)
02056 {
02057    static char_t buffer[40];
02058    uint_t i;
02059    uint_t j;
02060    char_t *p;
02061 
02062    //Best run of zeroes
02063    uint_t zeroRunStart = 0;
02064    uint_t zeroRunEnd = 0;
02065 
02066    //If the NULL pointer is given as parameter, then the internal buffer is used
02067    if(str == NULL)
02068       str = buffer;
02069 
02070    //Find the longest run of zeros for "::" short-handing
02071    for(i = 0; i < 8; i++)
02072    {
02073       //Compute the length of the current sequence of zeroes
02074       for(j = i; j < 8 && !ipAddr->w[j]; j++);
02075 
02076       //Keep track of the longest one
02077       if((j - i) > 1 && (j - i) > (zeroRunEnd - zeroRunStart))
02078       {
02079          //The symbol "::" should not be used to shorten just one zero field
02080          zeroRunStart = i;
02081          zeroRunEnd = j;
02082       }
02083    }
02084 
02085    //Format IPv6 address
02086    for(p = str, i = 0; i < 8; i++)
02087    {
02088       //Are we inside the best run of zeroes?
02089       if(i >= zeroRunStart && i < zeroRunEnd)
02090       {
02091          //Append a separator
02092          *(p++) = ':';
02093          //Skip the sequence of zeroes
02094          i = zeroRunEnd - 1;
02095       }
02096       else
02097       {
02098          //Add a separator between each 16-bit word
02099          if(i > 0)
02100             *(p++) = ':';
02101 
02102          //Convert the current 16-bit word to string
02103          p += sprintf(p, "%" PRIx16, ntohs(ipAddr->w[i]));
02104       }
02105    }
02106 
02107    //A trailing run of zeroes has been found?
02108    if(zeroRunEnd == 8)
02109       *(p++) = ':';
02110 
02111    //Properly terminate the string
02112    *p = '\0';
02113 
02114    //Return a pointer to the formatted string
02115    return str;
02116 }
02117 
02118 
02119 /**
02120  * @brief Dump IPv6 header for debugging purpose
02121  * @param[in] ipHeader IPv6 header
02122  **/
02123 
02124 void ipv6DumpHeader(const Ipv6Header *ipHeader)
02125 {
02126    //Dump IPv6 header contents
02127    TRACE_DEBUG("  Version = %" PRIu8 "\r\n", ipHeader->version);
02128    TRACE_DEBUG("  Traffic Class = %u\r\n", (ipHeader->trafficClassH << 4) | ipHeader->trafficClassL);
02129    TRACE_DEBUG("  Flow Label = 0x%05X\r\n", (ipHeader->flowLabelH << 16) | ntohs(ipHeader->flowLabelL));
02130    TRACE_DEBUG("  Payload Length = %" PRIu16 "\r\n", ntohs(ipHeader->payloadLength));
02131    TRACE_DEBUG("  Next Header = %" PRIu8 "\r\n", ipHeader->nextHeader);
02132    TRACE_DEBUG("  Hop Limit = %" PRIu8 "\r\n", ipHeader->hopLimit);
02133    TRACE_DEBUG("  Src Addr = %s\r\n", ipv6AddrToString(&ipHeader->srcAddr, NULL));
02134    TRACE_DEBUG("  Dest Addr = %s\r\n", ipv6AddrToString(&ipHeader->destAddr, NULL));
02135 }
02136 
02137 #endif
02138