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