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