ipv6.c
Go to the documentation of this file.
1 /**
2  * @file ipv6.c
3  * @brief IPv6 (Internet Protocol Version 6)
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2019 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @section Description
28  *
29  * IP version 6 (IPv6) is a new version of the Internet Protocol, designed
30  * as the successor to IP version 4 (IPv4). Refer to RFC 2460
31  *
32  * @author Oryx Embedded SARL (www.oryx-embedded.com)
33  * @version 1.9.6
34  **/
35 
36 //Switch to the appropriate trace level
37 #define TRACE_LEVEL IPV6_TRACE_LEVEL
38 
39 //Dependencies
40 #include <string.h>
41 #include <ctype.h>
42 #include "core/net.h"
43 #include "core/ip.h"
44 #include "core/udp.h"
45 #include "core/tcp_fsm.h"
46 #include "core/raw_socket.h"
47 #include "ipv6/ipv6.h"
48 #include "ipv6/ipv6_frag.h"
49 #include "ipv6/ipv6_misc.h"
50 #include "ipv6/ipv6_pmtu.h"
51 #include "ipv6/ipv6_routing.h"
52 #include "ipv6/icmpv6.h"
53 #include "ipv6/mld.h"
54 #include "ipv6/ndp.h"
55 #include "ipv6/ndp_cache.h"
56 #include "ipv6/ndp_misc.h"
57 #include "ipv6/ndp_router_adv.h"
58 #include "ipv6/slaac.h"
59 #include "dhcpv6/dhcpv6_client.h"
60 #include "mibs/ip_mib_module.h"
61 #include "debug.h"
62 
63 //Check TCP/IP stack configuration
64 #if (IPV6_SUPPORT == ENABLED)
65 
66 //Unspecified IPv6 address
68  IPV6_ADDR(0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000);
69 
70 //Loopback IPv6 address
72  IPV6_ADDR(0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001);
73 
74 //Link-local All-Nodes IPv6 address
76  IPV6_ADDR(0xFF02, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001);
77 
78 //Link-local All-Routers IPv6 address
80  IPV6_ADDR(0xFF02, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0002);
81 
82 //Link-local IPv6 address prefix
84  IPV6_ADDR(0xFE80, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000);
85 
86 //Solicited-node IPv6 address prefix
88  IPV6_ADDR(0xFF02, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0xFF00, 0x0000);
89 
90 
91 /**
92  * @brief IPv6 related initialization
93  * @param[in] interface Underlying network interface
94  * @return Error code
95  **/
96 
98 {
99  Ipv6Context *context;
100  NetInterface *physicalInterface;
101 
102  //Point to the physical interface
103  physicalInterface = nicGetPhysicalInterface(interface);
104 
105  //Point to the IPv6 context
106  context = &interface->ipv6Context;
107 
108  //Clear the IPv6 context
109  memset(context, 0, sizeof(Ipv6Context));
110 
111  //Initialize interface specific variables
112  context->linkMtu = physicalInterface->nicDriver->mtu;
113  context->isRouter = FALSE;
115 
116  //Multicast ICMPv6 Echo Request messages are allowed by default
117  context->enableMulticastEchoReq = TRUE;
118 
119  //Initialize the list of IPv6 addresses assigned to the interface
120  memset(context->addrList, 0, sizeof(context->addrList));
121  //Initialize the Prefix List
122  memset(context->prefixList, 0, sizeof(context->prefixList));
123  //Initialize the Default Router List
124  memset(context->routerList, 0, sizeof(context->routerList));
125  //Initialize the list of DNS servers
126  memset(context->dnsServerList, 0, sizeof(context->dnsServerList));
127  //Initialize the multicast filter table
128  memset(context->multicastFilter, 0, sizeof(context->multicastFilter));
129 
130 #if (IPV6_FRAG_SUPPORT == ENABLED)
131  //Identification field is used to identify fragments of an original IP datagram
132  context->identification = 0;
133  //Initialize the reassembly queue
134  memset(context->fragQueue, 0, sizeof(context->fragQueue));
135 #endif
136 
137  //Successful initialization
138  return NO_ERROR;
139 }
140 
141 
142 /**
143  * @brief Change the MTU of a network interface
144  * @param[in] interface Pointer to the desired network interface
145  * @param[in] mtu Maximum transmit unit
146  * @return Error code
147  **/
148 
149 error_t ipv6SetMtu(NetInterface *interface, size_t mtu)
150 {
151  error_t error;
152  NetInterface *physicalInterface;
153 
154  //Check parameters
155  if(interface == NULL)
157 
158  //Get exclusive access
160 
161  //Point to the physical interface
162  physicalInterface = nicGetPhysicalInterface(interface);
163 
164  //Make sure the specified MTU is greater than or equal to the minimum
165  //IPv6 MTU and does not exceed the maximum MTU of the interface
166  if(mtu >= IPV6_DEFAULT_MTU && mtu <= physicalInterface->nicDriver->mtu)
167  {
168  //Set the MTU to be used
169  interface->ipv6Context.linkMtu = mtu;
170  //Successful processing
171  error = NO_ERROR;
172  }
173  else
174  {
175  //The specified MTU is not valid
176  error = ERROR_OUT_OF_RANGE;
177  }
178 
179  //Release exclusive access
181 
182  //Return status code
183  return error;
184 }
185 
186 
187 /**
188  * @brief Retrieve the MTU for the specified interface
189  * @param[in] interface Pointer to the desired network interface
190  * @param[out] mtu Maximum transmit unit
191  * @return Error code
192  **/
193 
194 error_t ipv6GetMtu(NetInterface *interface, size_t *mtu)
195 {
196  //Check parameters
197  if(interface == NULL || mtu == NULL)
199 
200  //Get exclusive access
202  //Return the current MTU value
203  *mtu = interface->ipv6Context.linkMtu;
204  //Release exclusive access
206 
207  //Successful processing
208  return NO_ERROR;
209 }
210 
211 
212 /**
213  * @brief Assign link-local address
214  * @param[in] interface Pointer to the desired network interface
215  * @param[in] addr Link-local address
216  * @return Error code
217  **/
218 
220 {
221  error_t error;
222 
223  //Get exclusive access
225 
226 #if (NDP_SUPPORT == ENABLED)
227  //Check whether Duplicate Address Detection should be performed
228  if(interface->ndpContext.dupAddrDetectTransmits > 0)
229  {
230  //Use the link-local address as a tentative address
231  error = ipv6SetAddr(interface, 0, addr, IPV6_ADDR_STATE_TENTATIVE,
233  }
234  else
235 #endif
236  {
237  //The use of the link-local address is now unrestricted
238  error = ipv6SetAddr(interface, 0, addr, IPV6_ADDR_STATE_PREFERRED,
240  }
241 
242  //Release exclusive access
244 
245  //Return status code
246  return error;
247 }
248 
249 
250 /**
251  * @brief Retrieve link-local address
252  * @param[in] interface Pointer to the desired network interface
253  * @param[out] addr link-local address
254  * @return Error code
255  **/
256 
258 {
259  Ipv6AddrEntry *entry;
260 
261  //Check parameters
262  if(interface == NULL || addr == NULL)
264 
265  //Get exclusive access
267 
268  //Point to the corresponding entry
269  entry = &interface->ipv6Context.addrList[0];
270 
271  //Check whether the IPv6 address is valid
272  if(entry->state == IPV6_ADDR_STATE_PREFERRED ||
274  {
275  //Get IPv6 address
276  *addr = entry->addr;
277  }
278  else
279  {
280  //Return the unspecified address when no address has been assigned
282  }
283 
284  //Release exclusive access
286 
287  //Successful processing
288  return NO_ERROR;
289 }
290 
291 
292 /**
293  * @brief Assign global address
294  * @param[in] interface Pointer to the desired network interface
295  * @param[in] index Zero-based index
296  * @param[in] addr Global address
297  * @return Error code
298  **/
299 
301 {
302  error_t error;
303 
304  //Get exclusive access
306 
307 #if (NDP_SUPPORT == ENABLED)
308  //Check whether Duplicate Address Detection should be performed
309  if(interface->ndpContext.dupAddrDetectTransmits > 0)
310  {
311  //Use the global address as a tentative address
312  error = ipv6SetAddr(interface, index + 1, addr, IPV6_ADDR_STATE_TENTATIVE,
314  }
315  else
316 #endif
317  {
318  //The use of the global address is now unrestricted
319  error = ipv6SetAddr(interface, index + 1, addr, IPV6_ADDR_STATE_PREFERRED,
321  }
322 
323  //Release exclusive access
325 
326  //Return status code
327  return error;
328 }
329 
330 
331 /**
332  * @brief Retrieve global address
333  * @param[in] interface Pointer to the desired network interface
334  * @param[in] index Zero-based index
335  * @param[out] addr Global address
336  * @return Error code
337  **/
338 
340 {
341  Ipv6AddrEntry *entry;
342 
343  //Check parameters
344  if(interface == NULL || addr == NULL)
346 
347  //Make sure that the index is valid
348  if((index + 1) >= IPV6_ADDR_LIST_SIZE)
349  {
350  //Return the unspecified address when the index is out of range
352  //Report an error
353  return ERROR_OUT_OF_RANGE;
354  }
355 
356  //Get exclusive access
358 
359  //Point to the corresponding entry
360  entry = &interface->ipv6Context.addrList[index + 1];
361 
362  //Check whether the IPv6 address is valid
363  if(entry->state == IPV6_ADDR_STATE_PREFERRED ||
365  {
366  //Get IPv6 address
367  *addr = entry->addr;
368  }
369  else
370  {
371  //Return the unspecified address when no address has been assigned
373  }
374 
375  //Release exclusive access
377 
378  //Successful processing
379  return NO_ERROR;
380 }
381 
382 
383 /**
384  * @brief Assign anycast address
385  * @param[in] interface Pointer to the desired network interface
386  * @param[in] index Zero-based index
387  * @param[in] addr Anycast address
388  * @return Error code
389  **/
390 
392 {
393  error_t error;
394  NetInterface *physicalInterface;
395  Ipv6Addr *anycastAddrList;
396  Ipv6Addr solicitedNodeAddr;
397 
398  //Check parameters
399  if(interface == NULL || addr == NULL)
401 
402  //Make sure that the index is valid
403  if(index >= IPV6_ANYCAST_ADDR_LIST_SIZE)
404  return ERROR_OUT_OF_RANGE;
405 
406  //The IPv6 address must be a valid unicast address
408  return ERROR_INVALID_ADDRESS;
409 
410  //Initialize status code
411  error = NO_ERROR;
412 
413  //Get exclusive access
415 
416  //Point to the physical interface
417  physicalInterface = nicGetPhysicalInterface(interface);
418 
419  //Point to the list of anycast addresses assigned to the interface
420  anycastAddrList = interface->ipv6Context.anycastAddrList;
421 
422  //Check whether an anycast address is already assigned
423  if(!ipv6CompAddr(&anycastAddrList[index], &IPV6_UNSPECIFIED_ADDR))
424  {
425  //Ethernet interface?
426  if(physicalInterface->nicDriver != NULL &&
427  physicalInterface->nicDriver->type == NIC_TYPE_ETHERNET)
428  {
429  //Form the Solicited-Node address
430  ipv6ComputeSolicitedNodeAddr(&anycastAddrList[index], &solicitedNodeAddr);
431  //Leave the Solicited-Node multicast group
432  ipv6LeaveMulticastGroup(interface, &solicitedNodeAddr);
433  }
434  }
435 
436  //Assign the specified anycast address to the interface
437  anycastAddrList[index] = *addr;
438 
439  //Check whether the anycast address is valid
441  {
442  //Ethernet interface?
443  if(physicalInterface->nicDriver != NULL &&
444  physicalInterface->nicDriver->type == NIC_TYPE_ETHERNET)
445  {
446  //Form the Solicited-Node address for the link-local address
447  ipv6ComputeSolicitedNodeAddr(addr, &solicitedNodeAddr);
448  //Join the Solicited-Node multicast group for each assigned address
449  error = ipv6JoinMulticastGroup(interface, &solicitedNodeAddr);
450  }
451  }
452 
453  //Release exclusive access
455 
456  //Return status code
457  return error;
458 }
459 
460 
461 /**
462  * @brief Retrieve anycast address
463  * @param[in] interface Pointer to the desired network interface
464  * @param[in] index Zero-based index
465  * @param[out] addr Anycast address
466  * @return Error code
467  **/
468 
470 {
471  //Check parameters
472  if(interface == NULL || addr == NULL)
474 
475  //Make sure that the index is valid
476  if(index >= IPV6_ANYCAST_ADDR_LIST_SIZE)
477  {
478  //Return the unspecified address when the index is out of range
480  //Report an error
481  return ERROR_OUT_OF_RANGE;
482  }
483 
484  //Get exclusive access
486  //Return the corresponding entry
487  *addr = interface->ipv6Context.anycastAddrList[index];
488  //Release exclusive access
490 
491  //Successful processing
492  return NO_ERROR;
493 }
494 
495 
496 /**
497  * @brief Configure IPv6 prefix
498  * @param[in] interface Pointer to the desired network interface
499  * @param[in] index Zero-based index
500  * @param[in] prefix IPv6 prefix
501  * @param[in] length The number of leading bits in the prefix that are valid
502  **/
503 
505  uint_t index, const Ipv6Addr *prefix, uint_t length)
506 {
507  Ipv6PrefixEntry *entry;
508 
509  //Check parameters
510  if(interface == NULL || prefix == NULL)
512 
513  //Make sure that the index is valid
514  if(index >= IPV6_PREFIX_LIST_SIZE)
515  return ERROR_OUT_OF_RANGE;
516 
517  //Make sure the prefix length is valid
518  if(length >= 128)
520 
521  //Get exclusive access
523 
524  //Point to the corresponding entry
525  entry = &interface->ipv6Context.prefixList[index];
526 
527  //Set up IPv6 prefix
528  entry->prefix = *prefix;
529  entry->prefixLen = length;
530 
531  //Check prefix length
532  if(length > 0)
533  {
534  //Set On-link and Autonomous flags
535  entry->onLinkFlag = TRUE;
536  entry->autonomousFlag = FALSE;
537 
538  //Manually assigned prefixes have infinite lifetime
539  entry->validLifetime = INFINITE_DELAY;
541  entry->permanent = TRUE;
542  }
543  else
544  {
545  //Immediately time-out the entry
546  entry->validLifetime = 0;
547  entry->preferredLifetime = 0;
548  entry->permanent = FALSE;
549  }
550 
551  //Release exclusive access
553 
554  //Successful processing
555  return NO_ERROR;
556 }
557 
558 
559 /**
560  * @brief Retrieve IPv6 prefix
561  * @param[in] interface Pointer to the desired network interface
562  * @param[in] index Zero-based index
563  * @param[out] prefix IPv6 prefix
564  * @param[out] length The number of leading bits in the prefix that are valid
565  * @return Error code
566  **/
567 
569  uint_t index, Ipv6Addr *prefix, uint_t *length)
570 {
571  Ipv6PrefixEntry *entry;
572 
573  //Check parameters
574  if(interface == NULL || prefix == NULL)
576 
577  //Make sure that the index is valid
578  if(index >= IPV6_PREFIX_LIST_SIZE)
579  {
580  //Return the ::/0 prefix when the index is out of range
582  *length = 0;
583  //Report an error
584  return ERROR_OUT_OF_RANGE;
585  }
586 
587  //Get exclusive access
589 
590  //Point to the corresponding entry
591  entry = &interface->ipv6Context.prefixList[index];
592 
593  //Check whether the prefix is valid
594  if(entry->validLifetime > 0)
595  {
596  //Get IPv6 prefix
597  *prefix = entry->prefix;
598  *length = entry->prefixLen;
599  }
600  else
601  {
602  //Return the ::/0 prefix when the valid lifetime has expired
604  *length = 0;
605  }
606 
607  //Release exclusive access
609 
610  //Successful processing
611  return NO_ERROR;
612 }
613 
614 
615 /**
616  * @brief Configure default router
617  * @param[in] interface Pointer to the desired network interface
618  * @param[in] index Zero-based index
619  * @param[in] addr Default router address
620  * @return Error code
621  **/
622 
624 {
625  Ipv6RouterEntry *entry;
626 
627  //Check parameters
628  if(interface == NULL || addr == NULL)
630 
631  //Make sure that the index is valid
632  if(index >= IPV6_ROUTER_LIST_SIZE)
633  return ERROR_OUT_OF_RANGE;
634 
635  //The IPv6 address must be a valid unicast address
637  return ERROR_INVALID_ADDRESS;
638 
639  //Get exclusive access
641 
642  //Point to the corresponding entry
643  entry = &interface->ipv6Context.routerList[index];
644 
645  //Set up router address
646  entry->addr = *addr;
647  //Preference value
648  entry->preference = 0;
649 
650  //Valid IPv6 address?
652  {
653  //Manually assigned routers have infinite lifetime
654  entry->lifetime = INFINITE_DELAY;
655  entry->permanent = TRUE;
656  }
657  else
658  {
659  //Immediately time-out the entry
660  entry->lifetime = 0;
661  entry->permanent = FALSE;
662  }
663 
664  //Release exclusive access
666 
667  //Successful processing
668  return NO_ERROR;
669 }
670 
671 
672 /**
673  * @brief Retrieve default router
674  * @param[in] interface Pointer to the desired network interface
675  * @param[in] index Zero-based index
676  * @param[out] addr Default router address
677  * @return Error code
678  **/
679 
681 {
682  Ipv6RouterEntry *entry;
683 
684  //Check parameters
685  if(interface == NULL || addr == NULL)
687 
688  //Make sure that the index is valid
689  if(index >= IPV6_ROUTER_LIST_SIZE)
690  {
691  //Return the unspecified address when the index is out of range
693  //Report an error
694  return ERROR_OUT_OF_RANGE;
695  }
696 
697  //Get exclusive access
699 
700  //Point to the corresponding entry
701  entry = &interface->ipv6Context.routerList[index];
702 
703  //Check the lifetime of the entry
704  if(entry->lifetime > 0)
705  {
706  //Get router address
707  *addr = entry->addr;
708  }
709  else
710  {
711  //Return the unspecified address when the lifetime has expired
713  }
714 
715  //Release exclusive access
717 
718  //Successful processing
719  return NO_ERROR;
720 }
721 
722 
723 /**
724  * @brief Configure DNS server
725  * @param[in] interface Pointer to the desired network interface
726  * @param[in] index This parameter selects between the primary and secondary DNS server
727  * @param[in] addr DNS server address
728  * @return Error code
729  **/
730 
732 {
733  //Check parameters
734  if(interface == NULL || addr == NULL)
736 
737  //Make sure that the index is valid
738  if(index >= IPV6_DNS_SERVER_LIST_SIZE)
739  return ERROR_OUT_OF_RANGE;
740 
741  //The IPv6 address must be a valid unicast address
743  return ERROR_INVALID_ADDRESS;
744 
745  //Get exclusive access
747  //Set up DNS server address
748  interface->ipv6Context.dnsServerList[index] = *addr;
749  //Release exclusive access
751 
752  //Successful processing
753  return NO_ERROR;
754 }
755 
756 
757 /**
758  * @brief Retrieve DNS server
759  * @param[in] interface Pointer to the desired network interface
760  * @param[in] index This parameter selects between the primary and secondary DNS server
761  * @param[out] addr DNS server address
762  * @return Error code
763  **/
764 
766 {
767  //Check parameters
768  if(interface == NULL || addr == NULL)
770 
771  //Make sure that the index is valid
772  if(index >= IPV6_DNS_SERVER_LIST_SIZE)
773  {
774  //Return the unspecified address when the index is out of range
776  //Report an error
777  return ERROR_OUT_OF_RANGE;
778  }
779 
780  //Get exclusive access
782  //Get DNS server address
783  *addr = interface->ipv6Context.dnsServerList[index];
784  //Release exclusive access
786 
787  //Successful processing
788  return NO_ERROR;
789 }
790 
791 
792 /**
793  * @brief Callback function for link change event
794  * @param[in] interface Underlying network interface
795  **/
796 
798 {
799  uint_t i;
800  Ipv6Context *context;
801  Ipv6AddrEntry *entry;
802  NetInterface *physicalInterface;
803 
804  //Point to the physical interface
805  physicalInterface = nicGetPhysicalInterface(interface);
806 
807  //Point to the IPv6 context
808  context = &interface->ipv6Context;
809 
810  //Restore default parameters
811  context->linkMtu = physicalInterface->nicDriver->mtu;
813 
814  //Clear the list of IPv6 addresses
815  ipv6FlushAddrList(interface);
816  //Clear the Prefix List
817  ipv6FlushPrefixList(interface);
818  //Clear the Default Router List
819  ipv6FlushDefaultRouterList(interface);
820 
821 #if (IPV6_FRAG_SUPPORT == ENABLED)
822  //Flush the reassembly queue
823  ipv6FlushFragQueue(interface);
824 #endif
825 
826 #if (MLD_SUPPORT == ENABLED)
827  //Notify MLD of link state changes
828  mldLinkChangeEvent(interface);
829 #endif
830 
831 #if (NDP_SUPPORT == ENABLED)
832  //Notify NDP of link state changes
833  ndpLinkChangeEvent(interface);
834 #endif
835 
836 #if (NDP_ROUTER_ADV_SUPPORT == ENABLED)
837  //Notify the RA service of link state changes
838  ndpRouterAdvLinkChangeEvent(interface->ndpRouterAdvContext);
839 #endif
840 
841 #if (SLAAC_SUPPORT == ENABLED)
842  //Notify the SLAAC service of link state changes
843  slaacLinkChangeEvent(interface->slaacContext);
844 #endif
845 
846 #if (DHCPV6_CLIENT_SUPPORT == ENABLED)
847  //Notify the DHCPv6 client of link state changes
848  dhcpv6ClientLinkChangeEvent(interface->dhcpv6ClientContext);
849 #endif
850 
851  //Go through the list of IPv6 addresses
852  for(i = 0; i < IPV6_ADDR_LIST_SIZE; i++)
853  {
854  //Point to the current entry
855  entry = &context->addrList[i];
856 
857  //Check whether the IPv6 address has been manually assigned
858  if(entry->permanent)
859  {
860 #if (NDP_SUPPORT == ENABLED)
861  //Check whether Duplicate Address Detection should be performed
862  if(interface->ndpContext.dupAddrDetectTransmits > 0)
863  {
864  //Use the IPv6 address as a tentative address
865  ipv6SetAddr(interface, i, &entry->addr, IPV6_ADDR_STATE_TENTATIVE,
867  }
868  else
869 #endif
870  {
871  //The use of the IPv6 address is now unrestricted
872  ipv6SetAddr(interface, i, &entry->addr, IPV6_ADDR_STATE_PREFERRED,
874  }
875  }
876  }
877 }
878 
879 
880 /**
881  * @brief Incoming IPv6 packet processing
882  * @param[in] interface Underlying network interface
883  * @param[in] ipPacket Multi-part buffer that holds the incoming IPv6 packet
884  * @param[in] ipPacketOffset Offset to the first byte of the IPv6 packet
885  **/
886 
888  NetBuffer *ipPacket, size_t ipPacketOffset)
889 {
890  error_t error;
891  size_t i;
892  size_t length;
893  size_t nextHeaderOffset;
894  uint8_t *type;
895  Ipv6Header *ipHeader;
896  IpPseudoHeader pseudoHeader;
897 
898  //Total number of input datagrams received, including those received in error
899  IP_MIB_INC_COUNTER32(ipv6SystemStats.ipSystemStatsInReceives, 1);
900  IP_MIB_INC_COUNTER64(ipv6SystemStats.ipSystemStatsHCInReceives, 1);
901  IP_MIB_INC_COUNTER32(ipv6IfStatsTable[interface->index].ipIfStatsInReceives, 1);
902  IP_MIB_INC_COUNTER64(ipv6IfStatsTable[interface->index].ipIfStatsHCInReceives, 1);
903 
904  //Retrieve the length of the IPv6 packet
906 
907  //Total number of octets received in input IP datagrams
908  IP_MIB_INC_COUNTER32(ipv6SystemStats.ipSystemStatsInOctets, length);
909  IP_MIB_INC_COUNTER64(ipv6SystemStats.ipSystemStatsHCInOctets, length);
910  IP_MIB_INC_COUNTER32(ipv6IfStatsTable[interface->index].ipIfStatsInOctets, length);
911  IP_MIB_INC_COUNTER64(ipv6IfStatsTable[interface->index].ipIfStatsHCInOctets, length);
912 
913  //Ensure the packet length is greater than 40 bytes
914  if(length < sizeof(Ipv6Header))
915  {
916  //Number of input IP datagrams discarded because the datagram frame
917  //didn't carry enough data
918  IP_MIB_INC_COUNTER32(ipv6SystemStats.ipSystemStatsInTruncatedPkts, 1);
919  IP_MIB_INC_COUNTER32(ipv6IfStatsTable[interface->index].ipIfStatsInTruncatedPkts, 1);
920 
921  //Discard the received packet
922  return;
923  }
924 
925  //Point to the IPv6 header
926  ipHeader = netBufferAt(ipPacket, ipPacketOffset);
927  //Sanity check
928  if(ipHeader == NULL)
929  return;
930 
931  //Debug message
932  TRACE_INFO("IPv6 packet received (%" PRIuSIZE " bytes)...\r\n", length);
933  //Dump IPv6 header contents for debugging purpose
934  ipv6DumpHeader(ipHeader);
935 
936  //Check IP version number
937  if(ipHeader->version != IPV6_VERSION)
938  {
939  //Number of input datagrams discarded due to errors in their IP headers
940  IP_MIB_INC_COUNTER32(ipv6SystemStats.ipSystemStatsInHdrErrors, 1);
941  IP_MIB_INC_COUNTER32(ipv6IfStatsTable[interface->index].ipIfStatsInHdrErrors, 1);
942 
943  //Discard the received packet
944  return;
945  }
946 
947  //Ensure the payload length is correct before processing the packet
948  if(ntohs(ipHeader->payloadLen) > (length - sizeof(Ipv6Header)))
949  {
950  //Number of input IP datagrams discarded because the datagram frame
951  //didn't carry enough data
952  IP_MIB_INC_COUNTER32(ipv6SystemStats.ipSystemStatsInTruncatedPkts, 1);
953  IP_MIB_INC_COUNTER32(ipv6IfStatsTable[interface->index].ipIfStatsInTruncatedPkts, 1);
954 
955  //Discard the received packet
956  return;
957  }
958 
959  //Source address filtering
960  if(ipv6CheckSourceAddr(interface, &ipHeader->srcAddr))
961  {
962  //Number of input datagrams discarded due to errors in their IP headers
963  IP_MIB_INC_COUNTER32(ipv6SystemStats.ipSystemStatsInHdrErrors, 1);
964  IP_MIB_INC_COUNTER32(ipv6IfStatsTable[interface->index].ipIfStatsInHdrErrors, 1);
965 
966  //Discard the received packet
967  return;
968  }
969 
970 #if defined(IPV6_PACKET_FORWARD_HOOK)
971  IPV6_PACKET_FORWARD_HOOK(interface, ipPacket, ipPacketOffset);
972 #else
973  //Destination address filtering
974  if(ipv6CheckDestAddr(interface, &ipHeader->destAddr))
975  {
976 #if (IPV6_ROUTING_SUPPORT == ENABLED)
977  //Forward the packet according to the routing table
978  ipv6ForwardPacket(interface, ipPacket, ipPacketOffset);
979 #else
980  //Number of input datagrams discarded because the destination IP address
981  //was not a valid address
982  IP_MIB_INC_COUNTER32(ipv6SystemStats.ipSystemStatsInAddrErrors, 1);
983  IP_MIB_INC_COUNTER32(ipv6IfStatsTable[interface->index].ipIfStatsInAddrErrors, 1);
984 #endif
985  //We are done
986  return;
987  }
988 #endif
989 
990  //Update IP statistics
991  ipv6UpdateInStats(interface, &ipHeader->destAddr, length);
992 
993  //Calculate the effective length of the multi-part buffer
994  length = ipPacketOffset + sizeof(Ipv6Header) +
995  ntohs(ipHeader->payloadLen);
996 
997  //Adjust the length of the multi-part buffer if necessary
999 
1000  //Form the IPv6 pseudo header
1001  pseudoHeader.length = sizeof(Ipv6PseudoHeader);
1002  pseudoHeader.ipv6Data.srcAddr = ipHeader->srcAddr;
1003  pseudoHeader.ipv6Data.destAddr = ipHeader->destAddr;
1004  pseudoHeader.ipv6Data.reserved = 0;
1005 
1006  //Keep track of Next Header field
1007  nextHeaderOffset = ipPacketOffset + &ipHeader->nextHeader -
1008  (uint8_t *) ipHeader;
1009 
1010  //Point to the first extension header
1011  i = ipPacketOffset + sizeof(Ipv6Header);
1012 
1013  //Parse extension headers
1014  while(i < length)
1015  {
1016  //Retrieve the Next Header field of preceding header
1017  type = netBufferAt(ipPacket, nextHeaderOffset);
1018  //Sanity check
1019  if(type == NULL)
1020  return;
1021 
1022  //Update IPv6 pseudo header
1023  pseudoHeader.ipv6Data.length = htonl(length - i);
1024  pseudoHeader.ipv6Data.nextHeader = *type;
1025 
1026  //Each extension header is identified by the Next Header field of
1027  //the preceding header
1028  switch(*type)
1029  {
1030  //Hop-by-Hop Options header?
1032  //Parse current extension header
1033  error = ipv6ParseHopByHopOptHeader(interface,
1034  ipPacket, ipPacketOffset, &i, &nextHeaderOffset);
1035  //Continue processing
1036  break;
1037 
1038  //Destination Options header?
1039  case IPV6_DEST_OPT_HEADER:
1040  //Parse current extension header
1041  error = ipv6ParseDestOptHeader(interface,
1042  ipPacket, ipPacketOffset, &i, &nextHeaderOffset);
1043  //Continue processing
1044  break;
1045 
1046  //Routing header?
1047  case IPV6_ROUTING_HEADER:
1048  //Parse current extension header
1049  error = ipv6ParseRoutingHeader(interface,
1050  ipPacket, ipPacketOffset, &i, &nextHeaderOffset);
1051  //Continue processing
1052  break;
1053 
1054  //Fragment header?
1055  case IPV6_FRAGMENT_HEADER:
1056 #if (IPV6_FRAG_SUPPORT == ENABLED)
1057  //Parse current extension header
1058  ipv6ParseFragmentHeader(interface,
1059  ipPacket, ipPacketOffset, i, nextHeaderOffset);
1060 #endif
1061  //Exit immediately
1062  return;
1063 
1064  //Authentication header?
1065  case IPV6_AH_HEADER:
1066  //Parse current extension header
1067  error = ipv6ParseAuthHeader(interface,
1068  ipPacket, ipPacketOffset, &i, &nextHeaderOffset);
1069  //Continue processing
1070  break;
1071 
1072  //Encapsulating Security Payload header?
1073  case IPV6_ESP_HEADER:
1074  //Parse current extension header
1075  error = ipv6ParseEspHeader(interface,
1076  ipPacket, ipPacketOffset, &i, &nextHeaderOffset);
1077  //Continue processing
1078  break;
1079 
1080  //ICMPv6 header?
1081  case IPV6_ICMPV6_HEADER:
1082  //Process incoming ICMPv6 message
1083  icmpv6ProcessMessage(interface, &pseudoHeader.ipv6Data,
1084  ipPacket, i, ipHeader->hopLimit);
1085 
1086 #if (RAW_SOCKET_SUPPORT == ENABLED)
1087  //Packets addressed to the tentative address should be silently discarded
1088  if(!ipv6IsTentativeAddr(interface, &ipHeader->destAddr))
1089  {
1090  //Allow raw sockets to process ICMPv6 messages
1091  rawSocketProcessIpPacket(interface, &pseudoHeader, ipPacket, i);
1092  }
1093 #endif
1094  //Exit immediately
1095  return;
1096 
1097 #if (TCP_SUPPORT == ENABLED)
1098  //TCP header?
1099  case IPV6_TCP_HEADER:
1100  //Packets addressed to the tentative address should be silently discarded
1101  if(!ipv6IsTentativeAddr(interface, &ipHeader->destAddr))
1102  {
1103  //Process incoming TCP segment
1104  tcpProcessSegment(interface, &pseudoHeader, ipPacket, i);
1105  }
1106  else
1107  {
1108  //Number of input datagrams discarded because the destination IP address
1109  //was not a valid address
1110  IP_MIB_INC_COUNTER32(ipv6SystemStats.ipSystemStatsInAddrErrors, 1);
1111  IP_MIB_INC_COUNTER32(ipv6IfStatsTable[interface->index].ipIfStatsInAddrErrors, 1);
1112  }
1113 
1114  //Exit immediately
1115  return;
1116 #endif
1117 
1118 #if (UDP_SUPPORT == ENABLED)
1119  //UDP header?
1120  case IPV6_UDP_HEADER:
1121  //Packets addressed to the tentative address should be silently discarded
1122  if(!ipv6IsTentativeAddr(interface, &ipHeader->destAddr))
1123  {
1124  //Process incoming UDP datagram
1125  error = udpProcessDatagram(interface, &pseudoHeader, ipPacket, i);
1126 
1127  //Unreachable port?
1128  if(error == ERROR_PORT_UNREACHABLE)
1129  {
1130  //A destination node should originate a Destination Unreachable
1131  //message with Code 4 in response to a packet for which the
1132  //transport protocol has no listener
1134  ICMPV6_CODE_PORT_UNREACHABLE, 0, ipPacket, ipPacketOffset);
1135  }
1136  }
1137  else
1138  {
1139  //Number of input datagrams discarded because the destination IP address
1140  //was not a valid address
1141  IP_MIB_INC_COUNTER32(ipv6SystemStats.ipSystemStatsInAddrErrors, 1);
1142  IP_MIB_INC_COUNTER32(ipv6IfStatsTable[interface->index].ipIfStatsInAddrErrors, 1);
1143  }
1144 
1145  //Exit immediately
1146  return;
1147 #endif
1148 
1149  //No next header?
1150  case IPV6_NO_NEXT_HEADER:
1151  //If the payload length field of the IPv6 header indicates the presence of
1152  //octets past the end of the previous header, these octets must be ignored
1153  return;
1154 
1155  //Unrecognized header type?
1156  default:
1157  //Debug message
1158  TRACE_WARNING("Unrecognized Next Header type\r\n");
1159 
1160  //Packets addressed to the tentative address should be silently discarded
1161  if(!ipv6IsTentativeAddr(interface, &ipHeader->destAddr))
1162  {
1163  //Compute the offset of the unrecognized Next Header field within the packet
1164  size_t n = nextHeaderOffset - ipPacketOffset;
1165 
1166  //Send an ICMP Parameter Problem message
1168  ICMPV6_CODE_UNKNOWN_NEXT_HEADER, n, ipPacket, ipPacketOffset);
1169  }
1170  else
1171  {
1172  //Number of input datagrams discarded because the destination IP address
1173  //was not a valid address
1174  IP_MIB_INC_COUNTER32(ipv6SystemStats.ipSystemStatsInAddrErrors, 1);
1175  IP_MIB_INC_COUNTER32(ipv6IfStatsTable[interface->index].ipIfStatsInAddrErrors, 1);
1176  }
1177 
1178  //Discard incoming packet
1179  return;
1180  }
1181 
1182  //Any error while processing the current extension header?
1183  if(error)
1184  return;
1185  }
1186 }
1187 
1188 
1189 /**
1190  * @brief Parse Hop-by-Hop Options header
1191  * @param[in] interface Underlying network interface
1192  * @param[in] ipPacket Multi-part buffer containing the IPv6 packet
1193  * @param[in] ipPacketOffset Offset to the first byte of the IPv6 packet
1194  * @param[in,out] headerOffset Offset to the Hop-by-Hop Options header
1195  * @param[in,out] nextHeaderOffset Offset to the Next Header field
1196  * @brief Error code
1197  **/
1198 
1200  size_t ipPacketOffset, size_t *headerOffset, size_t *nextHeaderOffset)
1201 {
1202  error_t error;
1203  size_t n;
1204  size_t length;
1205  size_t headerLen;
1206  Ipv6HopByHopOptHeader *header;
1207 
1208  //Remaining bytes to process in the IPv6 packet
1209  length = netBufferGetLength(ipPacket) - *headerOffset;
1210 
1211  //Make sure the extension header is valid
1212  if(length < sizeof(Ipv6HopByHopOptHeader))
1213  return ERROR_INVALID_HEADER;
1214 
1215  //Point to the Hop-by-Hop Options header
1216  header = netBufferAt(ipPacket, *headerOffset);
1217  //Sanity check
1218  if(header == NULL)
1219  return ERROR_FAILURE;
1220 
1221  //Calculate the length of the entire header
1222  headerLen = (header->hdrExtLen * 8) + 8;
1223 
1224  //Check header length
1225  if(headerLen > length)
1226  return ERROR_INVALID_HEADER;
1227 
1228  //Debug message
1229  TRACE_DEBUG(" Hop-by-Hop Options header\r\n");
1230 
1231  //The Hop-by-Hop Options header, when present, must immediately follow
1232  //the IPv6 header
1233  if(*headerOffset != (ipPacketOffset + sizeof(Ipv6Header)))
1234  {
1235  //Compute the offset of the unrecognized Next Header field within the packet
1236  n = *nextHeaderOffset - ipPacketOffset;
1237 
1238  //Send an ICMP Parameter Problem message to the source of the packet
1240  ICMPV6_CODE_UNKNOWN_NEXT_HEADER, n, ipPacket, ipPacketOffset);
1241 
1242  //Discard incoming packet
1243  return ERROR_INVALID_HEADER;
1244  }
1245 
1246  //Compute the length of the Options field
1247  n = headerLen - sizeof(Ipv6HopByHopOptHeader);
1248 
1249  //Parse options
1250  error = ipv6ParseOptions(interface, ipPacket, ipPacketOffset,
1251  *headerOffset + sizeof(Ipv6HopByHopOptHeader), n);
1252 
1253  //Any error to report?
1254  if(error)
1255  return error;
1256 
1257  //Keep track of Next Header field
1258  *nextHeaderOffset = *headerOffset + &header->nextHeader - (uint8_t *) header;
1259  //Point to the next extension header
1260  *headerOffset += headerLen;
1261 
1262  //Successful processing
1263  return NO_ERROR;
1264 }
1265 
1266 
1267 /**
1268  * @brief Parse Destination Options header
1269  * @param[in] interface Underlying network interface
1270  * @param[in] ipPacket Multi-part buffer containing the IPv6 packet
1271  * @param[in] ipPacketOffset Offset to the first byte of the IPv6 packet
1272  * @param[in,out] headerOffset Offset to the Destination Options header
1273  * @param[in,out] nextHeaderOffset Offset to the Next Header field
1274  * @brief Error code
1275  **/
1276 
1278  size_t ipPacketOffset, size_t *headerOffset, size_t *nextHeaderOffset)
1279 {
1280  error_t error;
1281  size_t n;
1282  size_t length;
1283  size_t headerLen;
1284  Ipv6DestOptHeader *header;
1285 
1286  //Remaining bytes to process in the IPv6 packet
1287  length = netBufferGetLength(ipPacket) - *headerOffset;
1288 
1289  //Make sure the extension header is valid
1290  if(length < sizeof(Ipv6DestOptHeader))
1291  return ERROR_INVALID_HEADER;
1292 
1293  //Point to the Destination Options header
1294  header = netBufferAt(ipPacket, *headerOffset);
1295  //Sanity check
1296  if(header == NULL)
1297  return ERROR_FAILURE;
1298 
1299  //Calculate the length of the entire header
1300  headerLen = (header->hdrExtLen * 8) + 8;
1301 
1302  //Check header length
1303  if(headerLen > length)
1304  return ERROR_INVALID_HEADER;
1305 
1306  //Debug message
1307  TRACE_DEBUG(" Destination Options header\r\n");
1308 
1309  //Compute the length of the Options field
1310  n = headerLen - sizeof(Ipv6DestOptHeader);
1311 
1312  //Parse options
1313  error = ipv6ParseOptions(interface, ipPacket, ipPacketOffset,
1314  *headerOffset + sizeof(Ipv6DestOptHeader), n);
1315 
1316  //Any error to report?
1317  if(error)
1318  return error;
1319 
1320  //Keep track of Next Header field
1321  *nextHeaderOffset = *headerOffset + &header->nextHeader - (uint8_t *) header;
1322  //Point to the next extension header
1323  *headerOffset += headerLen;
1324 
1325  //Successful processing
1326  return NO_ERROR;
1327 }
1328 
1329 
1330 /**
1331  * @brief Parse Routing header
1332  * @param[in] interface Underlying network interface
1333  * @param[in] ipPacket Multi-part buffer containing the IPv6 packet
1334  * @param[in] ipPacketOffset Offset to the first byte of the IPv6 packet
1335  * @param[in,out] headerOffset Offset to the Routing header
1336  * @param[in,out] nextHeaderOffset Offset to the Next Header field
1337  * @brief Error code
1338  **/
1339 
1341  size_t ipPacketOffset, size_t *headerOffset, size_t *nextHeaderOffset)
1342 {
1343  size_t n;
1344  size_t length;
1345  size_t headerLen;
1346  Ipv6RoutingHeader *header;
1347 
1348  //Remaining bytes to process in the IPv6 packet
1349  length = netBufferGetLength(ipPacket) - *headerOffset;
1350 
1351  //Make sure the extension header is valid
1352  if(length < sizeof(Ipv6RoutingHeader))
1353  return ERROR_INVALID_HEADER;
1354 
1355  //Point to the Routing header
1356  header = netBufferAt(ipPacket, *headerOffset);
1357  //Sanity check
1358  if(header == NULL)
1359  return ERROR_FAILURE;
1360 
1361  //Calculate the length of the entire header
1362  headerLen = (header->hdrExtLen * 8) + 8;
1363 
1364  //Check header length
1365  if(headerLen > length)
1366  return ERROR_INVALID_HEADER;
1367 
1368  //Debug message
1369  TRACE_DEBUG(" Routing header\r\n");
1370 
1371  //If, while processing a received packet, a node encounters a Routing
1372  //header with an unrecognized Routing Type value, the required behavior
1373  //of the node depends on the value of the Segments Left field
1374  if(header->segmentsLeft != 0)
1375  {
1376  //Retrieve the offset of the Routing header within the packet
1377  n = *headerOffset - ipPacketOffset;
1378  //Compute the exact offset of the Routing Type field
1379  n += (uint8_t *) &header->routingType - (uint8_t *) header;
1380 
1381  //If Segments Left is non-zero, send an ICMP Parameter Problem,
1382  //Code 0, message to the packet's Source Address, pointing to
1383  //the unrecognized Routing Type
1385  ICMPV6_CODE_INVALID_HEADER_FIELD, n, ipPacket, ipPacketOffset);
1386 
1387  //The node must discard the packet
1388  return ERROR_INVALID_TYPE;
1389  }
1390 
1391  //Keep track of Next Header field
1392  *nextHeaderOffset = *headerOffset + &header->nextHeader - (uint8_t *) header;
1393  //Point to the next extension header
1394  *headerOffset += headerLen;
1395 
1396  //Successful processing
1397  return NO_ERROR;
1398 }
1399 
1400 
1401 /**
1402  * @brief Parse Authentication header
1403  * @param[in] interface Underlying network interface
1404  * @param[in] ipPacket Multi-part buffer containing the IPv6 packet
1405  * @param[in] ipPacketOffset Offset to the first byte of the IPv6 packet
1406  * @param[in,out] headerOffset Offset to the Authentication header
1407  * @param[in,out] nextHeaderOffset Offset to the Next Header field
1408  * @brief Error code
1409  **/
1410 
1412  size_t ipPacketOffset, size_t *headerOffset, size_t *nextHeaderOffset)
1413 {
1414  //Debug message
1415  TRACE_DEBUG(" Authentication header\r\n");
1416  //Authentication not supported
1417  return ERROR_FAILURE;
1418 }
1419 
1420 
1421 /**
1422  * @brief Parse Encapsulating Security Payload header
1423  * @param[in] interface Underlying network interface
1424  * @param[in] ipPacket Multi-part buffer containing the IPv6 packet
1425  * @param[in] ipPacketOffset Offset to the first byte of the IPv6 packet
1426  * @param[in,out] headerOffset Offset to the Encapsulating Security Payload header
1427  * @param[in,out] nextHeaderOffset Offset to the Next Header field
1428  * @brief Error code
1429  **/
1430 
1432  size_t ipPacketOffset, size_t *headerOffset, size_t *nextHeaderOffset)
1433 {
1434  //Debug message
1435  TRACE_DEBUG(" Encapsulating Security Payload header\r\n");
1436  //Authentication not supported
1437  return ERROR_FAILURE;
1438 }
1439 
1440 
1441 /**
1442  * @brief Parse IPv6 options
1443  * @param[in] interface Underlying network interface
1444  * @param[in] ipPacket Multi-part buffer containing the IPv6 packet
1445  * @param[in] ipPacketOffset Offset to the first byte of the IPv6 packet
1446  * @param[in] optionOffset Offset to the first byte of the Options field
1447  * @param[in] optionLen Length of the Options field
1448  * @brief Error code
1449  **/
1450 
1452  size_t ipPacketOffset, size_t optionOffset, size_t optionLen)
1453 {
1454  size_t i;
1455  size_t n;
1456  uint8_t type;
1457  uint8_t action;
1458  uint8_t *options;
1459  Ipv6Option *option;
1460  Ipv6Header *ipHeader;
1461 
1462  //Point to the first byte of the Options field
1463  options = netBufferAt(ipPacket, optionOffset);
1464 
1465  //Sanity check
1466  if(options == NULL)
1467  return ERROR_FAILURE;
1468 
1469  //Parse options
1470  for(i = 0; i < optionLen; )
1471  {
1472  //Point to the current option
1473  option = (Ipv6Option *) (options + i);
1474  //Get option type
1475  type = option->type & IPV6_OPTION_TYPE_MASK;
1476 
1477  //Pad1 option?
1479  {
1480  //Advance data pointer
1481  i++;
1482  }
1483  //PadN option?
1484  else if(type == IPV6_OPTION_TYPE_PADN)
1485  {
1486  //Malformed IPv6 packet?
1487  if((i + sizeof(Ipv6Option)) > optionLen)
1488  return ERROR_INVALID_LENGTH;
1489 
1490  //Advance data pointer
1491  i += sizeof(Ipv6Option) + option->length;
1492  }
1493  //Unrecognized option?
1494  else
1495  {
1496  //Point to the IPv6 header
1497  ipHeader = netBufferAt(ipPacket, ipPacketOffset);
1498 
1499  //Sanity check
1500  if(ipHeader == NULL)
1501  return ERROR_FAILURE;
1502 
1503  //Get the value of the highest-order two bits
1504  action = option->type & IPV6_ACTION_MASK;
1505 
1506  //The highest-order two bits specify the action that must be taken
1507  //if the processing IPv6 node does not recognize the option type
1508  if(action == IPV6_ACTION_SKIP_OPTION)
1509  {
1510  //Skip over this option and continue processing the header
1511  }
1512  else if(action == IPV6_ACTION_DISCARD_PACKET)
1513  {
1514  //Discard the packet
1515  return ERROR_INVALID_OPTION;
1516  }
1517  else if(action == IPV6_ACTION_SEND_ICMP_ERROR_ALL)
1518  {
1519  //Calculate the octet offset within the invoking packet
1520  //where the error was detected
1521  n = optionOffset + i - ipPacketOffset;
1522 
1523  //Send an ICMP Parameter Problem message to the source of the
1524  //packet, regardless of whether or not the destination address
1525  //was a multicast address
1527  ICMPV6_CODE_UNKNOWN_IPV6_OPTION, n, ipPacket, ipPacketOffset);
1528 
1529  //Discard the packet
1530  return ERROR_INVALID_OPTION;
1531  }
1532  else if(action == IPV6_ACTION_SEND_ICMP_ERROR_UNI)
1533  {
1534  //Send an ICMP Parameter Problem message to the source of the
1535  //packet, only if the destination address was not a multicast
1536  //address
1537  if(!ipv6IsMulticastAddr(&ipHeader->destAddr))
1538  {
1539  //Calculate the octet offset within the invoking packet
1540  //where the error was detected
1541  n = optionOffset + i - ipPacketOffset;
1542 
1543  //Send the ICMP Parameter Problem message
1545  ICMPV6_CODE_UNKNOWN_IPV6_OPTION, n, ipPacket, ipPacketOffset);
1546  }
1547 
1548  //Discard the packet
1549  return ERROR_INVALID_OPTION;
1550  }
1551 
1552  //Malformed IPv6 packet?
1553  if((i + sizeof(Ipv6Option)) > optionLen)
1554  return ERROR_INVALID_LENGTH;
1555 
1556  //Advance data pointer
1557  i += sizeof(Ipv6Option) + option->length;
1558  }
1559  }
1560 
1561  //Successful processing
1562  return NO_ERROR;
1563 }
1564 
1565 
1566 /**
1567  * @brief Send an IPv6 datagram
1568  * @param[in] interface Underlying network interface
1569  * @param[in] pseudoHeader IPv6 pseudo header
1570  * @param[in] buffer Multi-part buffer containing the payload
1571  * @param[in] offset Offset to the first byte of the payload
1572  * @param[in] flags Set of flags that influences the behavior of this function
1573  * @return Error code
1574  **/
1575 
1577  NetBuffer *buffer, size_t offset, uint_t flags)
1578 {
1579  error_t error;
1580  size_t length;
1581  size_t pathMtu;
1582 
1583  //Total number of IP datagrams which local IP user-protocols supplied to IP
1584  //in requests for transmission
1585  IP_MIB_INC_COUNTER32(ipv6SystemStats.ipSystemStatsOutRequests, 1);
1586  IP_MIB_INC_COUNTER64(ipv6SystemStats.ipSystemStatsHCOutRequests, 1);
1587  IP_MIB_INC_COUNTER32(ipv6IfStatsTable[interface->index].ipIfStatsOutRequests, 1);
1588  IP_MIB_INC_COUNTER64(ipv6IfStatsTable[interface->index].ipIfStatsHCOutRequests, 1);
1589 
1590  //Retrieve the length of payload
1591  length = netBufferGetLength(buffer) - offset;
1592 
1593  //Check whether the Hop Limit value is zero
1594  if((flags & IP_FLAG_HOP_LIMIT) == 0)
1595  {
1596  //Use default Hop Limit value
1597  flags |= interface->ipv6Context.curHopLimit;
1598  }
1599 
1600 #if (IPV6_PMTU_SUPPORT == ENABLED)
1601  //Retrieve the PMTU for the specified destination address
1602  pathMtu = ipv6GetPathMtu(interface, &pseudoHeader->destAddr);
1603 
1604  //The PMTU should not exceed the MTU of the first-hop link
1605  if(pathMtu > interface->ipv6Context.linkMtu)
1606  pathMtu = interface->ipv6Context.linkMtu;
1607 #else
1608  //The PMTU value for the path is assumed to be the MTU of the first-hop link
1609  pathMtu = interface->ipv6Context.linkMtu;
1610 #endif
1611 
1612  //If the payload is smaller than the PMTU then no fragmentation is needed
1613  if((length + sizeof(Ipv6Header)) <= pathMtu)
1614  {
1615  //Send data as is
1616  error = ipv6SendPacket(interface, pseudoHeader, 0, 0, buffer, offset,
1617  flags);
1618  }
1619  //If the payload length exceeds the PMTU then the device must fragment the data
1620  else
1621  {
1622 #if (IPV6_FRAG_SUPPORT == ENABLED)
1623  //Fragment IP datagram into smaller packets
1624  error = ipv6FragmentDatagram(interface, pseudoHeader, buffer, offset,
1625  pathMtu, flags);
1626 #else
1627  //Fragmentation is not supported
1628  error = ERROR_MESSAGE_TOO_LONG;
1629 #endif
1630  }
1631 
1632  //Return status code
1633  return error;
1634 }
1635 
1636 
1637 /**
1638  * @brief Send an IPv6 packet
1639  * @param[in] interface Underlying network interface
1640  * @param[in] pseudoHeader IPv6 pseudo header
1641  * @param[in] fragId Fragment identification field
1642  * @param[in] fragOffset Fragment offset field
1643  * @param[in] buffer Multi-part buffer containing the payload
1644  * @param[in] offset Offset to the first byte of the payload
1645  * @param[in] flags Set of flags that influences the behavior of this function
1646  * @return Error code
1647  **/
1648 
1650  uint32_t fragId, size_t fragOffset, NetBuffer *buffer, size_t offset,
1651  uint_t flags)
1652 {
1653  error_t error;
1654  size_t length;
1655  Ipv6Header *packet;
1656 #if (ETH_SUPPORT == ENABLED)
1657  NetInterface *physicalInterface;
1658 #endif
1659 
1660  //Calculate the length of the payload
1661  length = netBufferGetLength(buffer) - offset;
1662 
1663  //Add Fragment header?
1664  if(fragOffset != 0)
1665  {
1666  Ipv6FragmentHeader *header;
1667 
1668  //Is there enough space for the IPv6 header and the Fragment header?
1669  if(offset < (sizeof(Ipv6Header) + sizeof(Ipv6FragmentHeader)))
1670  return ERROR_INVALID_PARAMETER;
1671 
1672  //Make room for the Fragment header
1673  offset -= sizeof(Ipv6FragmentHeader);
1674  length += sizeof(Ipv6FragmentHeader);
1675 
1676  //Point to the Fragment header
1677  header = netBufferAt(buffer, offset);
1678  //Format the Fragment header
1679  header->nextHeader = pseudoHeader->nextHeader;
1680  header->reserved = 0;
1681  header->fragmentOffset = htons(fragOffset);
1682  header->identification = htonl(fragId);
1683 
1684  //Make room for the IPv6 header
1685  offset -= sizeof(Ipv6Header);
1686  length += sizeof(Ipv6Header);
1687 
1688  //Point to the IPv6 header
1689  packet = netBufferAt(buffer, offset);
1690  //Properly set the Next Header field
1691  packet->nextHeader = IPV6_FRAGMENT_HEADER;
1692  }
1693  else
1694  {
1695  //Is there enough space for the IPv6 header?
1696  if(offset < sizeof(Ipv6Header))
1697  return ERROR_INVALID_PARAMETER;
1698 
1699  //Make room for the IPv6 header
1700  offset -= sizeof(Ipv6Header);
1701  length += sizeof(Ipv6Header);
1702 
1703  //Point to the IPv6 header
1704  packet = netBufferAt(buffer, offset);
1705  //Properly set the Next Header field
1706  packet->nextHeader = pseudoHeader->nextHeader;
1707  }
1708 
1709  //Format IPv6 header
1710  packet->version = IPV6_VERSION;
1711  packet->trafficClassH = 0;
1712  packet->trafficClassL = 0;
1713  packet->flowLabelH = 0;
1714  packet->flowLabelL = 0;
1715  packet->payloadLen = htons(length - sizeof(Ipv6Header));
1716  packet->hopLimit = flags & IP_FLAG_HOP_LIMIT;
1717  packet->srcAddr = pseudoHeader->srcAddr;
1718  packet->destAddr = pseudoHeader->destAddr;
1719 
1720  //Ensure the source address is valid
1721  error = ipv6CheckSourceAddr(interface, &pseudoHeader->srcAddr);
1722  //Invalid source address?
1723  if(error)
1724  return error;
1725 
1726  //Check destination address
1727  if(ipv6CompAddr(&pseudoHeader->destAddr, &IPV6_UNSPECIFIED_ADDR))
1728  {
1729  //The unspecified address must not appear on the public Internet
1730  error = ERROR_INVALID_ADDRESS;
1731  }
1732  else if(ipv6IsLocalHostAddr(&pseudoHeader->destAddr))
1733  {
1734 #if (NET_LOOPBACK_IF_SUPPORT == ENABLED)
1735  uint_t i;
1736 
1737  //Initialize status code
1738  error = ERROR_NO_ROUTE;
1739 
1740  //Loop through network interfaces
1741  for(i = 0; i < NET_INTERFACE_COUNT; i++)
1742  {
1743  //Point to the current interface
1744  interface = &netInterface[i];
1745 
1746  //Loopback interface?
1747  if(interface->nicDriver != NULL &&
1748  interface->nicDriver->type == NIC_TYPE_LOOPBACK)
1749  {
1750  //Forward the packet to the loopback interface
1751  error = nicSendPacket(interface, buffer, offset);
1752  break;
1753  }
1754  }
1755 #else
1756  //The loopback address must not appear on the public Internet
1757  error = ERROR_NO_ROUTE;
1758 #endif
1759  }
1760  else
1761  {
1762 #if (ETH_SUPPORT == ENABLED)
1763  //Point to the physical interface
1764  physicalInterface = nicGetPhysicalInterface(interface);
1765 
1766  //Ethernet interface?
1767  if(physicalInterface->nicDriver != NULL &&
1768  physicalInterface->nicDriver->type == NIC_TYPE_ETHERNET)
1769  {
1771  MacAddr destMacAddr;
1772  NdpDestCacheEntry *entry;
1773 
1774  //When the sending node has a packet to send, it first examines
1775  //the Destination Cache
1776  entry = ndpFindDestCacheEntry(interface, &pseudoHeader->destAddr);
1777 
1778  //Check whether a matching entry exists
1779  if(entry != NULL)
1780  {
1781  //Retrieve the address of the next-hop
1782  destIpAddr = entry->nextHop;
1783  //Update timestamp
1784  entry->timestamp = osGetSystemTime();
1785  //No error to report
1786  error = NO_ERROR;
1787  }
1788  else
1789  {
1790  //Perform next-hop determination
1791  error = ndpSelectNextHop(interface, &pseudoHeader->destAddr, NULL,
1792  &destIpAddr, flags);
1793 
1794  //Check status code
1795  if(error == NO_ERROR)
1796  {
1797  //Create a new Destination Cache entry
1798  entry = ndpCreateDestCacheEntry(interface);
1799 
1800  //Destination cache entry successfully created?
1801  if(entry != NULL)
1802  {
1803  //Destination address
1804  entry->destAddr = pseudoHeader->destAddr;
1805  //Address of the next hop
1806  entry->nextHop = destIpAddr;
1807 
1808  //Initially, the PMTU value for a path is assumed to be the
1809  //MTU of the first-hop link
1810  entry->pathMtu = interface->ipv6Context.linkMtu;
1811 
1812  //Set timestamp
1813  entry->timestamp = osGetSystemTime();
1814  }
1815  }
1816  else if(error == ERROR_NO_ROUTE)
1817  {
1818  //Number of IP datagrams discarded because no route could be found
1819  //to transmit them to their destination
1820  IP_MIB_INC_COUNTER32(ipv6SystemStats.ipSystemStatsOutNoRoutes, 1);
1821  }
1822  }
1823 
1824  //Successful next-hop determination?
1825  if(error == NO_ERROR)
1826  {
1827  //Destination IPv6 address is a multicast address?
1829  {
1830  //Map IPv6 multicast address to MAC-layer multicast address
1831  error = ipv6MapMulticastAddrToMac(&destIpAddr, &destMacAddr);
1832  }
1833  else
1834  {
1835  //Resolve host address using Neighbor Discovery protocol
1836  error = ndpResolve(interface, &destIpAddr, &destMacAddr);
1837  }
1838 
1839  //Successful address resolution?
1840  if(error == NO_ERROR)
1841  {
1842  //Update IP statistics
1843  ipv6UpdateOutStats(interface, &destIpAddr, length);
1844 
1845  //Debug message
1846  TRACE_INFO("Sending IPv6 packet (%" PRIuSIZE " bytes)...\r\n", length);
1847  //Dump IP header contents for debugging purpose
1848  ipv6DumpHeader(packet);
1849 
1850  //Send Ethernet frame
1851  error = ethSendFrame(interface, &destMacAddr, buffer, offset,
1852  ETH_TYPE_IPV6);
1853  }
1854  //Address resolution is in progress?
1855  else if(error == ERROR_IN_PROGRESS)
1856  {
1857  //Debug message
1858  TRACE_INFO("Enqueuing IPv6 packet (%" PRIuSIZE " bytes)...\r\n", length);
1859  //Dump IP header contents for debugging purpose
1860  ipv6DumpHeader(packet);
1861 
1862  //Enqueue packets waiting for address resolution
1863  error = ndpEnqueuePacket(NULL, interface, &destIpAddr, buffer, offset);
1864  }
1865  //Address resolution failed?
1866  else
1867  {
1868  //Debug message
1869  TRACE_WARNING("Cannot map IPv6 address to Ethernet address!\r\n");
1870  }
1871  }
1872  }
1873  else
1874 #endif
1875 #if (PPP_SUPPORT == ENABLED)
1876  //PPP interface?
1877  if(interface->nicDriver != NULL &&
1878  interface->nicDriver->type == NIC_TYPE_PPP)
1879  {
1880  //Update IP statistics
1881  ipv6UpdateOutStats(interface, &pseudoHeader->destAddr, length);
1882 
1883  //Debug message
1884  TRACE_INFO("Sending IPv6 packet (%" PRIuSIZE " bytes)...\r\n", length);
1885  //Dump IP header contents for debugging purpose
1886  ipv6DumpHeader(packet);
1887 
1888  //Send PPP frame
1889  error = pppSendFrame(interface, buffer, offset, PPP_PROTOCOL_IPV6);
1890  }
1891  else
1892 #endif
1893  //6LoWPAN interface?
1894  if(interface->nicDriver != NULL &&
1895  interface->nicDriver->type == NIC_TYPE_6LOWPAN)
1896  {
1897  //Update IP statistics
1898  ipv6UpdateOutStats(interface, &pseudoHeader->destAddr, length);
1899 
1900  //Debug message
1901  TRACE_INFO("Sending IPv6 packet (%" PRIuSIZE " bytes)...\r\n", length);
1902  //Dump IP header contents for debugging purpose
1903  ipv6DumpHeader(packet);
1904 
1905  //Send the packet over the specified link
1906  error = nicSendPacket(interface, buffer, offset);
1907  }
1908  else
1909  //Unknown interface type?
1910  {
1911  //Report an error
1912  error = ERROR_INVALID_INTERFACE;
1913  }
1914  }
1915 
1916  //Return status code
1917  return error;
1918 }
1919 
1920 
1921 /**
1922  * @brief Join an IPv6 multicast group
1923  * @param[in] interface Underlying network interface
1924  * @param[in] groupAddr IPv6 Multicast address to join
1925  * @return Error code
1926  **/
1927 
1929 {
1930  error_t error;
1931  uint_t i;
1932  Ipv6FilterEntry *entry;
1933  Ipv6FilterEntry *firstFreeEntry;
1934 #if (ETH_SUPPORT == ENABLED)
1935  NetInterface *physicalInterface;
1936  MacAddr macAddr;
1937 #endif
1938 
1939  //The IPv6 address must be a valid multicast address
1941  return ERROR_INVALID_ADDRESS;
1942 
1943 #if (ETH_SUPPORT == ENABLED)
1944  //Point to the physical interface
1945  physicalInterface = nicGetPhysicalInterface(interface);
1946 #endif
1947 
1948  //Initialize error code
1949  error = NO_ERROR;
1950  //Keep track of the first free entry
1951  firstFreeEntry = NULL;
1952 
1953  //Go through the multicast filter table
1954  for(i = 0; i < IPV6_MULTICAST_FILTER_SIZE; i++)
1955  {
1956  //Point to the current entry
1957  entry = &interface->ipv6Context.multicastFilter[i];
1958 
1959  //Valid entry?
1960  if(entry->refCount > 0)
1961  {
1962  //Check whether the table already contains the specified IPv6 address
1963  if(ipv6CompAddr(&entry->addr, groupAddr))
1964  {
1965  //Increment the reference count
1966  entry->refCount++;
1967  //Successful processing
1968  return NO_ERROR;
1969  }
1970  }
1971  else
1972  {
1973  //Keep track of the first free entry
1974  if(firstFreeEntry == NULL)
1975  firstFreeEntry = entry;
1976  }
1977  }
1978 
1979  //Check whether the multicast filter table is full
1980  if(firstFreeEntry == NULL)
1981  {
1982  //A new entry cannot be added
1983  return ERROR_FAILURE;
1984  }
1985 
1986 #if (ETH_SUPPORT == ENABLED)
1987  //Map the IPv6 multicast address to a MAC-layer address
1989 
1990  //Add the corresponding address to the MAC filter table
1991  error = ethAcceptMacAddr(interface, &macAddr);
1992 
1993  //Check status code
1994  if(!error)
1995  {
1996  //Virtual interface?
1997  if(interface != physicalInterface)
1998  {
1999  //Configure the physical interface to accept the MAC address
2000  error = ethAcceptMacAddr(physicalInterface, &macAddr);
2001 
2002  //Any error to report?
2003  if(error)
2004  {
2005  //Clean up side effects
2006  ethDropMacAddr(interface, &macAddr);
2007  }
2008  }
2009  }
2010 #endif
2011 
2012  //MAC filter table successfully updated?
2013  if(!error)
2014  {
2015  //Now we can safely add a new entry to the table
2016  firstFreeEntry->addr = *groupAddr;
2017  //Initialize the reference count
2018  firstFreeEntry->refCount = 1;
2019 
2020 #if (MLD_SUPPORT == ENABLED)
2021  //Start listening to the multicast address
2022  mldStartListening(interface, firstFreeEntry);
2023 #endif
2024  }
2025 
2026  //Return status code
2027  return error;
2028 }
2029 
2030 
2031 /**
2032  * @brief Leave an IPv6 multicast group
2033  * @param[in] interface Underlying network interface
2034  * @param[in] groupAddr IPv6 multicast address to drop
2035  * @return Error code
2036  **/
2037 
2039 {
2040  uint_t i;
2041  Ipv6FilterEntry *entry;
2042 #if (ETH_SUPPORT == ENABLED)
2043  NetInterface *physicalInterface;
2044  MacAddr macAddr;
2045 #endif
2046 
2047  //The IPv6 address must be a valid multicast address
2049  return ERROR_INVALID_ADDRESS;
2050 
2051 #if (ETH_SUPPORT == ENABLED)
2052  //Point to the physical interface
2053  physicalInterface = nicGetPhysicalInterface(interface);
2054 #endif
2055 
2056  //Go through the multicast filter table
2057  for(i = 0; i < IPV6_MULTICAST_FILTER_SIZE; i++)
2058  {
2059  //Point to the current entry
2060  entry = &interface->ipv6Context.multicastFilter[i];
2061 
2062  //Valid entry?
2063  if(entry->refCount > 0)
2064  {
2065  //Specified IPv6 address found?
2066  if(ipv6CompAddr(&entry->addr, groupAddr))
2067  {
2068  //Decrement the reference count
2069  entry->refCount--;
2070 
2071  //Remove the entry if the reference count drops to zero
2072  if(entry->refCount == 0)
2073  {
2074 #if (MLD_SUPPORT == ENABLED)
2075  //Stop listening to the multicast address
2076  mldStopListening(interface, entry);
2077 #endif
2078 #if (ETH_SUPPORT == ENABLED)
2079  //Map the IPv6 multicast address to a MAC-layer address
2081  //Drop the corresponding address from the MAC filter table
2082  ethDropMacAddr(interface, &macAddr);
2083 
2084  //Virtual interface?
2085  if(interface != physicalInterface)
2086  {
2087  //Drop the corresponding address from the MAC filter table of
2088  //the physical interface
2089  ethDropMacAddr(physicalInterface, &macAddr);
2090  }
2091 #endif
2092  //Remove the multicast address from the list
2093  entry->addr = IPV6_UNSPECIFIED_ADDR;
2094  }
2095 
2096  //Successful processing
2097  return NO_ERROR;
2098  }
2099  }
2100  }
2101 
2102  //The specified IPv6 address does not exist
2103  return ERROR_ADDRESS_NOT_FOUND;
2104 }
2105 
2106 
2107 /**
2108  * @brief Convert a string representation of an IPv6 address to a binary IPv6 address
2109  * @param[in] str NULL-terminated string representing the IPv6 address
2110  * @param[out] ipAddr Binary representation of the IPv6 address
2111  * @return Error code
2112  **/
2113 
2115 {
2116  error_t error;
2117  int_t i = 0;
2118  int_t j = -1;
2119  int_t k = 0;
2120  int32_t value = -1;
2121 
2122  //Parse input string
2123  while(1)
2124  {
2125  //Hexadecimal digit found?
2126  if(isxdigit((uint8_t) *str))
2127  {
2128  //First digit to be decoded?
2129  if(value < 0)
2130  value = 0;
2131 
2132  //Update the value of the current 16-bit word
2133  if(isdigit((uint8_t) *str))
2134  value = (value * 16) + (*str - '0');
2135  else if(isupper((uint8_t) *str))
2136  value = (value * 16) + (*str - 'A' + 10);
2137  else
2138  value = (value * 16) + (*str - 'a' + 10);
2139 
2140  //Check resulting value
2141  if(value > 0xFFFF)
2142  {
2143  //The conversion failed
2144  error = ERROR_INVALID_SYNTAX;
2145  break;
2146  }
2147  }
2148  //"::" symbol found?
2149  else if(!strncmp(str, "::", 2))
2150  {
2151  //The "::" can only appear once in an IPv6 address
2152  if(j >= 0)
2153  {
2154  //The conversion failed
2155  error = ERROR_INVALID_SYNTAX;
2156  break;
2157  }
2158 
2159  //The "::" symbol is preceded by a number?
2160  if(value >= 0)
2161  {
2162  //Save the current 16-bit word
2163  ipAddr->w[i++] = htons(value);
2164  //Prepare to decode the next 16-bit word
2165  value = -1;
2166  }
2167 
2168  //Save the position of the "::" symbol
2169  j = i;
2170  //Point to the next character
2171  str++;
2172  }
2173  //":" symbol found?
2174  else if(*str == ':' && i < 8)
2175  {
2176  //Each ":" must be preceded by a valid number
2177  if(value < 0)
2178  {
2179  //The conversion failed
2180  error = ERROR_INVALID_SYNTAX;
2181  break;
2182  }
2183 
2184  //Save the current 16-bit word
2185  ipAddr->w[i++] = htons(value);
2186  //Prepare to decode the next 16-bit word
2187  value = -1;
2188  }
2189  //End of string detected?
2190  else if(*str == '\0' && i == 7 && j < 0)
2191  {
2192  //The NULL character must be preceded by a valid number
2193  if(value < 0)
2194  {
2195  //The conversion failed
2196  error = ERROR_INVALID_SYNTAX;
2197  }
2198  else
2199  {
2200  //Save the last 16-bit word of the IPv6 address
2201  ipAddr->w[i] = htons(value);
2202  //The conversion succeeded
2203  error = NO_ERROR;
2204  }
2205 
2206  //We are done
2207  break;
2208  }
2209  else if(*str == '\0' && i < 7 && j >= 0)
2210  {
2211  //Save the last 16-bit word of the IPv6 address
2212  if(value >= 0)
2213  ipAddr->w[i++] = htons(value);
2214 
2215  //Move the part of the address that follows the "::" symbol
2216  for(k = 0; k < (i - j); k++)
2217  ipAddr->w[7 - k] = ipAddr->w[i - 1 - k];
2218  //A sequence of zeroes can now be written in place of "::"
2219  for(k = 0; k < (8 - i); k++)
2220  ipAddr->w[j + k] = 0;
2221 
2222  //The conversion succeeded
2223  error = NO_ERROR;
2224  break;
2225  }
2226  //Invalid character...
2227  else
2228  {
2229  //The conversion failed
2230  error = ERROR_INVALID_SYNTAX;
2231  break;
2232  }
2233 
2234  //Point to the next character
2235  str++;
2236  }
2237 
2238  //Return status code
2239  return error;
2240 }
2241 
2242 
2243 /**
2244  * @brief Convert a binary IPv6 address to a string representation
2245  *
2246  * Call ipv6AddrToString() to convert an IPv6 address to a text representation. The
2247  * implementation of ipv6AddrToString() function follows RFC 5952 recommendations
2248  *
2249  * @param[in] ipAddr Binary representation of the IPv6 address
2250  * @param[out] str NULL-terminated string representing the IPv6 address
2251  * @return Pointer to the formatted string
2252  **/
2253 
2255 {
2256  static char_t buffer[40];
2257  uint_t i;
2258  uint_t j;
2259  char_t *p;
2260 
2261  //Best run of zeroes
2262  uint_t zeroRunStart = 0;
2263  uint_t zeroRunEnd = 0;
2264 
2265  //If the NULL pointer is given as parameter, then the internal buffer is used
2266  if(str == NULL)
2267  str = buffer;
2268 
2269  //Find the longest run of zeros for "::" short-handing
2270  for(i = 0; i < 8; i++)
2271  {
2272  //Compute the length of the current sequence of zeroes
2273  for(j = i; j < 8 && !ipAddr->w[j]; j++);
2274 
2275  //Keep track of the longest one
2276  if((j - i) > 1 && (j - i) > (zeroRunEnd - zeroRunStart))
2277  {
2278  //The symbol "::" should not be used to shorten just one zero field
2279  zeroRunStart = i;
2280  zeroRunEnd = j;
2281  }
2282  }
2283 
2284  //Format IPv6 address
2285  for(p = str, i = 0; i < 8; i++)
2286  {
2287  //Are we inside the best run of zeroes?
2288  if(i >= zeroRunStart && i < zeroRunEnd)
2289  {
2290  //Append a separator
2291  *(p++) = ':';
2292  //Skip the sequence of zeroes
2293  i = zeroRunEnd - 1;
2294  }
2295  else
2296  {
2297  //Add a separator between each 16-bit word
2298  if(i > 0)
2299  *(p++) = ':';
2300 
2301  //Convert the current 16-bit word to string
2302  p += sprintf(p, "%" PRIx16, ntohs(ipAddr->w[i]));
2303  }
2304  }
2305 
2306  //A trailing run of zeroes has been found?
2307  if(zeroRunEnd == 8)
2308  *(p++) = ':';
2309 
2310  //Properly terminate the string
2311  *p = '\0';
2312 
2313  //Return a pointer to the formatted string
2314  return str;
2315 }
2316 
2317 
2318 /**
2319  * @brief Dump IPv6 header for debugging purpose
2320  * @param[in] ipHeader IPv6 header
2321  **/
2322 
2323 void ipv6DumpHeader(const Ipv6Header *ipHeader)
2324 {
2325  //Dump IPv6 header contents
2326  TRACE_DEBUG(" Version = %" PRIu8 "\r\n", ipHeader->version);
2327  TRACE_DEBUG(" Traffic Class = %u\r\n", (ipHeader->trafficClassH << 4) | ipHeader->trafficClassL);
2328  TRACE_DEBUG(" Flow Label = 0x%05X\r\n", (ipHeader->flowLabelH << 16) | ntohs(ipHeader->flowLabelL));
2329  TRACE_DEBUG(" Payload Length = %" PRIu16 "\r\n", ntohs(ipHeader->payloadLen));
2330  TRACE_DEBUG(" Next Header = %" PRIu8 "\r\n", ipHeader->nextHeader);
2331  TRACE_DEBUG(" Hop Limit = %" PRIu8 "\r\n", ipHeader->hopLimit);
2332  TRACE_DEBUG(" Src Addr = %s\r\n", ipv6AddrToString(&ipHeader->srcAddr, NULL));
2333  TRACE_DEBUG(" Dest Addr = %s\r\n", ipv6AddrToString(&ipHeader->destAddr, NULL));
2334 }
2335 
2336 #endif
An address whose uniqueness on a link is being verified.
Definition: ipv6.h:172
error_t ethAcceptMacAddr(NetInterface *interface, const MacAddr *macAddr)
Add a unicast/multicast address to the MAC filter table.
Definition: ethernet.c:516
char_t * ipv6AddrToString(const Ipv6Addr *ipAddr, char_t *str)
Convert a binary IPv6 address to a string representation.
Definition: ipv6.c:2254
#define htons(value)
Definition: cpu_endian.h:392
IPv6 (Internet Protocol Version 6)
uint8_t length
Definition: dtls_misc.h:149
bool_t enableMulticastEchoReq
Support for multicast ICMPv6 Echo Request messages.
Definition: ipv6.h:467
systime_t lifetime
Router lifetime.
Definition: ipv6.h:437
Ipv6FilterEntry multicastFilter[IPV6_MULTICAST_FILTER_SIZE]
Multicast filter table.
Definition: ipv6.h:473
Ipv6PseudoHeader ipv6Data
Definition: ip.h:99
error_t ipv6SetPrefix(NetInterface *interface, uint_t index, const Ipv6Addr *prefix, uint_t length)
Configure IPv6 prefix.
Definition: ipv6.c:504
uint32_t identification
IPv6 fragment identification field.
Definition: ipv6.h:475
void ipv6ProcessPacket(NetInterface *interface, NetBuffer *ipPacket, size_t ipPacketOffset)
Incoming IPv6 packet processing.
Definition: ipv6.c:887
void ipv6FlushPrefixList(NetInterface *interface)
Flush the Prefix List.
Definition: ipv6_misc.c:675
Helper functions for NDP (Neighbor Discovery Protocol)
error_t ethSendFrame(NetInterface *interface, const MacAddr *destAddr, NetBuffer *buffer, size_t offset, uint16_t type)
Send an Ethernet frame.
Definition: ethernet.c:345
signed int int_t
Definition: compiler_port.h:44
#define IPV6_ADDR(a, b, c, d, e, f, g, h)
Definition: ipv6.h:112
void ipv6UpdateOutStats(NetInterface *interface, const Ipv6Addr *destIpAddr, size_t length)
Update IPv6 output statistics.
Definition: ipv6_misc.c:1505
error_t ipv6SetAnycastAddr(NetInterface *interface, uint_t index, const Ipv6Addr *addr)
Assign anycast address.
Definition: ipv6.c:391
void dhcpv6ClientLinkChangeEvent(Dhcpv6ClientContext *context)
Callback function for link change event.
#define IP_MIB_INC_COUNTER32(name, value)
Definition: ip_mib_module.h:46
Invalid interface.
Definition: error.h:53
uint8_t curHopLimit
Default value for the Hop Limit field.
Definition: ipv6.h:466
systime_t preferredLifetime
Preferred lifetime.
Definition: ipv6.h:424
uint8_t p
Definition: ndp.h:298
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:88
const Ipv6Addr IPV6_SOLICITED_NODE_ADDR_PREFIX
Definition: ipv6.c:87
error_t ipv6ParseDestOptHeader(NetInterface *interface, const NetBuffer *ipPacket, size_t ipPacketOffset, size_t *headerOffset, size_t *nextHeaderOffset)
Parse Destination Options header.
Definition: ipv6.c:1277
#define TRUE
Definition: os_port.h:50
NdpDestCacheEntry * ndpFindDestCacheEntry(NetInterface *interface, const Ipv6Addr *destAddr)
Search the Destination Cache for a given destination address.
Definition: ndp_cache.c:446
Ipv6Addr addr
IPv6 address.
Definition: ipv6.h:401
error_t ipv6GetDefaultRouter(NetInterface *interface, uint_t index, Ipv6Addr *addr)
Retrieve default router.
Definition: ipv6.c:680
#define Ipv6Header
Definition: ipv6.h:36
void ipv6FlushAddrList(NetInterface *interface)
Flush the list of IPv6 addresses.
Definition: ipv6_misc.c:644
error_t ipv6ParseAuthHeader(NetInterface *interface, const NetBuffer *ipPacket, size_t ipPacketOffset, size_t *headerOffset, size_t *nextHeaderOffset)
Parse Authentication header.
Definition: ipv6.c:1411
bool_t autonomousFlag
Autonomous flag.
Definition: ipv6.h:422
systime_t validLifetime
Valid lifetime.
Definition: ipv6.h:423
error_t ipv6SendDatagram(NetInterface *interface, Ipv6PseudoHeader *pseudoHeader, NetBuffer *buffer, size_t offset, uint_t flags)
Send an IPv6 datagram.
Definition: ipv6.c:1576
error_t nicSendPacket(NetInterface *interface, const NetBuffer *buffer, size_t offset)
Send a packet to the network controller.
Definition: nic.c:278
size_t ipv6GetPathMtu(NetInterface *interface, const Ipv6Addr *destAddr)
Retrieve the PMTU for the specified path.
Definition: ipv6_pmtu.c:54
#define NET_INTERFACE_COUNT
Definition: net.h:109
bool_t ipv6IsTentativeAddr(NetInterface *interface, const Ipv6Addr *ipAddr)
Check whether an IPv6 address is a tentative address.
Definition: ipv6_misc.c:1112
IPv6 routing.
#define ipv6CompAddr(ipAddr1, ipAddr2)
Definition: ipv6.h:121
error_t ipv6FragmentDatagram(NetInterface *interface, Ipv6PseudoHeader *pseudoHeader, const NetBuffer *payload, size_t payloadOffset, size_t pathMtu, uint_t flags)
Fragment IPv6 datagram into smaller packets.
Definition: ipv6_frag.c:61
Ipv6Addr prefix
IPv6 prefix information.
Definition: ipv6.h:419
Ipv6Addr destAddr
Destination IPv6 address.
Definition: ndp.h:564
__start_packed struct @185 Ipv6Option
IPv6 option.
Ipv6Addr addr
Router address.
Definition: ipv6.h:436
error_t ipv6Init(NetInterface *interface)
IPv6 related initialization.
Definition: ipv6.c:97
Ipv6Addr prefix
#define NDP_INFINITE_LIFETIME
Definition: ndp.h:202
size_t length
Definition: ip.h:92
error_t ipv6SetGlobalAddr(NetInterface *interface, uint_t index, const Ipv6Addr *addr)
Assign global address.
Definition: ipv6.c:300
#define IPV6_DEFAULT_HOP_LIMIT
Definition: ipv6.h:59
size_t pathMtu
Path MTU.
Definition: ndp.h:566
IPv6 Stateless Address Autoconfiguration.
error_t ipv6GetGlobalAddr(NetInterface *interface, uint_t index, Ipv6Addr *addr)
Retrieve global address.
Definition: ipv6.c:339
IPv6 context.
Definition: ipv6.h:462
error_t ethDropMacAddr(NetInterface *interface, const MacAddr *macAddr)
Remove a unicast/multicast address from the MAC filter table.
Definition: ethernet.c:586
void icmpv6ProcessMessage(NetInterface *interface, Ipv6PseudoHeader *pseudoHeader, const NetBuffer *buffer, size_t offset, uint8_t hopLimit)
Incoming ICMPv6 message processing.
Definition: icmpv6.c:95
Router advertisement service.
uint8_t ipPacket[]
Definition: ndp.h:430
IP pseudo header.
Definition: ip.h:90
error_t ndpSelectNextHop(NetInterface *interface, const Ipv6Addr *destAddr, const Ipv6Addr *unreachableNextHop, Ipv6Addr *nextHop, uint_t flags)
Next-hop determination.
Definition: ndp_misc.c:506
Loopback interface.
Definition: nic.h:82
#define ipv6IsMulticastAddr(ipAddr)
Definition: ipv6.h:133
error_t icmpv6SendErrorMessage(NetInterface *interface, uint8_t type, uint8_t code, uint32_t parameter, const NetBuffer *ipPacket, size_t ipPacketOffset)
Send an ICMPv6 Error message.
Definition: icmpv6.c:462
void ndpLinkChangeEvent(NetInterface *interface)
Callback function for link change event.
Definition: ndp.c:366
error_t ipv6SendPacket(NetInterface *interface, Ipv6PseudoHeader *pseudoHeader, uint32_t fragId, size_t fragOffset, NetBuffer *buffer, size_t offset, uint_t flags)
Send an IPv6 packet.
Definition: ipv6.c:1649
#define IPV6_VERSION
Definition: ipv6.h:107
error_t ipv6GetAnycastAddr(NetInterface *interface, uint_t index, Ipv6Addr *addr)
Retrieve anycast address.
Definition: ipv6.c:469
#define FALSE
Definition: os_port.h:46
NetInterface netInterface[NET_INTERFACE_COUNT]
Definition: net.c:79
ICMPv6 (Internet Control Message Protocol Version 6)
Invalid parameter.
Definition: error.h:47
#define htonl(value)
Definition: cpu_endian.h:393
error_t mldStartListening(NetInterface *interface, Ipv6FilterEntry *entry)
Start listening to the address on the interface.
Definition: mld.c:79
NetInterface * nicGetPhysicalInterface(NetInterface *interface)
Retrieve physical interface.
Definition: nic.c:84
bool_t ipv6IsLocalHostAddr(const Ipv6Addr *ipAddr)
Check whether the specified IPv6 is assigned to the host.
Definition: ipv6_misc.c:1148
char_t type
error_t
Error codes.
Definition: error.h:42
#define IP_MIB_INC_COUNTER64(name, value)
Definition: ip_mib_module.h:47
#define Ipv6PseudoHeader
Definition: ipv6.h:42
systime_t timestamp
Timestamp to manage entry lifetime.
Definition: ndp.h:567
error_t ipv6GetLinkLocalAddr(NetInterface *interface, Ipv6Addr *addr)
Retrieve link-local address.
Definition: ipv6.c:257
TCP finite state machine.
Prefix list entry.
Definition: ipv6.h:417
DHCPv6 client (Dynamic Host Configuration Protocol for IPv6)
void * netBufferAt(const NetBuffer *buffer, size_t offset)
Returns a pointer to the data at the specified position.
Definition: net_mem.c:413
void ipv6DumpHeader(const Ipv6Header *ipHeader)
Dump IPv6 header for debugging purpose.
Definition: ipv6.c:2323
Generic error code.
Definition: error.h:45
error_t ipv6ForwardPacket(NetInterface *srcInterface, NetBuffer *ipPacket, size_t ipPacketOffset)
Forward an IPv6 packet.
Definition: ipv6_routing.c:267
uint8_t preference
Preference value.
Definition: ipv6.h:438
const Ipv6Addr IPV6_LINK_LOCAL_ALL_NODES_ADDR
Definition: ipv6.c:75
bool_t permanent
Permanently assigned address.
Definition: ipv6.h:406
error_t ipv6SetLinkLocalAddr(NetInterface *interface, const Ipv6Addr *addr)
Assign link-local address.
Definition: ipv6.c:219
Ipv6Addr dnsServerList[IPV6_DNS_SERVER_LIST_SIZE]
DNS servers.
Definition: ipv6.h:472
NdpDestCacheEntry * ndpCreateDestCacheEntry(NetInterface *interface)
Create a new entry in the Destination Cache.
Definition: ndp_cache.c:395
void ipv6ParseFragmentHeader(NetInterface *interface, const NetBuffer *ipPacket, size_t ipPacketOffset, size_t fragHeaderOffset, size_t nextHeaderOffset)
Parse Fragment header and reassemble original datagram.
Definition: ipv6_frag.c:175
Ipv6AddrEntry addrList[IPV6_ADDR_LIST_SIZE]
IPv6 unicast address list.
Definition: ipv6.h:468
#define NetInterface
Definition: net.h:36
error_t ipv6CheckDestAddr(NetInterface *interface, const Ipv6Addr *ipAddr)
Destination IPv6 address filtering.
Definition: ipv6_misc.c:777
void ipv6FlushFragQueue(NetInterface *interface)
Flush IPv6 reassembly queue.
Definition: ipv6_frag.c:698
uint8_t options[]
Definition: tcp.h:320
Helper functions for IPv6.
OsMutex netMutex
Definition: net.c:75
#define IPV6_MULTICAST_FILTER_SIZE
Definition: ipv6.h:101
uint8_t fragOffset[3]
Definition: dtls_misc.h:189
const Ipv6Addr IPV6_UNSPECIFIED_ADDR
Definition: ipv6.c:67
void mldLinkChangeEvent(NetInterface *interface)
Callback function for link change event.
Definition: mld.c:198
error_t ipv6LeaveMulticastGroup(NetInterface *interface, const Ipv6Addr *groupAddr)
Leave an IPv6 multicast group.
Definition: ipv6.c:2038
void ndpRouterAdvLinkChangeEvent(NdpRouterAdvContext *context)
Callback function for link change event.
__start_packed struct @179 Ipv6Addr
IPv6 network address.
error_t ipv6JoinMulticastGroup(NetInterface *interface, const Ipv6Addr *groupAddr)
Join an IPv6 multicast group.
Definition: ipv6.c:1928
const Ipv6Addr IPV6_LOOPBACK_ADDR
Definition: ipv6.c:71
#define IPV6_DNS_SERVER_LIST_SIZE
Definition: ipv6.h:94
uint_t refCount
Reference count for the current entry.
Definition: ipv6.h:451
Internet Protocol version 6.
Definition: ppp.h:200
#define TRACE_INFO(...)
Definition: debug.h:94
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
Neighbor and destination cache management.
uint32_t mtu
Definition: icmpv6.h:173
error_t ipv6SetDnsServer(NetInterface *interface, uint_t index, const Ipv6Addr *addr)
Configure DNS server.
Definition: ipv6.c:731
error_t ipv6GetPrefix(NetInterface *interface, uint_t index, Ipv6Addr *prefix, uint_t *length)
Retrieve IPv6 prefix.
Definition: ipv6.c:568
Ipv6Addr addr
Multicast address.
Definition: ipv6.h:450
Path MTU Discovery for IPv6.
NDP (Neighbor Discovery Protocol)
TCP/IP raw sockets.
void ipv6FlushDefaultRouterList(NetInterface *interface)
Flush the Default Router List.
Definition: ipv6_misc.c:707
bool_t onLinkFlag
On-link flag.
Definition: ipv6.h:421
#define ntohs(value)
Definition: cpu_endian.h:398
PPP interface.
Definition: nic.h:80
error_t ipv6SetAddr(NetInterface *interface, uint_t index, const Ipv6Addr *addr, Ipv6AddrState state, systime_t validLifetime, systime_t preferredLifetime, bool_t permanent)
Set IPv6 address and address state.
Definition: ipv6_misc.c:95
Ipv6PrefixEntry prefixList[IPV6_PREFIX_LIST_SIZE]
Prefix list.
Definition: ipv6.h:470
IPv6 fragmentation and reassembly.
bool_t permanent
Permanently assigned prefix.
Definition: ipv6.h:425
uint8_t flags
Definition: tcp.h:314
#define TRACE_WARNING(...)
Definition: debug.h:84
#define TRACE_DEBUG(...)
Definition: debug.h:106
char char_t
Definition: compiler_port.h:43
__start_packed struct @180 Ipv6HopByHopOptHeader
IPv6 Hop-by-Hop Options header.
uint8_t prefixLen
IPv6 prefix length.
Definition: ipv6.h:420
error_t mldStopListening(NetInterface *interface, Ipv6FilterEntry *entry)
Stop listening to the address on the interface.
Definition: mld.c:128
void slaacLinkChangeEvent(SlaacContext *context)
Callback function for link change event.
Definition: slaac.c:202
#define IPV6_ANYCAST_ADDR_LIST_SIZE
Definition: ipv6.h:73
Default router list entry.
Definition: ipv6.h:434
#define IPV6_DEFAULT_MTU
Definition: ipv6.h:109
IPv6 address entry.
Definition: ipv6.h:399
error_t pppSendFrame(NetInterface *interface, NetBuffer *buffer, size_t offset, uint16_t protocol)
Send a PPP frame.
Definition: ppp.c:1006
error_t ndpEnqueuePacket(NetInterface *srcInterface, NetInterface *destInterface, const Ipv6Addr *ipAddr, NetBuffer *buffer, size_t offset)
Enqueue an IPv6 packet waiting for address resolution.
Definition: ndp.c:192
error_t ipv6ParseEspHeader(NetInterface *interface, const NetBuffer *ipPacket, size_t ipPacketOffset, size_t *headerOffset, size_t *nextHeaderOffset)
Parse Encapsulating Security Payload header.
Definition: ipv6.c:1431
IPv4 and IPv6 common routines.
uint8_t n
#define IPV6_ROUTER_LIST_SIZE
Definition: ipv6.h:87
const Ipv6Addr IPV6_LINK_LOCAL_ALL_ROUTERS_ADDR
Definition: ipv6.c:79
IP MIB module.
#define IPV6_ADDR_LIST_SIZE
Definition: ipv6.h:66
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
Ipv6FragDesc fragQueue[IPV6_MAX_FRAG_DATAGRAMS]
IPv6 fragment reassembly queue.
Definition: ipv6.h:476
Destination cache entry.
Definition: ndp.h:562
error_t ipv6ParseRoutingHeader(NetInterface *interface, const NetBuffer *ipPacket, size_t ipPacketOffset, size_t *headerOffset, size_t *nextHeaderOffset)
Parse Routing header.
Definition: ipv6.c:1340
UDP (User Datagram Protocol)
error_t netBufferSetLength(NetBuffer *buffer, size_t length)
Adjust the length of a multi-part buffer.
Definition: net_mem.c:320
error_t ipv6SetMtu(NetInterface *interface, size_t mtu)
Change the MTU of a network interface.
Definition: ipv6.c:149
Ipv4Addr groupAddr
Definition: igmp.h:127
__start_packed struct @181 Ipv6DestOptHeader
IPv6 Destination Options header.
error_t ipv6ComputeSolicitedNodeAddr(const Ipv6Addr *ipAddr, Ipv6Addr *solicitedNodeAddr)
Form a solicited-node address from an IPv6 address.
Definition: ipv6_misc.c:1377
error_t ipv6ParseHopByHopOptHeader(NetInterface *interface, const NetBuffer *ipPacket, size_t ipPacketOffset, size_t *headerOffset, size_t *nextHeaderOffset)
Parse Hop-by-Hop Options header.
Definition: ipv6.c:1199
#define Ipv6FragmentHeader
Definition: ipv6.h:39
error_t ndpResolve(NetInterface *interface, const Ipv6Addr *ipAddr, MacAddr *macAddr)
Address resolution using Neighbor Discovery protocol.
Definition: ndp.c:100
error_t rawSocketProcessIpPacket(NetInterface *interface, IpPseudoHeader *pseudoHeader, const NetBuffer *buffer, size_t offset)
Process incoming IP packet.
Definition: raw_socket.c:64
error_t ipv6StringToAddr(const char_t *str, Ipv6Addr *ipAddr)
Convert a string representation of an IPv6 address to a binary IPv6 address.
Definition: ipv6.c:2114
Ipv4Addr addr
Definition: nbns_common.h:121
error_t ipv6SetDefaultRouter(NetInterface *interface, uint_t index, const Ipv6Addr *addr)
Configure default router.
Definition: ipv6.c:623
bool_t isRouter
A flag indicating whether routing is enabled on this interface.
Definition: ipv6.h:465
An address assigned to an interface whose use is unrestricted.
Definition: ipv6.h:173
error_t ipv6GetDnsServer(NetInterface *interface, uint_t index, Ipv6Addr *addr)
Retrieve DNS server.
Definition: ipv6.c:765
bool_t permanent
Permanently assigned router.
Definition: ipv6.h:439
Ipv6AddrState state
IPv6 address state.
Definition: ipv6.h:402
#define IPV6_PREFIX_LIST_SIZE
Definition: ipv6.h:80
void ipv6LinkChangeEvent(NetInterface *interface)
Callback function for link change event.
Definition: ipv6.c:797
uint8_t value[]
Definition: dtls_misc.h:150
#define PRIuSIZE
Definition: compiler_port.h:78
6LoWPAN interface
Definition: nic.h:81
unsigned int uint_t
Definition: compiler_port.h:45
TCP/IP stack core.
An address assigned to an interface whose use is discouraged.
Definition: ipv6.h:174
error_t ipv6CheckSourceAddr(NetInterface *interface, const Ipv6Addr *ipAddr)
Source IPv6 address filtering.
Definition: ipv6_misc.c:754
void tcpProcessSegment(NetInterface *interface, IpPseudoHeader *pseudoHeader, const NetBuffer *buffer, size_t offset)
Incoming TCP segment processing.
Definition: tcp_fsm.c:73
const Ipv6Addr IPV6_LINK_LOCAL_ADDR_PREFIX
Definition: ipv6.c:83
error_t ipv6MapMulticastAddrToMac(const Ipv6Addr *ipAddr, MacAddr *macAddr)
Map an IPv6 multicast address to a MAC-layer multicast address.
Definition: ipv6_misc.c:1415
error_t udpProcessDatagram(NetInterface *interface, IpPseudoHeader *pseudoHeader, const NetBuffer *buffer, size_t offset)
Incoming UDP datagram processing.
Definition: udp.c:130
size_t linkMtu
Maximum transmission unit.
Definition: ipv6.h:464
void ipv6UpdateInStats(NetInterface *interface, const Ipv6Addr *destIpAddr, size_t length)
Update IPv6 input statistics.
Definition: ipv6_misc.c:1477
uint8_t ipAddr[4]
Definition: mib_common.h:187
error_t ipv6ParseOptions(NetInterface *interface, const NetBuffer *ipPacket, size_t ipPacketOffset, size_t optionOffset, size_t optionLen)
Parse IPv6 options.
Definition: ipv6.c:1451
Success.
Definition: error.h:44
Debugging facilities.
Ipv6Addr nextHop
IPv6 address of the next-hop neighbor.
Definition: ndp.h:565
#define INFINITE_DELAY
Definition: os_port.h:74
error_t ipv6GetMtu(NetInterface *interface, size_t *mtu)
Retrieve the MTU for the specified interface.
Definition: ipv6.c:194
__start_packed struct @108 MacAddr
MAC address.
__start_packed struct @182 Ipv6RoutingHeader
IPv6 Type 0 Routing header.
IPv6 multicast filter entry.
Definition: ipv6.h:448
MLD (Multicast Listener Discovery for IPv6)
Ipv6RouterEntry routerList[IPV6_ROUTER_LIST_SIZE]
Default router list.
Definition: ipv6.h:471
Ethernet interface.
Definition: nic.h:79
systime_t osGetSystemTime(void)
Retrieve system time.
Ipv4Addr destIpAddr
Definition: ipcp.h:78