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