ndp.c
Go to the documentation of this file.
1 /**
2  * @file ndp.c
3  * @brief NDP (Neighbor Discovery Protocol)
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2024 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  * The Neighbor Discovery Protocol is responsible for address autoconfiguration
30  * of nodes, discovery of the link-layer addresses of other nodes, duplicate
31  * address detection, finding available routers and address prefix discovery.
32  * Refer to RFC 4861 for more details
33  *
34  * @author Oryx Embedded SARL (www.oryx-embedded.com)
35  * @version 2.4.0
36  **/
37 
38 //Switch to the appropriate trace level
39 #define TRACE_LEVEL NDP_TRACE_LEVEL
40 
41 //Dependencies
42 #include <limits.h>
43 #include "core/net.h"
44 #include "ipv6/ipv6.h"
45 #include "ipv6/ipv6_misc.h"
46 #include "ipv6/icmpv6.h"
47 #include "ipv6/ndp.h"
48 #include "ipv6/ndp_cache.h"
49 #include "ipv6/ndp_misc.h"
50 #include "ipv6/slaac.h"
51 #include "ipv6/slaac_misc.h"
52 #include "mibs/ip_mib_module.h"
53 #include "debug.h"
54 
55 //Check TCP/IP stack configuration
56 #if (IPV6_SUPPORT == ENABLED && NDP_SUPPORT == ENABLED)
57 
58 //Tick counter to handle periodic operations
60 
61 
62 /**
63  * @brief Neighbor cache initialization
64  * @param[in] interface Underlying network interface
65  * @return Error code
66  **/
67 
69 {
70  NdpContext *context;
71 
72  //Point to the NDP context
73  context = &interface->ndpContext;
74 
75  //Clear the NDP context
76  osMemset(context, 0, sizeof(NdpContext));
77 
78  //Initialize interface specific variables
86 
87  //Enable Neighbor Discovery protocol
88  context->enable = TRUE;
89 
90  //Successful initialization
91  return NO_ERROR;
92 }
93 
94 
95 /**
96  * @brief Enable address resolution using Neighbor Discovery protocol
97  * @param[in] interface Underlying network interface
98  * @param[in] enable This flag specifies whether the host is allowed to send
99  * Neighbor solicitations and respond to incoming Neighbor solicitations.
100  * When the flag is set to FALSE, the host relies exclusively on static
101  * Neighbor cache entries to map IPv6 addresses into MAC addresses and
102  * silently drop incoming Neighbor solicitations
103  * @return Error code
104  **/
105 
107 {
108  //Check parameters
109  if(interface == NULL)
111 
112  //Get exclusive access
114 
115  //Enable or disable Neighbor Discovery protocol
116  interface->ndpContext.enable = enable;
117 
118  //If Neighbor Discovery protocol is disabled then flush dynamic entries
119  //from the Neighbor cache
120  if(!enable)
121  {
122  ndpFlushNeighborCache(interface);
123  }
124 
125  //Release exclusive access
127 
128  //Successful processing
129  return NO_ERROR;
130 }
131 
132 
133 /**
134  * @brief Add a static entry in the Neighbor cache
135  * @param[in] interface Underlying network interface
136  * @param[in] ipAddr IPv6 address
137  * @param[in] macAddr MAC address
138  * @return Error code
139  **/
140 
142  const MacAddr *macAddr)
143 {
144  error_t error;
145  NdpNeighborCacheEntry *entry;
146 
147  //Check parameters
148  if(interface == NULL || ipAddr == NULL || macAddr == NULL)
150 
151  //Get exclusive access
153 
154  //Search the Neighbor cache for the specified IPv6 address
155  entry = ndpFindNeighborCacheEntry(interface, ipAddr);
156 
157  //Check whether a matching entry exists
158  if(entry != NULL)
159  {
160  //Check the state of the Neighbor cache entry
161  if(entry->state == NDP_STATE_INCOMPLETE)
162  {
163  //Record the corresponding MAC address
164  entry->macAddr = *macAddr;
165  //Send all the packets that are pending for transmission
166  ndpSendQueuedPackets(interface, entry);
167  }
168  }
169  else
170  {
171  //Create a new entry in the Neighbor cache
172  entry = ndpCreateNeighborCacheEntry(interface);
173  }
174 
175  //Neighbor cache entry successfully created?
176  if(entry != NULL)
177  {
178  //Record the IPv6 address and the corresponding MAC address
179  entry->ipAddr = *ipAddr;
180  entry->macAddr = *macAddr;
181 
182  //Unused parameters
183  entry->isRouter = FALSE;
184  entry->timeout = 0;
185  entry->retransmitCount = 0;
186  entry->queueSize = 0;
187 
188  //Update entry state
190 
191  //Successful processing
192  error = NO_ERROR;
193  }
194  else
195  {
196  //Failed to create Neighbor cache entry
197  error = ERROR_OUT_OF_RESOURCES;
198  }
199 
200  //Release exclusive access
202 
203  //Return status code
204  return error;
205 }
206 
207 
208 /**
209  * @brief Remove a static entry from the Neighbor cache
210  * @param[in] interface Underlying network interface
211  * @param[in] ipAddr IPv6 address
212  * @return Error code
213  **/
214 
216 {
217  error_t error;
218  NdpNeighborCacheEntry *entry;
219 
220  //Check parameters
221  if(interface == NULL || ipAddr == NULL)
223 
224  //Get exclusive access
226 
227  //Search the Neighbor cache for the specified IPv6 address
228  entry = ndpFindNeighborCacheEntry(interface, ipAddr);
229 
230  //Check whether a matching entry has been found
231  if(entry != NULL && entry->state == NDP_STATE_PERMANENT)
232  {
233  //Delete Neighbor cache entry
235  //Successful processing
236  error = NO_ERROR;
237  }
238  else
239  {
240  //No matching entry in Neighbor cache
241  error = ERROR_NOT_FOUND;
242  }
243 
244  //Release exclusive access
246 
247  //Return status code
248  return error;
249 }
250 
251 
252 /**
253  * @brief Address resolution using Neighbor Discovery protocol
254  * @param[in] interface Underlying network interface
255  * @param[in] ipAddr IPv6 address
256  * @param[in] macAddr Physical address matching the specified IPv6 address
257  * @return Error code
258  **/
259 
261  MacAddr *macAddr)
262 {
263  error_t error;
264  NdpNeighborCacheEntry *entry;
265 
266  //Search the ndpCacheMutex cache for the specified IPv6 address
267  entry = ndpFindNeighborCacheEntry(interface, ipAddr);
268 
269  //Check whether a matching entry has been found
270  if(entry != NULL)
271  {
272  //Check the state of the Neighbor cache entry
273  if(entry->state == NDP_STATE_INCOMPLETE)
274  {
275  //The address resolution is already in progress
276  error = ERROR_IN_PROGRESS;
277  }
278  else if(entry->state == NDP_STATE_STALE)
279  {
280  //Copy the MAC address associated with the specified IPv6 address
281  *macAddr = entry->macAddr;
282 
283  //Delay before sending the first probe
285  //Switch to the DELAY state
287 
288  //Successful address resolution
289  error = NO_ERROR;
290  }
291  else
292  {
293  //Copy the MAC address associated with the specified IPv6 address
294  *macAddr = entry->macAddr;
295 
296  //Successful address resolution
297  error = NO_ERROR;
298  }
299  }
300  else
301  {
302  //Check whether Neighbor Discovery protocol is enabled
303  if(interface->ndpContext.enable)
304  {
305  //If no entry exists, then create a new one
306  entry = ndpCreateNeighborCacheEntry(interface);
307 
308  //Neighbor cache entry successfully created?
309  if(entry != NULL)
310  {
311  //Record the IPv6 address whose MAC address is unknown
312  entry->ipAddr = *ipAddr;
313 
314  //Reset retransmission counter
315  entry->retransmitCount = 0;
316  //No packet are pending in the transmit queue
317  entry->queueSize = 0;
318 
319  //Send a multicast Neighbor Solicitation message
320  ndpSendNeighborSol(interface, ipAddr, TRUE);
321 
322  //Set timeout value
323  entry->timeout = interface->ndpContext.retransTimer;
324  //Enter INCOMPLETE state
326 
327  //The address resolution is in progress
328  error = ERROR_IN_PROGRESS;
329  }
330  else
331  {
332  //Failed to create Neighbor cache entry
333  error = ERROR_OUT_OF_RESOURCES;
334  }
335  }
336  else
337  {
338  //Neighbor Discovery protocol is disabled
339  error = ERROR_INVALID_ADDRESS;
340  }
341  }
342 
343  //Return status code
344  return error;
345 }
346 
347 
348 /**
349  * @brief Enqueue an IPv6 packet waiting for address resolution
350  * @param[in] srcInterface Interface from which the packet has been received
351  * @param[in] destInterface Interface on which the packet should be sent
352  * @param[in] ipAddr IPv6 address of the destination host
353  * @param[in] buffer Multi-part buffer containing the packet to be enqueued
354  * @param[in] offset Offset to the first byte of the packet
355  * @param[in] ancillary Additional options passed to the stack along with
356  * the packet
357  * @return Error code
358  **/
359 
361  NetInterface *destInterface, const Ipv6Addr *ipAddr, NetBuffer *buffer,
362  size_t offset, NetTxAncillary *ancillary)
363 {
364  error_t error;
365  uint_t i;
366  size_t length;
367  NdpNeighborCacheEntry *entry;
368 
369  //Retrieve the length of the multi-part buffer
370  length = netBufferGetLength(buffer);
371 
372  //Search the Neighbor cache for the specified IPv6 address
373  entry = ndpFindNeighborCacheEntry(destInterface, ipAddr);
374 
375  //Check whether a matching entry exists
376  if(entry != NULL)
377  {
378  //Check the state of the Neighbor cache entry
379  if(entry->state == NDP_STATE_INCOMPLETE)
380  {
381  //Check whether the packet queue is full
382  if(entry->queueSize >= NDP_MAX_PENDING_PACKETS)
383  {
384  //When the queue overflows, the new arrival should replace the
385  //oldest entry
386  netBufferFree(entry->queue[0].buffer);
387 
388  //Make room for the new packet
389  for(i = 1; i < NDP_MAX_PENDING_PACKETS; i++)
390  {
391  entry->queue[i - 1] = entry->queue[i];
392  }
393 
394  //Adjust the number of pending packets
395  entry->queueSize--;
396  }
397 
398  //Index of the entry to be filled in
399  i = entry->queueSize;
400  //Allocate a memory buffer to store the packet
401  entry->queue[i].buffer = netBufferAlloc(length);
402 
403  //Successful memory allocation?
404  if(entry->queue[i].buffer != NULL)
405  {
406  //If the IPv6 packet has been forwarded, record the network
407  //interface from which the packet has been received
408  entry->queue[i].srcInterface = srcInterface;
409 
410  //Copy the contents of the IPv6 packet
411  netBufferCopy(entry->queue[i].buffer, 0, buffer, 0, length);
412  //Offset to the first byte of the IPv6 header
413  entry->queue[i].offset = offset;
414  //Additional options passed to the stack along with the packet
415  entry->queue[i].ancillary = *ancillary;
416 
417  //Increment the number of queued packets
418  entry->queueSize++;
419  //The packet was successfully enqueued
420  error = NO_ERROR;
421  }
422  else
423  {
424  //Failed to allocate memory
425  error = ERROR_OUT_OF_MEMORY;
426  }
427  }
428  else
429  {
430  //The address is already resolved
431  error = ERROR_UNEXPECTED_STATE;
432  }
433  }
434  else
435  {
436  //No matching entry in Neighbor Cache
437  error = ERROR_NOT_FOUND;
438  }
439 
440  //Return status code
441  return error;
442 }
443 
444 
445 /**
446  * @brief NDP timer handler
447  * @param[in] interface Underlying network interface
448  **/
449 
450 void ndpTick(NetInterface *interface)
451 {
452  systime_t time;
453  NdpContext *context;
454 
455  //Point to the NDP context
456  context = &interface->ndpContext;
457 
458  //Get current time
459  time = osGetSystemTime();
460 
461  //When an interface becomes enabled, a host may send some Router
462  //Solicitation messages to obtain Router Advertisements quickly
463  if(interface->linkState && !interface->ipv6Context.isRouter)
464  {
465  //Make sure that a valid link-local address has been assigned to the
466  //interface
468  {
469  //The host should transmit up to MAX_RTR_SOLICITATIONS Router
470  //Solicitation messages
471  if(context->rtrSolicitationCount == 0)
472  {
473  //Set time stamp
474  context->timestamp = time;
475 
476  //Check whether the host has already performed Duplicate Address
477  //Detection for the link-local address
478  if(context->dupAddrDetectTransmits > 0)
479  {
480  //If a host has already performed a random delay since the
481  //interface became enabled, there is no need to delay again
482  //before sending the first Router Solicitation message
483  context->timeout = 0;
484  }
485  else
486  {
487  //Before a host sends an initial solicitation, it should delay the
488  //transmission for a random amount of time in order to alleviate
489  //congestion when many hosts start up on a link at the same time
491  context->maxRtrSolicitationDelay);
492  }
493 
494  //Prepare to send the first Router Solicitation message
495  context->rtrSolicitationCount = 1;
496  }
497  else if(context->rtrSolicitationCount <= context->maxRtrSolicitations)
498  {
499  //Once the host sends a Router Solicitation, and receives a valid
500  //Router Advertisement with a non-zero Router Lifetime, the host must
501  //desist from sending additional solicitations on that interface
502  if(!context->rtrAdvReceived)
503  {
504  //Check current time
505  if(timeCompare(time, context->timestamp + context->timeout) >= 0)
506  {
507  //Send Router Solicitation message
508  ndpSendRouterSol(interface);
509 
510  //Save the time at which the message was sent
511  context->timestamp = time;
512  //Set timeout value
513  context->timeout = context->rtrSolicitationInterval;
514  //Increment retransmission counter
515  context->rtrSolicitationCount++;
516  }
517  }
518  }
519  }
520  }
521 
522  //Periodically update the Neighbor Cache
523  ndpUpdateNeighborCache(interface);
524 
525  //Manage the lifetime of IPv6 addresses
526  ndpUpdateAddrList(interface);
527 
528  //Periodically update the Prefix List
529  ndpUpdatePrefixList(interface);
530 
531  //Periodically update the Default Router List
532  ndpUpdateDefaultRouterList(interface);
533 }
534 
535 
536 /**
537  * @brief Callback function for link change event
538  * @param[in] interface Underlying network interface
539  **/
540 
542 {
543  NdpContext *context;
544 
545  //Point to the NDP context
546  context = &interface->ndpContext;
547 
548  //Restore default parameters
550  context->retransTimer = NDP_RETRANS_TIMER;
556 
557  //Reset retransmission counter for RS messages
558  context->rtrSolicitationCount = 0;
559  //Valid RA message not yet received
560  context->rtrAdvReceived = FALSE;
561 
562  //Flush the Neighbor Cache
563  ndpFlushNeighborCache(interface);
564  //Flush the Destination Cache
565  ndpFlushDestCache(interface);
566 }
567 
568 
569 /**
570  * @brief Router Advertisement message processing
571  * @param[in] interface Underlying network interface
572  * @param[in] pseudoHeader IPv6 pseudo header
573  * @param[in] buffer Multi-part buffer containing the Router Advertisement message
574  * @param[in] offset Offset to the first byte of the message
575  * @param[in] hopLimit Hop Limit field from IPv6 header
576  **/
577 
579  const Ipv6PseudoHeader *pseudoHeader, const NetBuffer *buffer,
580  size_t offset, uint8_t hopLimit)
581 {
582  error_t error;
583  uint32_t n;
584  size_t length;
586  NdpMtuOption *mtuOption;
587  NdpPrefixInfoOption *prefixInfoOption;
588 #if (ETH_SUPPORT == ENABLED)
589  NdpLinkLayerAddrOption *linkLayerAddrOption;
590  NdpNeighborCacheEntry *entry;
591 #endif
592 
593  //Retrieve the length of the message
594  length = netBufferGetLength(buffer) - offset;
595 
596  //Check the length of the Router Advertisement message
597  if(length < sizeof(NdpRouterAdvMessage))
598  return;
599 
600  //Point to the beginning of the message
601  message = netBufferAt(buffer, offset);
602  //Sanity check
603  if(message == NULL)
604  return;
605 
606  //Debug message
607  TRACE_INFO("Router Advertisement message received (%" PRIuSIZE " bytes)...\r\n", length);
608  //Dump message contents for debugging purpose
610 
611  //Routers must use their link-local address as the source for the
612  //Router Advertisement so that hosts can uniquely identify routers
613  if(!ipv6IsLinkLocalUnicastAddr(&pseudoHeader->srcAddr))
614  return;
615 
616  //The IPv6 Hop Limit field must have a value of 255 to ensure that the
617  //packet has not been forwarded by a router
618  if(hopLimit != NDP_HOP_LIMIT)
619  return;
620 
621  //ICMPv6 Code must be 0. An advertisement that passes the validity
622  //checks is called a valid advertisement
623  if(message->code)
624  return;
625 
626  //Calculate the length of the Options field
627  length -= sizeof(NdpRouterAdvMessage);
628 
629  //Parse Options field
630  error = ndpCheckOptions(message->options, length);
631  //All included options must have a length that is greater than zero
632  if(error)
633  return;
634 
635  //Check the Router Lifetime value
636  if(ntohs(message->routerLifetime) != 0)
637  {
638  //Add a new entry in the Default Router List
639  ipv6AddDefaultRouter(interface, &pseudoHeader->srcAddr,
640  ntohs(message->routerLifetime), message->prf);
641 
642  //The host should send at least one solicitation in the case where
643  //an advertisement is received prior to having sent a solicitation
644  if(interface->ndpContext.rtrSolicitationCount > 1)
645  {
646  //Once the host sends a Router Solicitation, and receives a valid
647  //Router Advertisement with a non-zero Router Lifetime, the host must
648  //desist from sending additional solicitations on that interface
649  interface->ndpContext.rtrAdvReceived = TRUE;
650  }
651  }
652  else
653  {
654  //Immediately time-out the entry
655  ipv6RemoveDefaultRouter(interface, &pseudoHeader->srcAddr);
656  }
657 
658  //6LoWPAN interface?
659  if(interface->nicDriver != NULL &&
660  interface->nicDriver->type == NIC_TYPE_6LOWPAN)
661  {
662  //In all cases, the Router Solicitation retransmissions are terminated
663  //when a Router Advertisement is received (refer to RFC 6675 5.3)
664  interface->ndpContext.rtrAdvReceived = TRUE;
665  }
666 
667  //A Router Advertisement field (Cur Hop Limit, Reachable Time, and
668  //Retrans Timer) may contain a value denoting that it is unspecified.
669  //In such cases, the parameter should be ignored and the host should
670  //continue using whatever value it is already using
671  if(message->curHopLimit != 0)
672  {
673  //Get the default value that should be placed in the Hop Count
674  //field of the IP header for outgoing IP packets
675  interface->ipv6Context.curHopLimit = message->curHopLimit;
676  }
677 
678  //A value of zero means unspecified
679  if(message->reachableTime != 0)
680  {
681  //The Reachable Time field holds the time, in milliseconds, that
682  //a node assumes a neighbor is reachable after having received a
683  //reachability confirmation
684  interface->ndpContext.reachableTime = ntohl(message->reachableTime);
685  }
686 
687  //A value of zero means unspecified
688  if(message->retransTimer != 0)
689  {
690  //The Retrans Timer field holds the time, in milliseconds, between
691  //retransmitted Neighbor Solicitation messages
692  interface->ndpContext.retransTimer = ntohl(message->retransTimer);
693  }
694 
695 #if (ETH_SUPPORT == ENABLED)
696  //Search for the Source Link-Layer Address option
697  linkLayerAddrOption = ndpGetOption(message->options, length,
699 
700  //Source Link-Layer Address option found?
701  if(linkLayerAddrOption != NULL && linkLayerAddrOption->length == 1)
702  {
703  //Debug message
704  TRACE_DEBUG(" Source Link-Layer Address = %s\r\n",
705  macAddrToString(&linkLayerAddrOption->linkLayerAddr, NULL));
706  }
707  else
708  {
709  //No valid Source Link-Layer Address option...
710  linkLayerAddrOption = NULL;
711  }
712 
713  //Search the Neighbor cache for the router
714  entry = ndpFindNeighborCacheEntry(interface, &pseudoHeader->srcAddr);
715 
716  //No matching entry has been found?
717  if(entry == NULL)
718  {
719  //If the advertisement contains a Source Link-Layer Address option,
720  //the link-layer address should be recorded in the Neighbor cache
721  if(linkLayerAddrOption)
722  {
723  //Check whether Neighbor Discovery protocol is enabled
724  if(interface->ndpContext.enable)
725  {
726  //Create an entry for the router
727  entry = ndpCreateNeighborCacheEntry(interface);
728 
729  //Neighbor cache entry successfully created?
730  if(entry != NULL)
731  {
732  //Record the IPv6 address and the corresponding MAC address
733  entry->ipAddr = pseudoHeader->srcAddr;
734  entry->macAddr = linkLayerAddrOption->linkLayerAddr;
735 
736  //The IsRouter flag must be set to TRUE
737  entry->isRouter = TRUE;
738 
739  //The reachability state must be set to STALE
741  }
742  }
743  }
744  }
745  else
746  {
747  //The sender of a Router Advertisement is implicitly assumed to be a
748  //router
749  entry->isRouter = TRUE;
750 
751  //Check if the advertisement contains a Source Link-Layer Address option
752  if(linkLayerAddrOption)
753  {
754  //Check the state of the Neighbor cache entry
755  if(entry->state == NDP_STATE_PERMANENT)
756  {
757  //Static Neighbor cache entries are never updated
758  }
759  else if(entry->state == NDP_STATE_INCOMPLETE)
760  {
761  //Record link-layer address
762  entry->macAddr = linkLayerAddrOption->linkLayerAddr;
763 
764  //Send all the packets that are pending for transmission
765  n = ndpSendQueuedPackets(interface, entry);
766 
767  //Check whether any packets have been sent
768  if(n > 0)
769  {
770  //Start delay timer
772  //Switch to the DELAY state
774  }
775  else
776  {
777  //Enter the STALE state
779  }
780  }
781  else
782  {
783  //Different link-layer address than cached?
784  if(!macCompAddr(&entry->macAddr, &linkLayerAddrOption->linkLayerAddr))
785  {
786  //Update link-layer address
787  entry->macAddr = linkLayerAddrOption->linkLayerAddr;
788 
789  //The reachability state must be set to STALE
791  }
792  }
793  }
794  }
795 #endif
796 
797  //Search for the MTU option
798  mtuOption = ndpGetOption(message->options, length, NDP_OPT_MTU);
799 
800  //MTU option found?
801  if(mtuOption != NULL && mtuOption->length == 1)
802  {
803  NetInterface *physicalInterface;
804 
805  //Point to the physical interface
806  physicalInterface = nicGetPhysicalInterface(interface);
807 
808  //This option specifies the recommended MTU for the link
809  n = ntohl(mtuOption->mtu);
810 
811  //The host should copy the option's value so long as the value is greater
812  //than or equal to the minimum IPv6 MTU and does not exceed the maximum
813  //MTU of the interface
814  if(n >= IPV6_DEFAULT_MTU && n <= physicalInterface->nicDriver->mtu)
815  {
816  //Save the MTU value
817  interface->ipv6Context.linkMtu = n;
818  }
819  }
820 
821  //Point to the beginning of the Options field
822  n = 0;
823 
824  //Parse Options field
825  while(1)
826  {
827  //Search the Options field for any Prefix Information options
828  prefixInfoOption = ndpGetOption(message->options + n, length - n,
830 
831  //No more option of the specified type?
832  if(prefixInfoOption == NULL)
833  break;
834 
835  //Hosts use the advertised on-link prefixes to build and maintain a list
836  //that is used in deciding when a packet's destination is on-link or
837  //beyond a router
838  ndpParsePrefixInfoOption(interface, prefixInfoOption);
839 
840  //Retrieve the offset to the current position
841  n = (uint8_t *) prefixInfoOption - message->options;
842  //Jump to the next option
843  n += prefixInfoOption->length * 8;
844  }
845 
846 #if (SLAAC_SUPPORT == ENABLED)
847  //Stateless Address Autoconfiguration is currently used?
848  if(interface->slaacContext != NULL)
849  {
850  //Process the valid advertisement
851  slaacParseRouterAdv(interface->slaacContext, message,
852  length + sizeof(NdpRouterAdvMessage));
853  }
854 #endif
855 }
856 
857 
858 /**
859  * @brief Neighbor Solicitation message processing
860  * @param[in] interface Underlying network interface
861  * @param[in] pseudoHeader IPv6 pseudo header
862  * @param[in] buffer Multi-part buffer containing the Neighbor Solicitation message
863  * @param[in] offset Offset to the first byte of the message
864  * @param[in] hopLimit Hop Limit field from IPv6 header
865  **/
866 
868  const Ipv6PseudoHeader *pseudoHeader, const NetBuffer *buffer,
869  size_t offset, uint8_t hopLimit)
870 {
871 #if (ETH_SUPPORT == ENABLED)
872  error_t error;
873  uint_t i;
874  uint_t n;
875  size_t length;
876  bool_t validTarget;
878  NdpLinkLayerAddrOption *option;
879  NdpNeighborCacheEntry *neighborCacheEntry;
880  Ipv6AddrEntry *addrEntry;
881 
882  //Retrieve the length of the message
883  length = netBufferGetLength(buffer) - offset;
884 
885  //Check the length of the Neighbor Solicitation message
886  if(length < sizeof(NdpNeighborSolMessage))
887  return;
888 
889  //Point to the beginning of the message
890  message = netBufferAt(buffer, offset);
891  //Sanity check
892  if(message == NULL)
893  return;
894 
895  //Debug message
896  TRACE_INFO("Neighbor Solicitation message received (%" PRIuSIZE " bytes)...\r\n", length);
897  //Dump message contents for debugging purpose
899 
900  //The IPv6 Hop Limit field must have a value of 255 to ensure that the
901  //packet has not been forwarded by a router
902  if(hopLimit != NDP_HOP_LIMIT)
903  return;
904 
905  //ICMPv6 Code must be 0
906  if(message->code)
907  return;
908 
909  //If the IP source address is the unspecified address, the IP destination
910  //address must be a solicited-node multicast address
911  if(ipv6CompAddr(&pseudoHeader->srcAddr, &IPV6_UNSPECIFIED_ADDR) &&
912  !ipv6IsSolicitedNodeAddr(&pseudoHeader->destAddr))
913  {
914  //Debug message
915  TRACE_WARNING("Destination address must be a solicited-node address!\r\n");
916  //Exit immediately
917  return;
918  }
919 
920  //Calculate the length of the Options field
921  length -= sizeof(NdpNeighborSolMessage);
922 
923  //Parse Options field
924  error = ndpCheckOptions(message->options, length);
925  //All included options must have a length that is greater than zero
926  if(error)
927  return;
928 
929  //Search for the Source Link-Layer Address option
930  option = ndpGetOption(message->options, length,
932 
933  //The target address must a valid unicast or anycast address assigned to
934  //the interface or a tentative address on which DAD is being performed
935  validTarget = FALSE;
936 
937  //Loop through the IPv6 addresses assigned to the interface
938  for(i = 0; i < IPV6_ADDR_LIST_SIZE; i++)
939  {
940  //Point to the current entry
941  addrEntry = &interface->ipv6Context.addrList[i];
942 
943  //Compare target address
944  if(ipv6CompAddr(&addrEntry->addr, &message->targetAddr))
945  {
946  //Check address state
947  if(addrEntry->state == IPV6_ADDR_STATE_TENTATIVE)
948  {
949  //If the source address of the Neighbor Solicitation is the
950  //unspecified address, the solicitation is from a node performing
951  //Duplicate Address Detection
952  if(ipv6CompAddr(&pseudoHeader->srcAddr, &IPV6_UNSPECIFIED_ADDR))
953  {
954  //The source link-layer address must not be included when the
955  //source IP address is the unspecified address
956  if(option == NULL)
957  {
958  //Debug message
959  TRACE_WARNING("The tentative address %s is a duplicate!\r\n",
960  ipv6AddrToString(&addrEntry->addr, NULL));
961 
962  //The tentative address is a duplicate and should not be used
963  addrEntry->duplicate = TRUE;
964  }
965  }
966 
967  //In all cases, a node must not respond to a Neighbor Solicitation
968  //for a tentative address
969  return;
970  }
971  else if(addrEntry->state != IPV6_ADDR_STATE_INVALID)
972  {
973  //The target address is a valid address assigned to the interface
974  validTarget = TRUE;
975  //We are done
976  break;
977  }
978  }
979  }
980 
981  //Invalid target address?
982  if(!validTarget)
983  {
984  //The Neighbor Solicitation must be discarded if the target address
985  //is not a valid anycast address assigned to the interface
986  if(!ipv6IsAnycastAddr(interface, &message->targetAddr))
987  {
988  //Debug message
989  TRACE_WARNING("Wrong target address!\r\n");
990  //Exit immediately
991  return;
992  }
993  }
994 
995  //Source Link-Layer Address option found?
996  if(option != NULL && option->length == 1)
997  {
998  //Debug message
999  TRACE_DEBUG(" Source Link-Layer Address = %s\r\n",
1000  macAddrToString(&option->linkLayerAddr, NULL));
1001 
1002  //The Source Link-Layer Address option must not be included when the
1003  //source IP address is the unspecified address
1004  if(ipv6CompAddr(&pseudoHeader->srcAddr, &IPV6_UNSPECIFIED_ADDR))
1005  return;
1006 
1007  //Search the Neighbor Cache for the source address of the solicitation
1008  neighborCacheEntry = ndpFindNeighborCacheEntry(interface,
1009  &pseudoHeader->srcAddr);
1010 
1011  //No matching entry has been found?
1012  if(neighborCacheEntry == NULL)
1013  {
1014  //Check whether Neighbor Discovery protocol is enabled
1015  if(interface->ndpContext.enable)
1016  {
1017  //Create an entry
1018  neighborCacheEntry = ndpCreateNeighborCacheEntry(interface);
1019 
1020  //Neighbor cache entry successfully created?
1021  if(neighborCacheEntry != NULL)
1022  {
1023  //Record the IPv6 and the corresponding MAC address
1024  neighborCacheEntry->ipAddr = pseudoHeader->srcAddr;
1025  neighborCacheEntry->macAddr = option->linkLayerAddr;
1026 
1027  //Enter the STALE state
1028  ndpChangeState(neighborCacheEntry, NDP_STATE_STALE);
1029  }
1030  }
1031  }
1032  else
1033  {
1034  //Check the state of the Neighbor cache entry
1035  if(neighborCacheEntry->state == NDP_STATE_PERMANENT)
1036  {
1037  //Static Neighbor cache entries are never updated
1038  }
1039  else if(neighborCacheEntry->state == NDP_STATE_INCOMPLETE)
1040  {
1041  //Record link-layer address
1042  neighborCacheEntry->macAddr = option->linkLayerAddr;
1043 
1044  //Send all the packets that are pending for transmission
1045  n = ndpSendQueuedPackets(interface, neighborCacheEntry);
1046 
1047  //Check whether any packets have been sent
1048  if(n > 0)
1049  {
1050  //Start delay timer
1051  neighborCacheEntry->timeout = NDP_DELAY_FIRST_PROBE_TIME;
1052  //Switch to the DELAY state
1053  ndpChangeState(neighborCacheEntry, NDP_STATE_DELAY);
1054  }
1055  else
1056  {
1057  //Enter the STALE state
1058  ndpChangeState(neighborCacheEntry, NDP_STATE_STALE);
1059  }
1060  }
1061  else
1062  {
1063  //Different link-layer address than cached?
1064  if(!macCompAddr(&neighborCacheEntry->macAddr, &option->linkLayerAddr))
1065  {
1066  //Update link-layer address
1067  neighborCacheEntry->macAddr = option->linkLayerAddr;
1068 
1069  //Enter the STALE state
1070  ndpChangeState(neighborCacheEntry, NDP_STATE_STALE);
1071  }
1072  }
1073  }
1074  }
1075  //Source Link-Layer Address option not found?
1076  else
1077  {
1078  //The Source Link-Layer Address option must not be included when the
1079  //source IP address is the unspecified address. Otherwise, this option
1080  //must be included in multicast solicitations
1081  if(!ipv6CompAddr(&pseudoHeader->srcAddr, &IPV6_UNSPECIFIED_ADDR) &&
1082  ipv6IsMulticastAddr(&pseudoHeader->destAddr))
1083  {
1084  //Debug message
1085  TRACE_WARNING("The Source Link-Layer Address must be included!\r\n");
1086  //Exit immediately
1087  return;
1088  }
1089  }
1090 
1091  //Check whether a Neighbor Advertisement should be sent in response
1092  if(interface->ndpContext.enable)
1093  {
1094  //After any updates to the Neighbor cache, the node sends a Neighbor
1095  //Advertisement response as described in RFC 4861 7.2.4
1096  ndpSendNeighborAdv(interface, &message->targetAddr,
1097  &pseudoHeader->srcAddr);
1098  }
1099 #endif
1100 }
1101 
1102 
1103 /**
1104  * @brief Neighbor Advertisement message processing
1105  * @param[in] interface Underlying network interface
1106  * @param[in] pseudoHeader IPv6 pseudo header
1107  * @param[in] buffer Multi-part buffer containing the Neighbor Advertisement message
1108  * @param[in] offset Offset to the first byte of the message
1109  * @param[in] hopLimit Hop Limit field from IPv6 header
1110  **/
1111 
1113  const Ipv6PseudoHeader *pseudoHeader, const NetBuffer *buffer,
1114  size_t offset, uint8_t hopLimit)
1115 {
1116 #if (ETH_SUPPORT == ENABLED)
1117  error_t error;
1118  uint_t i;
1119  uint_t n;
1120  size_t length;
1121  bool_t differentLinkLayerAddr;
1123  NdpLinkLayerAddrOption *option;
1124  NdpNeighborCacheEntry *neighborCacheEntry;
1125  Ipv6AddrEntry *addrEntry;
1126 
1127  //Retrieve the length of the message
1128  length = netBufferGetLength(buffer) - offset;
1129 
1130  //Check the length of the Neighbor Advertisement message
1131  if(length < sizeof(NdpNeighborAdvMessage))
1132  return;
1133 
1134  //Point to the beginning of the message
1135  message = netBufferAt(buffer, offset);
1136  //Sanity check
1137  if(message == NULL)
1138  return;
1139 
1140  //Debug message
1141  TRACE_INFO("Neighbor Advertisement message received (%" PRIuSIZE " bytes)...\r\n", length);
1142  //Dump message contents for debugging purpose
1144 
1145  //The IPv6 Hop Limit field must have a value of 255 to ensure that the
1146  //packet has not been forwarded by a router
1147  if(hopLimit != NDP_HOP_LIMIT)
1148  return;
1149 
1150  //ICMPv6 Code must be 0
1151  if(message->code)
1152  return;
1153 
1154  //The target address must not be a multicast address
1155  if(ipv6IsMulticastAddr(&message->targetAddr))
1156  {
1157  //Debug message
1158  TRACE_WARNING("Target address must not be a multicast address!\r\n");
1159  //Exit immediately
1160  return;
1161  }
1162 
1163  //If the destination address is a multicast address
1164  //then the Solicited flag must be zero
1165  if(ipv6IsMulticastAddr(&pseudoHeader->destAddr) && message->s)
1166  {
1167  //Debug message
1168  TRACE_WARNING("Solicited flag must be zero!\r\n");
1169  //Exit immediately
1170  return;
1171  }
1172 
1173  //Calculate the length of the Options field
1174  length -= sizeof(NdpNeighborAdvMessage);
1175 
1176  //Parse Options field
1177  error = ndpCheckOptions(message->options, length);
1178  //All included options must have a length that is greater than zero
1179  if(error)
1180  return;
1181 
1182  //Duplicate address detection
1183  for(i = 0; i < IPV6_ADDR_LIST_SIZE; i++)
1184  {
1185  //Point to the current entry
1186  addrEntry = &interface->ipv6Context.addrList[i];
1187 
1188  //Valid entry?
1189  if(addrEntry->state != IPV6_ADDR_STATE_INVALID)
1190  {
1191  //Check whether the target address is tentative or matches a unicast
1192  //address assigned to the interface
1193  if(ipv6CompAddr(&addrEntry->addr, &message->targetAddr))
1194  {
1195  //Debug message
1196  TRACE_WARNING("The address %s is a duplicate!\r\n",
1197  ipv6AddrToString(&addrEntry->addr, NULL));
1198 
1199  //The address is a duplicate and should not be used
1200  addrEntry->duplicate = TRUE;
1201  //Exit immediately
1202  return;
1203  }
1204  }
1205  }
1206 
1207  //Search the Neighbor cache for the specified target address
1208  neighborCacheEntry = ndpFindNeighborCacheEntry(interface, &message->targetAddr);
1209 
1210  //If no entry exists, the advertisement should be silently discarded
1211  if(neighborCacheEntry != NULL)
1212  {
1213  //This flag tells whether the supplied link-layer
1214  //address differs from that in the cache
1215  differentLinkLayerAddr = FALSE;
1216 
1217  //Search for the Target Link-Layer Address option
1218  option = ndpGetOption(message->options, length,
1220 
1221  //Target Link-Layer Address option found?
1222  if(option != NULL && option->length == 1)
1223  {
1224  //Debug message
1225  TRACE_DEBUG(" Target Link-Layer Address = %s\r\n",
1226  macAddrToString(&option->linkLayerAddr, NULL));
1227 
1228  //Different link-layer address than cached?
1229  if(!macCompAddr(&neighborCacheEntry->macAddr, &option->linkLayerAddr))
1230  {
1231  differentLinkLayerAddr = TRUE;
1232  }
1233  }
1234 
1235  //Check the state of the Neighbor cache entry
1236  if(neighborCacheEntry->state == NDP_STATE_PERMANENT)
1237  {
1238  //Static Neighbor cache entries are never updated
1239  }
1240  else if(neighborCacheEntry->state == NDP_STATE_INCOMPLETE)
1241  {
1242  //If no Target Link-Layer Address option is included, the receiving
1243  //node should silently discard the received advertisement
1244  if(option != NULL && option->length == 1)
1245  {
1246  //Record the link-layer address
1247  neighborCacheEntry->macAddr = option->linkLayerAddr;
1248 
1249  //Send all the packets that are pending for transmission
1250  n = ndpSendQueuedPackets(interface, neighborCacheEntry);
1251 
1252  //Solicited flag is set?
1253  if(message->s)
1254  {
1255  //Computing the random ReachableTime value
1256  neighborCacheEntry->timeout = interface->ndpContext.reachableTime;
1257  //Switch to the REACHABLE state
1258  ndpChangeState(neighborCacheEntry, NDP_STATE_REACHABLE);
1259  }
1260  else
1261  {
1262  //Check whether any packets have been sent
1263  if(n > 0)
1264  {
1265  //Start delay timer
1266  neighborCacheEntry->timeout = NDP_DELAY_FIRST_PROBE_TIME;
1267  //Switch to the DELAY state
1268  ndpChangeState(neighborCacheEntry, NDP_STATE_DELAY);
1269  }
1270  else
1271  {
1272  //Enter the STALE state
1273  ndpChangeState(neighborCacheEntry, NDP_STATE_STALE);
1274  }
1275  }
1276  }
1277  }
1278  else
1279  {
1280  //Check whether the Override flag is clear and the supplied link-layer
1281  //address differs from that in the cache
1282  if(!message->o && differentLinkLayerAddr)
1283  {
1284  //REACHABLE state?
1285  if(neighborCacheEntry->state == NDP_STATE_REACHABLE)
1286  {
1287  //Enter the STALE state
1288  ndpChangeState(neighborCacheEntry, NDP_STATE_STALE);
1289  }
1290  }
1291  else
1292  {
1293  //Solicited flag is set?
1294  if(message->s)
1295  {
1296  //Different link-layer address than cached?
1297  if(differentLinkLayerAddr)
1298  {
1299  //The link-layer address must be inserted in the cache
1300  neighborCacheEntry->macAddr = option->linkLayerAddr;
1301  }
1302 
1303  //Computing the random ReachableTime value
1304  neighborCacheEntry->timeout = interface->ndpContext.reachableTime;
1305  //Switch to the REACHABLE state
1306  ndpChangeState(neighborCacheEntry, NDP_STATE_REACHABLE);
1307  }
1308  else
1309  {
1310  //Different link-layer address than cached?
1311  if(differentLinkLayerAddr)
1312  {
1313  //The link-layer address must be inserted in the cache
1314  neighborCacheEntry->macAddr = option->linkLayerAddr;
1315 
1316  //The state must be set to STALE
1317  ndpChangeState(neighborCacheEntry, NDP_STATE_STALE);
1318  }
1319  }
1320  }
1321  }
1322 
1323  //The IsRouter flag in the cache entry must be set based on the Router
1324  //flag in the received advertisement
1325  if(message->r)
1326  {
1327  //The neighbor is a router
1328  neighborCacheEntry->isRouter = TRUE;
1329  }
1330  else
1331  {
1332  //Check whether the IsRouter flag changes from TRUE to FALSE as a
1333  //result of this update
1334  if(neighborCacheEntry->isRouter)
1335  {
1336  //The node must remove that router from the Default Router list
1337  //and update the Destination cache entries for all destinations
1338  //using that neighbor as a router
1339  ipv6RemoveDefaultRouter(interface, &neighborCacheEntry->ipAddr);
1340  }
1341 
1342  //The neighbor is a host
1343  neighborCacheEntry->isRouter = FALSE;
1344  }
1345  }
1346 #endif
1347 }
1348 
1349 
1350 /**
1351  * @brief Redirect message processing
1352  * @param[in] interface Underlying network interface
1353  * @param[in] pseudoHeader IPv6 pseudo header
1354  * @param[in] buffer Multi-part buffer containing the Redirect message
1355  * @param[in] offset Offset to the first byte of the message
1356  * @param[in] hopLimit Hop Limit field from IPv6 header
1357  **/
1358 
1360  const Ipv6PseudoHeader *pseudoHeader, const NetBuffer *buffer,
1361  size_t offset, uint8_t hopLimit)
1362 {
1363 #if (ETH_SUPPORT == ENABLED)
1364  error_t error;
1365  uint_t n;
1366  size_t length;
1368  NdpLinkLayerAddrOption *option;
1369  NdpNeighborCacheEntry *neighborCacheEntry;
1370  NdpDestCacheEntry *destCacheEntry;
1371 
1372  //Retrieve the length of the message
1373  length = netBufferGetLength(buffer) - offset;
1374 
1375  //Check the length of the Redirect message
1376  if(length < sizeof(NdpRedirectMessage))
1377  return;
1378 
1379  //Point to the beginning of the message
1380  message = netBufferAt(buffer, offset);
1381  //Sanity check
1382  if(message == NULL)
1383  return;
1384 
1385  //Debug message
1386  TRACE_INFO("Redirect message received (%" PRIuSIZE " bytes)...\r\n", length);
1387  //Dump message contents for debugging purpose
1389 
1390  //The IPv6 Hop Limit field must have a value of 255 to ensure that the
1391  //packet has not been forwarded by a router
1392  if(hopLimit != NDP_HOP_LIMIT)
1393  return;
1394 
1395  //ICMPv6 Code must be 0
1396  if(message->code)
1397  return;
1398 
1399  //Routers must use their link-local address as the source for Redirect
1400  //messages so that hosts can uniquely identify routers
1401  if(!ipv6IsLinkLocalUnicastAddr(&pseudoHeader->srcAddr))
1402  return;
1403 
1404  //The IP source address of the Redirect must be the same as the current
1405  //first-hop router for the specified Destination address
1406  if(!ndpIsFirstHopRouter(interface, &message->destAddr, &pseudoHeader->srcAddr))
1407  return;
1408 
1409  //The Destination Address field in the Redirect message must not
1410  //contain a multicast address
1411  if(ipv6IsMulticastAddr(&message->destAddr))
1412  return;
1413 
1414  //The Target Address must be either a link-local address (when redirected
1415  //to a router) or the same as the Destination Address (when redirected to
1416  //the on-link destination)
1417  if(!ipv6IsLinkLocalUnicastAddr(&message->targetAddr) &&
1418  !ipv6CompAddr(&message->targetAddr, &message->destAddr))
1419  {
1420  //Silently discard the received Redirect message
1421  return;
1422  }
1423 
1424  //Calculate the length of the Options field
1425  length -= sizeof(NdpNeighborAdvMessage);
1426 
1427  //Parse Options field
1428  error = ndpCheckOptions(message->options, length);
1429  //All included options must have a length that is greater than zero
1430  if(error)
1431  return;
1432 
1433  //Search the Destination cache for the specified address
1434  destCacheEntry = ndpFindDestCacheEntry(interface, &message->destAddr);
1435 
1436  //Check whether a corresponding Destination cache entry exists
1437  if(destCacheEntry != NULL)
1438  {
1439  //The entry is updated with information learned from Redirect messages
1440  destCacheEntry->nextHop = message->targetAddr;
1441  //Save current time
1442  destCacheEntry->timestamp = osGetSystemTime();
1443  }
1444  else
1445  {
1446  //If no Destination Cache entry exists for the destination, an
1447  //implementation should create such an entry
1448  destCacheEntry = ndpCreateDestCacheEntry(interface);
1449 
1450  //Destination cache entry successfully created?
1451  if(destCacheEntry != NULL)
1452  {
1453  //Destination address
1454  destCacheEntry->destAddr = message->destAddr;
1455  //Address of the next hop
1456  destCacheEntry->nextHop = message->targetAddr;
1457 
1458  //Initially, the PMTU value for a path is assumed to be
1459  //the MTU of the first-hop link
1460  destCacheEntry->pathMtu = interface->ipv6Context.linkMtu;
1461 
1462  //Save current time
1463  destCacheEntry->timestamp = osGetSystemTime();
1464  }
1465  }
1466 
1467  //Search for the Target Link-Layer Address option
1468  option = ndpGetOption(message->options, length,
1470 
1471  //If the Redirect contains a Target Link-Layer Address option, the host
1472  //either creates or updates the Neighbor Cache entry for the target
1473  if(option != NULL && option->length == 1)
1474  {
1475  //Debug message
1476  TRACE_DEBUG(" Target Link-Layer Address = %s\r\n",
1477  macAddrToString(&option->linkLayerAddr, NULL));
1478 
1479  //Search the Neighbor cache for the specified target address
1480  neighborCacheEntry = ndpFindNeighborCacheEntry(interface,
1481  &message->targetAddr);
1482 
1483  //No matching entry has been found?
1484  if(neighborCacheEntry == NULL)
1485  {
1486  //Check whether Neighbor Discovery protocol is enabled
1487  if(interface->ndpContext.enable)
1488  {
1489  //Create an entry for the target
1490  neighborCacheEntry = ndpCreateNeighborCacheEntry(interface);
1491 
1492  //Neighbor cache entry successfully created?
1493  if(neighborCacheEntry != NULL)
1494  {
1495  //Record the Target address
1496  neighborCacheEntry->ipAddr = message->targetAddr;
1497  //The cached link-layer address is copied from the option
1498  neighborCacheEntry->macAddr = option->linkLayerAddr;
1499 
1500  //Newly created Neighbor Cache entries should set the IsRouter
1501  //flag to FALSE
1502  neighborCacheEntry->isRouter = FALSE;
1503 
1504  //The reachability state must be set to STALE
1505  ndpChangeState(neighborCacheEntry, NDP_STATE_STALE);
1506  }
1507  }
1508  }
1509  else
1510  {
1511  //If the Target Address is not the same as the Destination Address,
1512  //the host must set IsRouter to TRUE for the target
1513  if(!ipv6CompAddr(&message->targetAddr, &message->destAddr))
1514  {
1515  neighborCacheEntry->isRouter = TRUE;
1516  }
1517 
1518  //Check the state of the Neighbor cache entry
1519  if(neighborCacheEntry->state == NDP_STATE_PERMANENT)
1520  {
1521  //Static Neighbor cache entries are never updated
1522  }
1523  else if(neighborCacheEntry->state == NDP_STATE_INCOMPLETE)
1524  {
1525  //Record link-layer address
1526  neighborCacheEntry->macAddr = option->linkLayerAddr;
1527 
1528  //Send all the packets that are pending for transmission
1529  n = ndpSendQueuedPackets(interface, neighborCacheEntry);
1530 
1531  //Check whether any packets have been sent
1532  if(n > 0)
1533  {
1534  //Start delay timer
1535  neighborCacheEntry->timeout = NDP_DELAY_FIRST_PROBE_TIME;
1536  //Switch to the DELAY state
1537  ndpChangeState(neighborCacheEntry, NDP_STATE_DELAY);
1538  }
1539  else
1540  {
1541  //Enter the STALE state
1542  ndpChangeState(neighborCacheEntry, NDP_STATE_STALE);
1543  }
1544  }
1545  else
1546  {
1547  //Different link-layer address than cached?
1548  if(!macCompAddr(&neighborCacheEntry->macAddr, &option->linkLayerAddr))
1549  {
1550  //Update link-layer address
1551  neighborCacheEntry->macAddr = option->linkLayerAddr;
1552 
1553  //The reachability state must be set to STALE
1554  ndpChangeState(neighborCacheEntry, NDP_STATE_STALE);
1555  }
1556  }
1557  }
1558  }
1559 #endif
1560 }
1561 
1562 
1563 /**
1564  * @brief Send a Router Solicitation message
1565  * @param[in] interface Underlying network interface
1566  * @return Error code
1567  **/
1568 
1570 {
1571  error_t error;
1572  size_t offset;
1573  size_t length;
1574  NetBuffer *buffer;
1576  Ipv6PseudoHeader pseudoHeader;
1577  NetTxAncillary ancillary;
1578 
1579  //The destination address is typically the all-routers multicast address
1580  pseudoHeader.destAddr = IPV6_LINK_LOCAL_ALL_ROUTERS_ADDR;
1581 
1582  //Select the most appropriate source address to be used when sending the
1583  //Router Solicitation message
1584  error = ipv6SelectSourceAddr(&interface, &pseudoHeader.destAddr,
1585  &pseudoHeader.srcAddr);
1586 
1587  //No address assigned to the interface?
1588  if(error)
1589  {
1590  //Use the unspecified address if no address is assigned
1591  //to the sending interface
1592  pseudoHeader.srcAddr = IPV6_UNSPECIFIED_ADDR;
1593  }
1594 
1595  //The only defined option that may appear in a Router Solicitation
1596  //message is the Source Link-Layer Address option
1598 
1599  //Allocate a memory buffer to hold the Router Solicitation message
1600  buffer = ipAllocBuffer(length, &offset);
1601  //Failed to allocate memory?
1602  if(buffer == NULL)
1603  return ERROR_OUT_OF_MEMORY;
1604 
1605  //Point to the beginning of the message
1606  message = netBufferAt(buffer, offset);
1607 
1608  //Format Router Solicitation message
1610  message->code = 0;
1611  message->checksum = 0;
1612  message->reserved = 0;
1613 
1614  //Length of the message, excluding any option
1615  length = sizeof(NdpRouterSolMessage);
1616 
1617  //The Source Link-Layer Address option must not be included
1618  //when the source IPv6 address is the unspecified address
1619  if(!ipv6CompAddr(&pseudoHeader.srcAddr, &IPV6_UNSPECIFIED_ADDR))
1620  {
1621 #if (ETH_SUPPORT == ENABLED)
1622  NetInterface *logicalInterface;
1623 
1624  //Point to the logical interface
1625  logicalInterface = nicGetLogicalInterface(interface);
1626 
1627  //Check whether a MAC address has been assigned to the interface
1628  if(!macCompAddr(&logicalInterface->macAddr, &MAC_UNSPECIFIED_ADDR))
1629  {
1630  //Add Source Link-Layer Address option
1632  &logicalInterface->macAddr, sizeof(MacAddr));
1633  }
1634 #endif
1635  }
1636 
1637  //Adjust the length of the multi-part buffer
1638  netBufferSetLength(buffer, offset + length);
1639 
1640  //Format IPv6 pseudo header
1641  pseudoHeader.length = htonl(length);
1642  pseudoHeader.reserved[0] = 0;
1643  pseudoHeader.reserved[1] = 0;
1644  pseudoHeader.reserved[2] = 0;
1645  pseudoHeader.nextHeader = IPV6_ICMPV6_HEADER;
1646 
1647  //Calculate ICMPv6 header checksum
1648  message->checksum = ipCalcUpperLayerChecksumEx(&pseudoHeader,
1649  sizeof(Ipv6PseudoHeader), buffer, offset, length);
1650 
1651  //Total number of ICMP messages which this entity attempted to send
1652  IP_MIB_INC_COUNTER32(icmpv6Stats.icmpStatsOutMsgs, 1);
1653  //Increment per-message type ICMP counter
1654  IP_MIB_INC_COUNTER32(icmpv6MsgStatsTable.icmpMsgStatsOutPkts[ICMPV6_TYPE_ROUTER_SOL], 1);
1655 
1656  //Debug message
1657  TRACE_INFO("Sending Router Solicitation message (%" PRIuSIZE " bytes)...\r\n", length);
1658  //Dump message contents for debugging purpose
1660 
1661  //Additional options can be passed to the stack along with the packet
1662  ancillary = NET_DEFAULT_TX_ANCILLARY;
1663 
1664  //By setting the Hop Limit to 255, Neighbor Discovery is immune to off-link
1665  //senders that accidentally or intentionally send NDP messages (refer to
1666  //RFC 4861, section 3.1)
1667  ancillary.ttl = NDP_HOP_LIMIT;
1668 
1669  //Send Router Solicitation message
1670  error = ipv6SendDatagram(interface, &pseudoHeader, buffer, offset,
1671  &ancillary);
1672 
1673  //Free previously allocated memory
1674  netBufferFree(buffer);
1675 
1676  //Return status code
1677  return error;
1678 }
1679 
1680 
1681 /**
1682  * @brief Send a Neighbor Solicitation message
1683  * @param[in] interface Underlying network interface
1684  * @param[in] targetIpAddr Target IPv6 address
1685  * @param[in] multicast Unicast or unicast Neighbor Solicitation message
1686  * @return Error code
1687  **/
1688 
1690  const Ipv6Addr *targetIpAddr, bool_t multicast)
1691 {
1692  error_t error;
1693  size_t offset;
1694  size_t length;
1695  NetBuffer *buffer;
1697  Ipv6PseudoHeader pseudoHeader;
1698  NetTxAncillary ancillary;
1699 
1700  //Multicast Neighbor Solicitation message?
1701  if(multicast)
1702  {
1703  //Compute the solicited-node multicast address that
1704  //corresponds to the target IPv6 address
1705  ipv6ComputeSolicitedNodeAddr(targetIpAddr, &pseudoHeader.destAddr);
1706  }
1707  else
1708  {
1709  //Unicast Neighbor Solicitation message
1710  pseudoHeader.destAddr = *targetIpAddr;
1711  }
1712 
1713  //Check whether the target address is a tentative address
1714  if(ipv6IsTentativeAddr(interface, targetIpAddr))
1715  {
1716  //The IPv6 source is set to the unspecified address
1717  pseudoHeader.srcAddr = IPV6_UNSPECIFIED_ADDR;
1718  }
1719  else
1720  {
1721  //Select the most appropriate source address to be used when sending
1722  //the Neighbor Solicitation message
1723  error = ipv6SelectSourceAddr(&interface, targetIpAddr,
1724  &pseudoHeader.srcAddr);
1725 
1726  //No address assigned to the interface?
1727  if(error)
1728  return error;
1729  }
1730 
1731  //The only defined option that may appear in a Neighbor Solicitation
1732  //message is the Source Link-Layer Address option
1734 
1735  //Allocate a memory buffer to hold the Neighbor Solicitation message
1736  buffer = ipAllocBuffer(length, &offset);
1737  //Failed to allocate memory?
1738  if(buffer == NULL)
1739  return ERROR_OUT_OF_MEMORY;
1740 
1741  //Point to the beginning of the message
1742  message = netBufferAt(buffer, offset);
1743 
1744  //Format Neighbor Solicitation message
1746  message->code = 0;
1747  message->checksum = 0;
1748  message->reserved = 0;
1749  message->targetAddr = *targetIpAddr;
1750 
1751  //Length of the message, excluding any option
1752  length = sizeof(NdpNeighborSolMessage);
1753 
1754  //The Source Link-Layer Address option must not be included
1755  //when the source IPv6 address is the unspecified address
1756  if(!ipv6CompAddr(&pseudoHeader.srcAddr, &IPV6_UNSPECIFIED_ADDR))
1757  {
1758 #if (ETH_SUPPORT == ENABLED)
1759  NetInterface *logicalInterface;
1760 
1761  //Point to the logical interface
1762  logicalInterface = nicGetLogicalInterface(interface);
1763 
1764  //Add Source Link-Layer Address option
1766  &logicalInterface->macAddr, sizeof(MacAddr));
1767 #endif
1768  }
1769 
1770  //Adjust the length of the multi-part buffer
1771  netBufferSetLength(buffer, offset + length);
1772 
1773  //Format IPv6 pseudo header
1774  pseudoHeader.length = htonl(length);
1775  pseudoHeader.reserved[0] = 0;
1776  pseudoHeader.reserved[1] = 0;
1777  pseudoHeader.reserved[2] = 0;
1778  pseudoHeader.nextHeader = IPV6_ICMPV6_HEADER;
1779 
1780  //Calculate ICMPv6 header checksum
1781  message->checksum = ipCalcUpperLayerChecksumEx(&pseudoHeader,
1782  sizeof(Ipv6PseudoHeader), buffer, offset, length);
1783 
1784  //Total number of ICMP messages which this entity attempted to send
1785  IP_MIB_INC_COUNTER32(icmpv6Stats.icmpStatsOutMsgs, 1);
1786  //Increment per-message type ICMP counter
1787  IP_MIB_INC_COUNTER32(icmpv6MsgStatsTable.icmpMsgStatsOutPkts[ICMPV6_TYPE_NEIGHBOR_SOL], 1);
1788 
1789  //Debug message
1790  TRACE_INFO("Sending Neighbor Solicitation message (%" PRIuSIZE " bytes)...\r\n", length);
1791  //Dump message contents for debugging purpose
1793 
1794  //Additional options can be passed to the stack along with the packet
1795  ancillary = NET_DEFAULT_TX_ANCILLARY;
1796 
1797  //By setting the Hop Limit to 255, Neighbor Discovery is immune to off-link
1798  //senders that accidentally or intentionally send NDP messages (refer to
1799  //RFC 4861, section 3.1)
1800  ancillary.ttl = NDP_HOP_LIMIT;
1801 
1802  //Send Neighbor Solicitation message
1803  error = ipv6SendDatagram(interface, &pseudoHeader, buffer, offset,
1804  &ancillary);
1805 
1806  //Free previously allocated memory
1807  netBufferFree(buffer);
1808 
1809  //Return status code
1810  return error;
1811 }
1812 
1813 
1814 /**
1815  * @brief Send a Neighbor Advertisement message
1816  * @param[in] interface Underlying network interface
1817  * @param[in] targetIpAddr Target IPv6 address
1818  * @param[in] destIpAddr Destination IPv6 address
1819  * @return Error code
1820  **/
1821 
1823  const Ipv6Addr *targetIpAddr, const Ipv6Addr *destIpAddr)
1824 {
1825  error_t error;
1826  size_t offset;
1827  size_t length;
1828  NetBuffer *buffer;
1830  Ipv6PseudoHeader pseudoHeader;
1831  NetTxAncillary ancillary;
1832 #if (ETH_SUPPORT == ENABLED)
1833  NetInterface *logicalInterface;
1834 #endif
1835 
1836  //Destination IP address is the unspecified address?
1838  {
1839  //If the destination is the unspecified address, the node must
1840  //multicast the advertisement to the all-nodes address
1841  pseudoHeader.destAddr = IPV6_LINK_LOCAL_ALL_NODES_ADDR;
1842  }
1843  else
1844  {
1845  //Otherwise, the node must unicast the advertisement to the
1846  //destination IP address
1847  pseudoHeader.destAddr = *destIpAddr;
1848  }
1849 
1850  //Check whether the target address is a valid anycast address assigned
1851  //to the interface
1852  if(ipv6IsAnycastAddr(interface, targetIpAddr))
1853  {
1854  //Select the most appropriate source address to be used when sending
1855  //the Neighbor Advertisement message
1856  error = ipv6SelectSourceAddr(&interface, targetIpAddr,
1857  &pseudoHeader.srcAddr);
1858 
1859  //No address assigned to the interface?
1860  if(error)
1861  return error;
1862  }
1863  else
1864  {
1865  //Set the source IP address
1866  pseudoHeader.srcAddr = *targetIpAddr;
1867  }
1868 
1869  //The only defined option that may appear in a Neighbor Advertisement
1870  //message is the Target Link-Layer Address option
1872 
1873  //Allocate a memory buffer to hold the Neighbor Advertisement message
1874  buffer = ipAllocBuffer(length, &offset);
1875  //Failed to allocate memory?
1876  if(buffer == NULL)
1877  return ERROR_OUT_OF_MEMORY;
1878 
1879  //Point to the beginning of the message
1880  message = netBufferAt(buffer, offset);
1881 
1882  //Format Neighbor Advertisement message
1884  message->code = 0;
1885  message->checksum = 0;
1886  message->reserved1 = 0;
1887  message->reserved2[0] = 0;
1888  message->reserved2[1] = 0;
1889  message->reserved2[2] = 0;
1890  message->targetAddr = *targetIpAddr;
1891 
1892  //The Router flag indicates that the sender is a router
1893  if(interface->ipv6Context.isRouter)
1894  {
1895  message->r = TRUE;
1896  }
1897  else
1898  {
1899  message->r = FALSE;
1900  }
1901 
1902  //If the destination is the unspecified address, the node must set
1903  //the Solicited flag to zero
1905  {
1906  message->s = FALSE;
1907  }
1908  else
1909  {
1910  message->s = TRUE;
1911  }
1912 
1913  //The Override flag should not be set in solicited advertisements
1914  //for anycast addresses
1915  if(ipv6IsAnycastAddr(interface, targetIpAddr))
1916  {
1917  message->o = FALSE;
1918  }
1919  else
1920  {
1921  message->o = TRUE;
1922  }
1923 
1924  //Length of the message, excluding any option
1925  length = sizeof(NdpNeighborAdvMessage);
1926 
1927 #if (ETH_SUPPORT == ENABLED)
1928  //Point to the logical interface
1929  logicalInterface = nicGetLogicalInterface(interface);
1930 
1931  //Add Target Link-Layer Address option
1933  &logicalInterface->macAddr, sizeof(MacAddr));
1934 #endif
1935 
1936  //Adjust the length of the multi-part buffer
1937  netBufferSetLength(buffer, offset + length);
1938 
1939  //Format IPv6 pseudo header
1940  pseudoHeader.length = htonl(length);
1941  pseudoHeader.reserved[0] = 0;
1942  pseudoHeader.reserved[1] = 0;
1943  pseudoHeader.reserved[2] = 0;
1944  pseudoHeader.nextHeader = IPV6_ICMPV6_HEADER;
1945 
1946  //Calculate ICMPv6 header checksum
1947  message->checksum = ipCalcUpperLayerChecksumEx(&pseudoHeader,
1948  sizeof(Ipv6PseudoHeader), buffer, offset, length);
1949 
1950  //Total number of ICMP messages which this entity attempted to send
1951  IP_MIB_INC_COUNTER32(icmpv6Stats.icmpStatsOutMsgs, 1);
1952  //Increment per-message type ICMP counter
1953  IP_MIB_INC_COUNTER32(icmpv6MsgStatsTable.icmpMsgStatsOutPkts[ICMPV6_TYPE_NEIGHBOR_ADV], 1);
1954 
1955  //Debug message
1956  TRACE_INFO("Sending Neighbor Advertisement message (%" PRIuSIZE " bytes)...\r\n", length);
1957  //Dump message contents for debugging purpose
1959 
1960  //Additional options can be passed to the stack along with the packet
1961  ancillary = NET_DEFAULT_TX_ANCILLARY;
1962 
1963  //By setting the Hop Limit to 255, Neighbor Discovery is immune to off-link
1964  //senders that accidentally or intentionally send NDP messages (refer to
1965  //RFC 4861, section 3.1)
1966  ancillary.ttl = NDP_HOP_LIMIT;
1967 
1968  //Send Neighbor Advertisement message
1969  error = ipv6SendDatagram(interface, &pseudoHeader, buffer, offset,
1970  &ancillary);
1971 
1972  //Free previously allocated memory
1973  netBufferFree(buffer);
1974 
1975  //Return status code
1976  return error;
1977 }
1978 
1979 
1980 /**
1981  * @brief Send a Redirect message
1982  * @param[in] interface Underlying network interface
1983  * @param[in] targetAddr IPv6 address that is a better first hop to use
1984  * for the destination address
1985  * @param[in] ipPacket Multi-part buffer that holds the IPv6 packet that
1986  * triggered the sending of the Redirect
1987  * @param[in] ipPacketOffset Offset to the first byte of the IPv6 packet
1988  * @return Error code
1989  **/
1990 
1992  const NetBuffer *ipPacket, size_t ipPacketOffset)
1993 {
1994  error_t error;
1995  size_t offset;
1996  size_t length;
1997  size_t ipPacketLen;
1998  size_t optionLen;
1999  size_t paddingLen;
2000  NetBuffer *buffer;
2002  NdpRedirectedHeaderOption *option;
2003  NdpNeighborCacheEntry *entry;
2004  Ipv6Header *ipHeader;
2005  Ipv6PseudoHeader pseudoHeader;
2006  NetTxAncillary ancillary;
2007  uint8_t padding[8];
2008 
2009  //Retrieve the length of the forwarded IPv6 packet
2010  ipPacketLen = netBufferGetLength(ipPacket) - ipPacketOffset;
2011 
2012  //Check the length of the IPv6 packet
2013  if(ipPacketLen < sizeof(Ipv6Header))
2014  return ERROR_INVALID_LENGTH;
2015 
2016  //Point to the header of the invoking packet
2017  ipHeader = netBufferAt(ipPacket, ipPacketOffset);
2018  //Sanity check
2019  if(ipHeader == NULL)
2020  return ERROR_FAILURE;
2021 
2022  //The only defined options that may appear in a Redirect message are the
2023  //Target Link-Layer Address option and the Redirected Header option
2024  length = sizeof(NdpRedirectMessage) + sizeof(NdpLinkLayerAddrOption) +
2025  sizeof(NdpRedirectedHeaderOption);
2026 
2027  //Allocate a memory buffer to hold the Redirect message
2028  buffer = ipAllocBuffer(length, &offset);
2029  //Failed to allocate memory?
2030  if(buffer == NULL)
2031  return ERROR_OUT_OF_MEMORY;
2032 
2033  //Point to the beginning of the message
2034  message = netBufferAt(buffer, offset);
2035 
2036  //Format Redirect message
2037  message->type = ICMPV6_TYPE_REDIRECT;
2038  message->code = 0;
2039  message->checksum = 0;
2040  message->reserved = 0;
2041  message->targetAddr = *targetAddr;
2042  message->destAddr = ipHeader->destAddr;
2043 
2044  //Length of the message, excluding any option
2045  length = sizeof(NdpRedirectMessage);
2046 
2047  //Search the Neighbor cache for the specified target address
2048  entry = ndpFindNeighborCacheEntry(interface, targetAddr);
2049 
2050  //Include the link-layer address of the target, if known
2051  if(entry != NULL)
2052  {
2053  //Add Target Link-Layer Address option
2055  &entry->macAddr, sizeof(MacAddr));
2056  }
2057 
2058  //Retrieve the length of the IPv6 packet that triggered the sending
2059  //of the Redirect
2060  ipPacketLen = netBufferGetLength(ipPacket) - ipPacketOffset;
2061 
2062  //Return as much of the forwarded IPv6 packet as can fit without the
2063  //redirect packet exceeding the minimum IPv6 MTU
2064  ipPacketLen = MIN(ipPacketLen, IPV6_DEFAULT_MTU -
2065  sizeof(NdpRedirectedHeaderOption) - length);
2066 
2067  //Length of the Redirected Header option in units of 8 bytes including
2068  //the type and length fields
2069  optionLen = (ipPacketLen + sizeof(NdpOption) + 7) / 8;
2070 
2071  //Add Redirected Header option
2072  option = (NdpRedirectedHeaderOption *) ((uint8_t *) message + length);
2073 
2074  //Format Redirected Header option
2075  option->type = NDP_OPT_REDIRECTED_HEADER;
2076  option->length = (uint8_t) optionLen;
2077  option->reserved1 = 0;
2078  option->reserved2 = 0;
2079 
2080  //Update the length of Redirect message
2081  length += sizeof(NdpRedirectedHeaderOption);
2082 
2083  //Adjust the length of the multi-part buffer
2084  netBufferSetLength(buffer, offset + length);
2085 
2086  //Copy the contents of the forwarded IPv6 packet
2087  error = netBufferConcat(buffer, ipPacket, ipPacketOffset, ipPacketLen);
2088 
2089  //Check status code
2090  if(!error)
2091  {
2092  //Options should be padded when necessary to ensure that they end on
2093  //their natural 64-bit boundaries
2094  if((ipPacketLen + sizeof(NdpRedirectedHeaderOption)) < (optionLen * 8))
2095  {
2096  //Determine the amount of padding data to append
2097  paddingLen = (optionLen * 8) - ipPacketLen -
2098  sizeof(NdpRedirectedHeaderOption);
2099 
2100  //Prepare padding data
2101  osMemset(padding, 0, paddingLen);
2102  //Append padding bytes
2103  error = netBufferAppend(buffer, padding, paddingLen);
2104  }
2105  }
2106 
2107  //Check status code
2108  if(!error)
2109  {
2110  //Get the length of the resulting message
2111  length = netBufferGetLength(buffer) - offset;
2112 
2113  //Format IPv6 pseudo header
2114  pseudoHeader.srcAddr = interface->ipv6Context.addrList[0].addr;
2115  pseudoHeader.destAddr = ipHeader->srcAddr;
2116  pseudoHeader.length = htonl(length);
2117  pseudoHeader.reserved[0] = 0;
2118  pseudoHeader.reserved[1] = 0;
2119  pseudoHeader.reserved[2] = 0;
2120  pseudoHeader.nextHeader = IPV6_ICMPV6_HEADER;
2121 
2122  //Message checksum calculation
2123  message->checksum = ipCalcUpperLayerChecksumEx(&pseudoHeader,
2124  sizeof(Ipv6PseudoHeader), buffer, offset, length);
2125 
2126  //Total number of ICMP messages which this entity attempted to send
2127  IP_MIB_INC_COUNTER32(icmpv6Stats.icmpStatsOutMsgs, 1);
2128  //Increment per-message type ICMP counter
2129  IP_MIB_INC_COUNTER32(icmpv6MsgStatsTable.icmpMsgStatsOutPkts[ICMPV6_TYPE_REDIRECT], 1);
2130 
2131  //Debug message
2132  TRACE_INFO("Sending Redirect message (%" PRIuSIZE " bytes)...\r\n", length);
2133  //Dump message contents for debugging purpose
2135 
2136  //Additional options can be passed to the stack along with the packet
2137  ancillary = NET_DEFAULT_TX_ANCILLARY;
2138 
2139  //By setting the Hop Limit to 255, Neighbor Discovery is immune to off-link
2140  //senders that accidentally or intentionally send NDP messages (refer to
2141  //RFC 4861, section 3.1)
2142  ancillary.ttl = NDP_HOP_LIMIT;
2143 
2144  //Send Redirect message
2145  error = ipv6SendDatagram(interface, &pseudoHeader, buffer, offset,
2146  &ancillary);
2147  }
2148 
2149  //Free previously allocated memory
2150  netBufferFree(buffer);
2151 
2152  //Return status code
2153  return error;
2154 }
2155 
2156 
2157 /**
2158  * @brief Dump Router Solicitation message for debugging purpose
2159  * @param[in] message Router Solicitation message
2160  **/
2161 
2163 {
2164  //Dump Router Solicitation message
2165  TRACE_DEBUG(" Type = %" PRIu8 "\r\n", message->type);
2166  TRACE_DEBUG(" Code = %" PRIu8 "\r\n", message->code);
2167  TRACE_DEBUG(" Checksum = 0x%04" PRIX16 "\r\n", ntohs(message->checksum));
2168 }
2169 
2170 
2171 /**
2172  * @brief Dump Router Advertisement message for debugging purpose
2173  * @param[in] message Router Advertisement message
2174  **/
2175 
2177 {
2178  //Dump Router Advertisement message
2179  TRACE_DEBUG(" Type = %" PRIu8 "\r\n", message->type);
2180  TRACE_DEBUG(" Code = %" PRIu8 "\r\n", message->code);
2181  TRACE_DEBUG(" Checksum = 0x%04" PRIX16 "\r\n", ntohs(message->checksum));
2182  TRACE_DEBUG(" Cur Hop Limit = %" PRIu8 "\r\n", message->curHopLimit);
2183  TRACE_DEBUG(" M = %" PRIu8 "\r\n", message->m);
2184  TRACE_DEBUG(" O = %" PRIu8 "\r\n", message->o);
2185  TRACE_DEBUG(" Router Lifetime = %" PRIu16 "\r\n", ntohs(message->routerLifetime));
2186  TRACE_DEBUG(" Reachable Time = %" PRIu32 "\r\n", ntohl(message->reachableTime));
2187  TRACE_DEBUG(" Retrans Timer = %" PRIu32 "\r\n", ntohl(message->retransTimer));
2188 }
2189 
2190 
2191 /**
2192  * @brief Dump Neighbor Solicitation message for debugging purpose
2193  * @param[in] message Neighbor Solicitation message
2194  **/
2195 
2197 {
2198  //Dump Neighbor Solicitation message
2199  TRACE_DEBUG(" Type = %" PRIu8 "\r\n", message->type);
2200  TRACE_DEBUG(" Code = %" PRIu8 "\r\n", message->code);
2201  TRACE_DEBUG(" Checksum = 0x%04" PRIX16 "\r\n", ntohs(message->checksum));
2202  TRACE_DEBUG(" Target Address = %s\r\n", ipv6AddrToString(&message->targetAddr, NULL));
2203 }
2204 
2205 
2206 /**
2207  * @brief Dump Neighbor Advertisement message for debugging purpose
2208  * @param[in] message Neighbor Advertisement message
2209  **/
2210 
2212 {
2213  //Dump Neighbor Advertisement message
2214  TRACE_DEBUG(" Type = %" PRIu8 "\r\n", message->type);
2215  TRACE_DEBUG(" Code = %" PRIu8 "\r\n", message->code);
2216  TRACE_DEBUG(" Checksum = 0x%04" PRIX16 "\r\n", ntohs(message->checksum));
2217  TRACE_DEBUG(" R = %" PRIu8 "\r\n", message->r);
2218  TRACE_DEBUG(" S = %" PRIu8 "\r\n", message->s);
2219  TRACE_DEBUG(" O = %" PRIu8 "\r\n", message->o);
2220  TRACE_DEBUG(" Target Address = %s\r\n", ipv6AddrToString(&message->targetAddr, NULL));
2221 }
2222 
2223 
2224 /**
2225  * @brief Dump Redirect message for debugging purpose
2226  * @param[in] message Redirect message
2227  **/
2228 
2230 {
2231  //Dump Neighbor Advertisement message
2232  TRACE_DEBUG(" Type = %" PRIu8 "\r\n", message->type);
2233  TRACE_DEBUG(" Code = %" PRIu8 "\r\n", message->code);
2234  TRACE_DEBUG(" Checksum = 0x%04" PRIX16 "\r\n", ntohs(message->checksum));
2235  TRACE_DEBUG(" Target Address = %s\r\n", ipv6AddrToString(&message->targetAddr, NULL));
2236  TRACE_DEBUG(" Destination Address = %s\r\n", ipv6AddrToString(&message->destAddr, NULL));
2237 }
2238 
2239 #endif
uint8_t message[]
Definition: chap.h:154
unsigned int uint_t
Definition: compiler_port.h:50
#define PRIuSIZE
int bool_t
Definition: compiler_port.h:53
#define ntohl(value)
Definition: cpu_endian.h:422
#define htonl(value)
Definition: cpu_endian.h:414
#define ntohs(value)
Definition: cpu_endian.h:421
Debugging facilities.
#define TRACE_DEBUG(...)
Definition: debug.h:107
#define TRACE_WARNING(...)
Definition: debug.h:85
#define TRACE_INFO(...)
Definition: debug.h:95
uint8_t n
uint32_t time
error_t
Error codes.
Definition: error.h:43
@ ERROR_IN_PROGRESS
Definition: error.h:213
@ ERROR_INVALID_ADDRESS
Definition: error.h:103
@ ERROR_NOT_FOUND
Definition: error.h:147
@ ERROR_OUT_OF_RESOURCES
Definition: error.h:64
@ NO_ERROR
Success.
Definition: error.h:44
@ ERROR_OUT_OF_MEMORY
Definition: error.h:63
@ ERROR_UNEXPECTED_STATE
Definition: error.h:99
@ ERROR_INVALID_LENGTH
Definition: error.h:111
@ ERROR_FAILURE
Generic error code.
Definition: error.h:45
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
const MacAddr MAC_UNSPECIFIED_ADDR
Definition: ethernet.c:53
char_t * macAddrToString(const MacAddr *macAddr, char_t *str)
Convert a MAC address to a dash delimited string.
Definition: ethernet.c:917
#define macCompAddr(macAddr1, macAddr2)
Definition: ethernet.h:130
MacAddr
Definition: ethernet.h:195
ICMPv6 (Internet Control Message Protocol Version 6)
@ ICMPV6_TYPE_NEIGHBOR_SOL
Definition: icmpv6.h:64
@ ICMPV6_TYPE_REDIRECT
Definition: icmpv6.h:66
@ ICMPV6_TYPE_NEIGHBOR_ADV
Definition: icmpv6.h:65
@ ICMPV6_TYPE_ROUTER_SOL
Definition: icmpv6.h:62
NetBuffer * ipAllocBuffer(size_t length, size_t *offset)
Allocate a buffer to hold an IP packet.
Definition: ip.c:744
uint16_t ipCalcUpperLayerChecksumEx(const void *pseudoHeader, size_t pseudoHeaderLen, const NetBuffer *buffer, size_t offset, size_t length)
Calculate IP upper-layer checksum over a multi-part buffer.
Definition: ip.c:719
IP MIB module.
#define IP_MIB_INC_COUNTER32(name, value)
Definition: ip_mib_module.h:46
Ipv4Addr ipAddr
Definition: ipcp.h:105
Ipv4Addr destIpAddr
Definition: ipcp.h:80
const Ipv6Addr IPV6_LINK_LOCAL_ALL_NODES_ADDR
Definition: ipv6.c:73
char_t * ipv6AddrToString(const Ipv6Addr *ipAddr, char_t *str)
Convert a binary IPv6 address to a string representation.
Definition: ipv6.c:2376
const Ipv6Addr IPV6_UNSPECIFIED_ADDR
Definition: ipv6.c:65
const Ipv6Addr IPV6_LINK_LOCAL_ALL_ROUTERS_ADDR
Definition: ipv6.c:77
error_t ipv6SendDatagram(NetInterface *interface, const Ipv6PseudoHeader *pseudoHeader, NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Send an IPv6 datagram.
Definition: ipv6.c:1667
Ipv6AddrState ipv6GetLinkLocalAddrState(NetInterface *interface)
Get the state of the link-local address.
Definition: ipv6.c:326
IPv6 (Internet Protocol Version 6)
Ipv6Addr
Definition: ipv6.h:251
#define ipv6IsSolicitedNodeAddr(ipAddr)
Definition: ipv6.h:136
uint8_t hopLimit
Definition: ipv6.h:274
#define IPV6_DEFAULT_MTU
Definition: ipv6.h:108
@ IPV6_ICMPV6_HEADER
Definition: ipv6.h:186
#define Ipv6PseudoHeader
Definition: ipv6.h:42
#define ipv6IsMulticastAddr(ipAddr)
Definition: ipv6.h:132
#define ipv6IsLinkLocalUnicastAddr(ipAddr)
Definition: ipv6.h:124
#define IPV6_ADDR_LIST_SIZE
Definition: ipv6.h:65
#define ipv6CompAddr(ipAddr1, ipAddr2)
Definition: ipv6.h:120
@ IPV6_ADDR_STATE_PREFERRED
An address assigned to an interface whose use is unrestricted.
Definition: ipv6.h:168
@ IPV6_ADDR_STATE_INVALID
An address that is not assigned to any interface.
Definition: ipv6.h:166
@ IPV6_ADDR_STATE_TENTATIVE
An address whose uniqueness on a link is being verified.
Definition: ipv6.h:167
#define Ipv6Header
Definition: ipv6.h:36
error_t ipv6SelectSourceAddr(NetInterface **interface, const Ipv6Addr *destAddr, Ipv6Addr *srcAddr)
IPv6 source address selection.
Definition: ipv6_misc.c:895
void ipv6AddDefaultRouter(NetInterface *interface, const Ipv6Addr *addr, uint16_t lifetime, uint8_t preference)
Add a new entry to the Default Router List.
Definition: ipv6_misc.c:537
error_t ipv6ComputeSolicitedNodeAddr(const Ipv6Addr *ipAddr, Ipv6Addr *solicitedNodeAddr)
Form a solicited-node address from an IPv6 address.
Definition: ipv6_misc.c:1390
bool_t ipv6IsAnycastAddr(NetInterface *interface, const Ipv6Addr *ipAddr)
Check whether an IPv6 address is an anycast address.
Definition: ipv6_misc.c:1089
void ipv6RemoveDefaultRouter(NetInterface *interface, const Ipv6Addr *addr)
Remove an entry from the Default Router List.
Definition: ipv6_misc.c:602
bool_t ipv6IsTentativeAddr(NetInterface *interface, const Ipv6Addr *ipAddr)
Check whether an IPv6 address is a tentative address.
Definition: ipv6_misc.c:1125
Helper functions for IPv6.
void ndpDumpNeighborSolMessage(const NdpNeighborSolMessage *message)
Dump Neighbor Solicitation message for debugging purpose.
Definition: ndp.c:2196
void ndpProcessNeighborSol(NetInterface *interface, const Ipv6PseudoHeader *pseudoHeader, const NetBuffer *buffer, size_t offset, uint8_t hopLimit)
Neighbor Solicitation message processing.
Definition: ndp.c:867
void ndpDumpRedirectMessage(const NdpRedirectMessage *message)
Dump Redirect message for debugging purpose.
Definition: ndp.c:2229
void ndpDumpNeighborAdvMessage(const NdpNeighborAdvMessage *message)
Dump Neighbor Advertisement message for debugging purpose.
Definition: ndp.c:2211
error_t ndpSendRedirect(NetInterface *interface, const Ipv6Addr *targetAddr, const NetBuffer *ipPacket, size_t ipPacketOffset)
Send a Redirect message.
Definition: ndp.c:1991
void ndpDumpRouterAdvMessage(const NdpRouterAdvMessage *message)
Dump Router Advertisement message for debugging purpose.
Definition: ndp.c:2176
void ndpProcessRedirect(NetInterface *interface, const Ipv6PseudoHeader *pseudoHeader, const NetBuffer *buffer, size_t offset, uint8_t hopLimit)
Redirect message processing.
Definition: ndp.c:1359
error_t ndpEnqueuePacket(NetInterface *srcInterface, NetInterface *destInterface, const Ipv6Addr *ipAddr, NetBuffer *buffer, size_t offset, NetTxAncillary *ancillary)
Enqueue an IPv6 packet waiting for address resolution.
Definition: ndp.c:360
error_t ndpAddStaticEntry(NetInterface *interface, const Ipv6Addr *ipAddr, const MacAddr *macAddr)
Add a static entry in the Neighbor cache.
Definition: ndp.c:141
error_t ndpSendNeighborAdv(NetInterface *interface, const Ipv6Addr *targetIpAddr, const Ipv6Addr *destIpAddr)
Send a Neighbor Advertisement message.
Definition: ndp.c:1822
error_t ndpInit(NetInterface *interface)
Neighbor cache initialization.
Definition: ndp.c:68
error_t ndpEnable(NetInterface *interface, bool_t enable)
Enable address resolution using Neighbor Discovery protocol.
Definition: ndp.c:106
error_t ndpSendRouterSol(NetInterface *interface)
Send a Router Solicitation message.
Definition: ndp.c:1569
void ndpDumpRouterSolMessage(const NdpRouterSolMessage *message)
Dump Router Solicitation message for debugging purpose.
Definition: ndp.c:2162
error_t ndpRemoveStaticEntry(NetInterface *interface, const Ipv6Addr *ipAddr)
Remove a static entry from the Neighbor cache.
Definition: ndp.c:215
void ndpProcessNeighborAdv(NetInterface *interface, const Ipv6PseudoHeader *pseudoHeader, const NetBuffer *buffer, size_t offset, uint8_t hopLimit)
Neighbor Advertisement message processing.
Definition: ndp.c:1112
error_t ndpSendNeighborSol(NetInterface *interface, const Ipv6Addr *targetIpAddr, bool_t multicast)
Send a Neighbor Solicitation message.
Definition: ndp.c:1689
void ndpLinkChangeEvent(NetInterface *interface)
Callback function for link change event.
Definition: ndp.c:541
systime_t ndpTickCounter
Definition: ndp.c:59
void ndpProcessRouterAdv(NetInterface *interface, const Ipv6PseudoHeader *pseudoHeader, const NetBuffer *buffer, size_t offset, uint8_t hopLimit)
Router Advertisement message processing.
Definition: ndp.c:578
void ndpTick(NetInterface *interface)
NDP timer handler.
Definition: ndp.c:450
error_t ndpResolve(NetInterface *interface, const Ipv6Addr *ipAddr, MacAddr *macAddr)
Address resolution using Neighbor Discovery protocol.
Definition: ndp.c:260
NDP (Neighbor Discovery Protocol)
NdpRedirectedHeaderOption
Definition: ndp.h:432
NdpRouterAdvMessage
Definition: ndp.h:310
#define NDP_RETRANS_TIMER
Definition: ndp.h:186
Ipv6Addr targetAddr
Definition: ndp.h:323
NdpRedirectMessage
Definition: ndp.h:367
NdpNeighborSolMessage
Definition: ndp.h:325
uint8_t ipPacket[]
Definition: ndp.h:431
NdpNeighborAdvMessage
Definition: ndp.h:351
#define NDP_RTR_SOLICITATION_INTERVAL
Definition: ndp.h:130
NdpMtuOption
Definition: ndp.h:445
@ NDP_STATE_NONE
Definition: ndp.h:249
@ NDP_STATE_DELAY
Definition: ndp.h:253
@ NDP_STATE_REACHABLE
Definition: ndp.h:251
@ NDP_STATE_STALE
Definition: ndp.h:252
@ NDP_STATE_PERMANENT
Definition: ndp.h:255
@ NDP_STATE_INCOMPLETE
Definition: ndp.h:250
NdpOption
Definition: ndp.h:379
NdpPrefixInfoOption
Definition: ndp.h:418
#define NDP_MAX_RTR_SOLICITATIONS
Definition: ndp.h:137
#define NDP_DUP_ADDR_DETECT_TRANSMITS
Definition: ndp.h:158
#define NDP_MAX_RTR_SOLICITATION_DELAY
Definition: ndp.h:123
#define NDP_MIN_RTR_SOLICITATION_DELAY
Definition: ndp.h:116
NdpLinkLayerAddrOption
Definition: ndp.h:391
NdpRouterSolMessage
Definition: ndp.h:278
#define NDP_DELAY_FIRST_PROBE_TIME
Definition: ndp.h:193
#define NDP_HOP_LIMIT
Definition: ndp.h:199
#define NDP_REACHABLE_TIME
Definition: ndp.h:179
@ NDP_OPT_REDIRECTED_HEADER
Definition: ndp.h:219
@ NDP_OPT_SOURCE_LINK_LAYER_ADDR
Definition: ndp.h:216
@ NDP_OPT_PREFIX_INFORMATION
Definition: ndp.h:218
@ NDP_OPT_TARGET_LINK_LAYER_ADDR
Definition: ndp.h:217
@ NDP_OPT_MTU
Definition: ndp.h:220
#define NDP_MAX_PENDING_PACKETS
Definition: ndp.h:67
uint_t ndpSendQueuedPackets(NetInterface *interface, NdpNeighborCacheEntry *entry)
Send packets that are waiting for address resolution.
Definition: ndp_cache.c:350
void ndpFlushDestCache(NetInterface *interface)
Flush Destination Cache.
Definition: ndp_cache.c:532
void ndpFlushNeighborCache(NetInterface *interface)
Flush Neighbor cache.
Definition: ndp_cache.c:315
NdpNeighborCacheEntry * ndpFindNeighborCacheEntry(NetInterface *interface, const Ipv6Addr *ipAddr)
Search the Neighbor cache for a given IPv6 address.
Definition: ndp_cache.c:154
NdpDestCacheEntry * ndpFindDestCacheEntry(NetInterface *interface, const Ipv6Addr *destAddr)
Search the Destination Cache for a given destination address.
Definition: ndp_cache.c:503
NdpNeighborCacheEntry * ndpCreateNeighborCacheEntry(NetInterface *interface)
Create a new entry in the Neighbor cache.
Definition: ndp_cache.c:72
void ndpChangeState(NdpNeighborCacheEntry *entry, NdpState newState)
Update Neighbor cache entry state.
Definition: ndp_cache.c:53
void ndpUpdateNeighborCache(NetInterface *interface)
Periodically update Neighbor cache.
Definition: ndp_cache.c:187
NdpDestCacheEntry * ndpCreateDestCacheEntry(NetInterface *interface)
Create a new entry in the Destination Cache.
Definition: ndp_cache.c:452
Neighbor and destination cache management.
void ndpUpdateDefaultRouterList(NetInterface *interface)
Periodically update Default Router List.
Definition: ndp_misc.c:285
void ndpUpdateAddrList(NetInterface *interface)
Manage the lifetime of IPv6 addresses.
Definition: ndp_misc.c:97
void ndpAddOption(void *message, size_t *messageLen, uint8_t type, const void *value, size_t length)
Append an option to a NDP message.
Definition: ndp_misc.c:593
void ndpUpdatePrefixList(NetInterface *interface)
Periodically update Prefix List.
Definition: ndp_misc.c:249
void * ndpGetOption(uint8_t *options, size_t length, uint8_t type)
Search a NDP message for a given option.
Definition: ndp_misc.c:641
error_t ndpCheckOptions(const uint8_t *options, size_t length)
Check NDP message options.
Definition: ndp_misc.c:683
bool_t ndpIsFirstHopRouter(NetInterface *interface, const Ipv6Addr *destAddr, const Ipv6Addr *nextHop)
Check whether an address is the first-hop router for the specified destination.
Definition: ndp_misc.c:443
void ndpParsePrefixInfoOption(NetInterface *interface, NdpPrefixInfoOption *option)
Parse Prefix Information Option.
Definition: ndp_misc.c:54
Helper functions for NDP (Neighbor Discovery Protocol)
TCP/IP stack core.
#define NetInterface
Definition: net.h:36
#define netMutex
Definition: net_legacy.h:195
void * netBufferAt(const NetBuffer *buffer, size_t offset)
Returns a pointer to the data at the specified position.
Definition: net_mem.c:415
error_t netBufferCopy(NetBuffer *dest, size_t destOffset, const NetBuffer *src, size_t srcOffset, size_t length)
Copy data between multi-part buffers.
Definition: net_mem.c:506
NetBuffer * netBufferAlloc(size_t length)
Allocate a multi-part buffer.
Definition: net_mem.c:243
void netBufferFree(NetBuffer *buffer)
Dispose a multi-part buffer.
Definition: net_mem.c:282
error_t netBufferConcat(NetBuffer *dest, const NetBuffer *src, size_t srcOffset, size_t length)
Concatenate two multi-part buffers.
Definition: net_mem.c:444
error_t netBufferSetLength(NetBuffer *buffer, size_t length)
Adjust the length of a multi-part buffer.
Definition: net_mem.c:322
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
error_t netBufferAppend(NetBuffer *dest, const void *src, size_t length)
Append data a multi-part buffer.
Definition: net_mem.c:588
const NetTxAncillary NET_DEFAULT_TX_ANCILLARY
Definition: net_misc.c:71
uint32_t netGenerateRandRange(uint32_t min, uint32_t max)
Generate a random value in the specified range.
Definition: net_misc.c:914
#define NetTxAncillary
Definition: net_misc.h:36
NetInterface * nicGetLogicalInterface(NetInterface *interface)
Retrieve logical interface.
Definition: nic.c:52
NetInterface * nicGetPhysicalInterface(NetInterface *interface)
Retrieve physical interface.
Definition: nic.c:84
@ NIC_TYPE_6LOWPAN
6LoWPAN interface
Definition: nic.h:87
#define osMemset(p, value, length)
Definition: os_port.h:135
#define timeCompare(t1, t2)
Definition: os_port.h:40
#define MIN(a, b)
Definition: os_port.h:63
#define TRUE
Definition: os_port.h:50
#define FALSE
Definition: os_port.h:46
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
systime_t osGetSystemTime(void)
Retrieve system time.
uint32_t systime_t
System time.
IPv6 Stateless Address Autoconfiguration.
void slaacParseRouterAdv(SlaacContext *context, NdpRouterAdvMessage *message, size_t length)
Parse Router Advertisement message.
Definition: slaac_misc.c:104
Helper functions for SLAAC.
IPv6 address entry.
Definition: ipv6.h:399
bool_t duplicate
The address is a duplicate.
Definition: ipv6.h:402
Ipv6AddrState state
IPv6 address state.
Definition: ipv6.h:401
Ipv6Addr addr
IPv6 address.
Definition: ipv6.h:400
NDP context.
Definition: ndp.h:580
systime_t timestamp
Timestamp to manage retransmissions.
Definition: ndp.h:590
uint_t rtrSolicitationCount
Retransmission counter for RS messages.
Definition: ndp.h:588
uint_t dupAddrDetectTransmits
Maximum number of NS messages sent while performing DAD.
Definition: ndp.h:583
systime_t minRtrSolicitationDelay
Minimum delay before transmitting the first RS message.
Definition: ndp.h:584
uint32_t reachableTime
The time a node assumes a neighbor is reachable.
Definition: ndp.h:581
uint32_t retransTimer
The time between retransmissions of NS messages.
Definition: ndp.h:582
systime_t maxRtrSolicitationDelay
Maximum delay before transmitting the first RS message.
Definition: ndp.h:585
bool_t rtrAdvReceived
Valid RA message received.
Definition: ndp.h:589
systime_t timeout
Timeout value.
Definition: ndp.h:591
uint_t maxRtrSolicitations
Number of retransmissions for RS messages.
Definition: ndp.h:587
bool_t enable
Enable address resolution using Neighbor Discovery protocol.
Definition: ndp.h:592
systime_t rtrSolicitationInterval
Time interval between retransmissions of RS messages.
Definition: ndp.h:586
Destination cache entry.
Definition: ndp.h:567
systime_t timestamp
Timestamp to manage entry lifetime.
Definition: ndp.h:571
size_t pathMtu
Path MTU.
Definition: ndp.h:570
Ipv6Addr nextHop
IPv6 address of the next-hop neighbor.
Definition: ndp.h:569
Ipv6Addr destAddr
Destination IPv6 address.
Definition: ndp.h:568
Neighbor cache entry.
Definition: ndp.h:549
Ipv6Addr ipAddr
Unicast IPv6 address.
Definition: ndp.h:551
bool_t isRouter
A flag indicating whether the neighbor is a router or a host.
Definition: ndp.h:553
NdpQueueItem queue[NDP_MAX_PENDING_PACKETS]
Packets waiting for address resolution to complete.
Definition: ndp.h:557
MacAddr macAddr
Link layer address associated with the IPv6 address.
Definition: ndp.h:552
NdpState state
Reachability state.
Definition: ndp.h:550
uint_t retransmitCount
Retransmission counter.
Definition: ndp.h:556
uint_t queueSize
Number of queued packets.
Definition: ndp.h:558
systime_t timeout
Timeout value.
Definition: ndp.h:555
NetInterface * srcInterface
Interface from which the packet has been received.
Definition: ndp.h:537
NetBuffer * buffer
Packet waiting for address resolution.
Definition: ndp.h:538
size_t offset
Offset to the first byte of the packet.
Definition: ndp.h:539
NetTxAncillary ancillary
Additional options.
Definition: ndp.h:540
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
uint8_t length
Definition: tcp.h:368