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