A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
icmpv6-l4-protocol.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2007-2009 Strasbourg University
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * Author: Sebastien Vincent <vincent@clarinet.u-strasbg.fr>
19  * David Gross <gdavid.devel@gmail.com>
20  * Mehdi Benamor <benamor.mehdi@ensi.rnu.tn>
21  * Tommaso Pecorella <tommaso.pecorella@unifi.it>
22  */
23 
24 #include "ns3/log.h"
25 #include "ns3/assert.h"
26 #include "ns3/packet.h"
27 #include "ns3/node.h"
28 #include "ns3/boolean.h"
29 #include "ns3/ipv6-routing-protocol.h"
30 #include "ns3/ipv6-route.h"
31 
33 #include "ipv6-l3-protocol.h"
34 #include "ipv6-interface.h"
35 #include "icmpv6-l4-protocol.h"
36 #include "ndisc-cache.h"
37 
38 namespace ns3 {
39 
40 NS_OBJECT_ENSURE_REGISTERED (Icmpv6L4Protocol);
41 
42 NS_LOG_COMPONENT_DEFINE ("Icmpv6L4Protocol");
43 
44 const uint8_t Icmpv6L4Protocol::PROT_NUMBER = 58;
45 
50 const uint32_t Icmpv6L4Protocol::MAX_RA_DELAY_TIME = 500; /* millisecond */
51 
55 
60 const uint32_t Icmpv6L4Protocol::REACHABLE_TIME = 30000;
61 const uint32_t Icmpv6L4Protocol::RETRANS_TIMER = 1000;
63 const double Icmpv6L4Protocol::MIN_RANDOM_FACTOR = 0.5;
64 const double Icmpv6L4Protocol::MAX_RANDOM_FACTOR = 1.5;
65 
67 {
68  static TypeId tid = TypeId ("ns3::Icmpv6L4Protocol")
70  .AddConstructor<Icmpv6L4Protocol> ()
71  .AddAttribute ("DAD", "Always do DAD check.",
72  BooleanValue (true),
73  MakeBooleanAccessor (&Icmpv6L4Protocol::m_alwaysDad),
74  MakeBooleanChecker ())
75  ;
76  return tid;
77 }
78 
80  : m_node (0)
81 {
83 }
84 
86 {
88 }
89 
91 {
93  for (CacheList::const_iterator it = m_cacheList.begin (); it != m_cacheList.end (); it++)
94  {
95  Ptr<NdiscCache> cache = *it;
96  cache->Dispose ();
97  cache = 0;
98  }
99  m_cacheList.clear ();
101 
102  m_node = 0;
104 }
105 
107 {
109  if (m_node == 0)
110  {
111  Ptr<Node> node = this->GetObject<Node> ();
112  if (node != 0)
113  {
114  Ptr<Ipv6L3Protocol> ipv6 = this->GetObject<Ipv6L3Protocol> ();
115  if (ipv6 != 0 && m_downTarget.IsNull ())
116  {
117  SetNode (node);
118  ipv6->Insert (this);
119  Ptr<Ipv6RawSocketFactoryImpl> rawFactory = CreateObject<Ipv6RawSocketFactoryImpl> ();
120  ipv6->AggregateObject (rawFactory);
122  }
123  }
124  }
126 }
127 
129 {
130  NS_LOG_FUNCTION (this << node);
131  m_node = node;
132 }
133 
135 {
137  return PROT_NUMBER;
138 }
139 
141 {
143  return PROT_NUMBER;
144 }
145 
147 {
149  return 1;
150 }
151 
153 {
154  return m_alwaysDad;
155 }
156 
158 {
159  NS_LOG_FUNCTION (this << target << interface);
160  Ipv6Address addr;
162 
163  NS_ASSERT (ipv6);
164 
165  if (!m_alwaysDad)
166  {
167  return;
168  }
169 
170  /* TODO : disable multicast loopback to prevent NS probing to be received by the sender */
171 
172  Ptr<Packet> p = ForgeNS ("::",Ipv6Address::MakeSolicitedAddress (target), target, interface->GetDevice ()->GetAddress ());
173 
174  /* update last packet UID */
175  interface->SetNsDadUid (target, p->GetUid ());
176  interface->Send (p, Ipv6Address::MakeSolicitedAddress (target));
177 }
178 
180 {
181  NS_LOG_FUNCTION (this << packet << header);
183 }
184 
186 {
187  NS_LOG_FUNCTION (this << packet << src << dst << interface);
188  Ptr<Packet> p = packet->Copy ();
189  Ptr<Ipv6> ipv6 = m_node->GetObject<Ipv6> ();
190 
191  /* very ugly! try to find something better in the future */
192  uint8_t type;
193  p->CopyData (&type, sizeof(type));
194 
195  switch (type)
196  {
198  if (ipv6->IsForwarding (ipv6->GetInterfaceForDevice (interface->GetDevice ())))
199  {
200  HandleRS (p, src, dst, interface);
201  }
202  break;
204  if (!ipv6->IsForwarding (ipv6->GetInterfaceForDevice (interface->GetDevice ())))
205  {
206  HandleRA (p, src, dst, interface);
207  }
208  break;
210  HandleNS (p, src, dst, interface);
211  break;
213  HandleNA (p, src, dst, interface);
214  break;
216  HandleRedirection (p, src, dst, interface);
217  break;
219  HandleEchoRequest (p, src, dst, interface);
220  break;
222  // EchoReply does not contain any info about L4
223  // so we can not forward it up.
224  // TODO: implement request / reply consistency check.
225  break;
227  HandleDestinationUnreachable (p, src, dst, interface);
228  break;
230  HandlePacketTooBig (p, src, dst, interface);
231  break;
233  HandleTimeExceeded (p, src, dst, interface);
234  break;
236  HandleParameterError (p, src, dst, interface);
237  break;
238  default:
239  NS_LOG_LOGIC ("Unknown ICMPv6 message type=" << type);
240  break;
241  }
242 
243  return IpL4Protocol::RX_OK;
244 }
245 
247  uint32_t info, Ipv6Header ipHeader,
248  const uint8_t payload[8])
249 {
251 
252  // TODO assuming the ICMP is carrying a extensionless IP packet
253 
254  uint8_t nextHeader = ipHeader.GetNextHeader ();
255 
256  Ptr<IpL4Protocol> l4 = ipv6->GetProtocol (nextHeader);
257  if (l4 != 0)
258  {
259  l4->ReceiveIcmp (source, ipHeader.GetHopLimit (), icmp.GetType (), icmp.GetCode (),
260  info, ipHeader.GetSourceAddress (), ipHeader.GetDestinationAddress (), payload);
261  }
262 }
263 
265 {
266  NS_LOG_FUNCTION (this << packet << src << dst << interface);
267  Icmpv6Echo request;
268  uint8_t* buf = new uint8_t[packet->GetSize ()];
269 
270  packet->RemoveHeader (request);
271  /* XXX IPv6 extension: obtain a fresh copy of data otherwise it crash... */
272  packet->CopyData (buf, packet->GetSize ());
273  Ptr<Packet> p = Create<Packet> (buf, packet->GetSize ());
274 
275  /* if we send message from ff02::* (link-local multicast), we use our link-local address */
276  SendEchoReply (dst.IsMulticast () ? interface->GetLinkLocalAddress ().GetAddress () : dst, src, request.GetId (), request.GetSeq (), p);
277  delete[] buf;
278 }
279 
280 void Icmpv6L4Protocol::HandleRA (Ptr<Packet> packet, Ipv6Address const &src, Ipv6Address const &dst, Ptr<Ipv6Interface> interface)
281 {
282  NS_LOG_FUNCTION (this << packet << src << dst << interface);
283  Ptr<Packet> p = packet->Copy ();
284  Icmpv6RA raHeader;
287  Icmpv6OptionMtu mtuHdr;
289  bool next = true;
290  bool hasLla = false;
291  bool hasMtu = false;
292 
293  p->RemoveHeader (raHeader);
294 
295  while (next == true)
296  {
297  uint8_t type = 0;
298  p->CopyData (&type, sizeof(type));
299 
300  switch (type)
301  {
303  p->RemoveHeader (prefixHdr);
304  ipv6->AddAutoconfiguredAddress (ipv6->GetInterfaceForDevice (interface->GetDevice ()), prefixHdr.GetPrefix (), prefixHdr.GetPrefixLength (),
305  prefixHdr.GetFlags (), prefixHdr.GetValidTime (), prefixHdr.GetPreferredTime (), src);
306  break;
308  /* take in account the first MTU option */
309  if (!hasMtu)
310  {
311  p->RemoveHeader (mtuHdr);
312  hasMtu = true;
313  /* XXX case of multiple prefix on single interface */
314  /* interface->GetDevice ()->SetMtu (m.GetMtu ()); */
315  }
316  break;
318  /* take in account the first LLA option */
319  if (!hasLla)
320  {
321  p->RemoveHeader (llaHdr);
322  ReceiveLLA (llaHdr, src, dst, interface);
323  hasLla = true;
324  }
325  break;
326  default:
327  /* unknow option, quit */
328  next = false;
329  }
330  }
331 }
332 
334 {
335  NS_LOG_FUNCTION (this << lla << src << dst << interface);
336  Address hardwareAddress;
337  NdiscCache::Entry* entry = 0;
338  Ptr<NdiscCache> cache = FindCache (interface->GetDevice ());
339 
340  /* check if we have this address in our cache */
341  entry = cache->Lookup (src);
342 
343  if (!entry)
344  {
345  entry = cache->Add (src);
346  entry->SetRouter (true);
347  entry->SetMacAddress (lla.GetAddress ());
348  entry->MarkReachable ();
349  entry->StartReachableTimer ();
350  }
351  else
352  {
353  std::list<Ptr<Packet> > waiting;
354  if (entry->IsIncomplete ())
355  {
356  entry->StopRetransmitTimer ();
357  // mark it to reachable
358  waiting = entry->MarkReachable (lla.GetAddress ());
359  entry->StopReachableTimer ();
360  entry->StartReachableTimer ();
361  // send out waiting packet
362  for (std::list<Ptr<Packet> >::const_iterator it = waiting.begin (); it != waiting.end (); it++)
363  {
364  cache->GetInterface ()->Send (*it, src);
365  }
366  entry->ClearWaitingPacket ();
367  }
368  else
369  {
370  if (entry->GetMacAddress () != lla.GetAddress ())
371  {
372  entry->SetMacAddress (lla.GetAddress ());
373  entry->MarkStale ();
374  entry->SetRouter (true);
375  }
376  else
377  {
378  if (!entry->IsReachable ())
379  {
380  entry->StopProbeTimer ();
381  entry->StopDelayTimer ();
382  waiting = entry->MarkReachable (lla.GetAddress ());
383  if (entry->IsProbe ())
384  {
385  for (std::list<Ptr<Packet> >::const_iterator it = waiting.begin (); it != waiting.end (); it++)
386  {
387  cache->GetInterface ()->Send (*it, src);
388  }
389  }
390  entry->StopReachableTimer ();
391  entry->StartReachableTimer ();
392  }
393  }
394  }
395  }
396 }
397 
398 void Icmpv6L4Protocol::HandleRS (Ptr<Packet> packet, Ipv6Address const &src, Ipv6Address const &dst, Ptr<Ipv6Interface> interface)
399 {
400  NS_LOG_FUNCTION (this << packet << src << dst << interface);
402  Icmpv6RS rsHeader;
403  packet->RemoveHeader (rsHeader);
404  Address hardwareAddress;
406  NdiscCache::Entry* entry = 0;
407  Ptr<NdiscCache> cache = FindCache (interface->GetDevice ());
408 
409  if (src != Ipv6Address::GetAny ())
410  {
411  /* XXX search all options following the RS header */
412  /* test if the next option is SourceLinkLayerAddress */
413  uint8_t type;
414  packet->CopyData (&type, sizeof(type));
415 
417  {
418  return;
419  }
420  packet->RemoveHeader (lla);
421  NS_LOG_LOGIC ("Cache updated by RS");
422 
423  entry = cache->Lookup (src);
424  if (!entry)
425  {
426  entry = cache->Add (src);
427  entry->SetRouter (false);
428  entry->MarkStale (lla.GetAddress ());
429  }
430  else if (entry->GetMacAddress () != lla.GetAddress ())
431  {
432  entry->MarkStale (lla.GetAddress ());
433  }
434  }
435 }
436 
437 void Icmpv6L4Protocol::HandleNS (Ptr<Packet> packet, Ipv6Address const &src, Ipv6Address const &dst, Ptr<Ipv6Interface> interface)
438 {
439  NS_LOG_FUNCTION (this << packet << src << dst << interface);
440  Icmpv6NS nsHeader ("::");
441  Ipv6InterfaceAddress ifaddr;
442  uint32_t nb = interface->GetNAddresses ();
443  uint32_t i = 0;
444  bool found = false;
445 
446  packet->RemoveHeader (nsHeader);
447 
448  Ipv6Address target = nsHeader.GetIpv6Target ();
449 
450  for (i = 0; i < nb; i++)
451  {
452  ifaddr = interface->GetAddress (i);
453 
454  if (ifaddr.GetAddress () == target)
455  {
456  found = true;
457  break;
458  }
459  }
460 
461  if (!found)
462  {
463  NS_LOG_LOGIC ("Not a NS for us");
464  return;
465  }
466 
467  if (packet->GetUid () == ifaddr.GetNsDadUid ())
468  {
469  /* don't process our own DAD probe */
470  NS_LOG_LOGIC ("Hey we receive our DAD probe!");
471  return;
472  }
473 
475  Address hardwareAddress;
476  NdiscCache::Entry* entry = 0;
477  Ptr<NdiscCache> cache = FindCache (interface->GetDevice ());
478  uint8_t flags = 0;
479 
480  /* XXX search all options following the NS header */
481 
482  if (src != Ipv6Address::GetAny ())
483  {
484  uint8_t type;
485  packet->CopyData (&type, sizeof(type));
486 
488  {
489  return;
490  }
491 
492  /* Get LLA */
493  packet->RemoveHeader (lla);
494 
495  entry = cache->Lookup (src);
496  if (!entry)
497  {
498  entry = cache->Add (src);
499  entry->SetRouter (false);
500  entry->MarkStale (lla.GetAddress ());
501  }
502  else if (entry->GetMacAddress () != lla.GetAddress ())
503  {
504  entry->MarkStale (lla.GetAddress ());
505  }
506 
507  flags = 3; /* S + O flags */
508  }
509  else
510  {
511  /* it means someone do a DAD */
512  flags = 1; /* O flag */
513  }
514 
515  /* send a NA to src */
517 
518  if (ipv6->IsForwarding (ipv6->GetInterfaceForDevice (interface->GetDevice ())))
519  {
520  flags += 4; /* R flag */
521  }
522 
523  hardwareAddress = interface->GetDevice ()->GetAddress ();
524  Ptr<Packet> p = ForgeNA (target.IsLinkLocal () ? interface->GetLinkLocalAddress ().GetAddress () : ifaddr.GetAddress (), src.IsAny () ? Ipv6Address::GetAllNodesMulticast () : src, &hardwareAddress, flags );
525  interface->Send (p, src.IsAny () ? Ipv6Address::GetAllNodesMulticast () : src);
526 
527  /* not a NS for us discard it */
528 }
529 
531 {
532  NS_LOG_FUNCTION (this << src << dst << hardwareAddress);
533  Ptr<Packet> p = Create<Packet> ();
534  Ipv6Header ipHeader;
535  Icmpv6RS rs;
536  Icmpv6OptionLinkLayerAddress llOption (1, hardwareAddress); /* we give our mac address in response */
537 
538  NS_LOG_LOGIC ("Send RS ( from " << src << " to " << dst << ")");
539  p->AddHeader (llOption);
540 
542  p->AddHeader (rs);
543 
544  ipHeader.SetSourceAddress (src);
545  ipHeader.SetDestinationAddress (dst);
546  ipHeader.SetNextHeader (PROT_NUMBER);
547  ipHeader.SetPayloadLength (p->GetSize ());
548  ipHeader.SetHopLimit (255);
549 
550  p->AddHeader (ipHeader);
551 
552  return p;
553 }
554 
556 {
557  NS_LOG_FUNCTION (this << src << dst << id << seq << data);
558  Ptr<Packet> p = data->Copy ();
559  Ipv6Header ipHeader;
560  Icmpv6Echo req (1);
561 
562  req.SetId (id);
563  req.SetSeq (seq);
564 
565  p->AddHeader (req);
566 
567  return p;
568 }
569 
570 void Icmpv6L4Protocol::HandleNA (Ptr<Packet> packet, Ipv6Address const &src, Ipv6Address const &dst, Ptr<Ipv6Interface> interface)
571 {
572  NS_LOG_FUNCTION (this << packet << src << dst << interface);
573  Icmpv6NA naHeader;
575 
576  packet->RemoveHeader (naHeader);
577  Ipv6Address target = naHeader.GetIpv6Target ();
578 
579  Address hardwareAddress;
580  NdiscCache::Entry* entry = 0;
581  Ptr<NdiscCache> cache = FindCache (interface->GetDevice ());
582  std::list<Ptr<Packet> > waiting;
583 
584  /* check if we have something in our cache */
585  entry = cache->Lookup (target);
586 
587  if (!entry)
588  {
589  /* ouch!! we are victim of a DAD */
590  Ipv6InterfaceAddress ifaddr;
591  bool found = false;
592  uint32_t i = 0;
593  uint32_t nb = 0;
594 
595  for (i = 0; i < nb; i++)
596  {
597  if (ifaddr.GetAddress () == target)
598  {
599  found = true;
600  break;
601  }
602  }
603 
604  if (found)
605  {
607  {
608  interface->SetState (ifaddr.GetAddress (), Ipv6InterfaceAddress::INVALID);
609  }
610  }
611  /* we have not initiated any communication with the target so... discard the NA */
612  return;
613  }
614 
615  /* XXX search all options following the NA header */
616  /* Get LLA */
617  uint8_t type;
618  packet->CopyData (&type, sizeof(type));
619 
621  {
622  return;
623  }
624  packet->RemoveHeader (lla);
625 
626  if (entry->IsIncomplete ())
627  {
628  /* we receive a NA so stop the retransmission timer */
629  entry->StopRetransmitTimer ();
630 
631  if (naHeader.GetFlagS ())
632  {
633  /* mark it to reachable */
634  waiting = entry->MarkReachable (lla.GetAddress ());
635  entry->StopReachableTimer ();
636  entry->StartReachableTimer ();
637  /* send out waiting packet */
638  for (std::list<Ptr<Packet> >::const_iterator it = waiting.begin (); it != waiting.end (); it++)
639  {
640  cache->GetInterface ()->Send (*it, src);
641  }
642  entry->ClearWaitingPacket ();
643  }
644  else
645  {
646  entry->MarkStale (lla.GetAddress ());
647  }
648 
649  if (naHeader.GetFlagR ())
650  {
651  entry->SetRouter (true);
652  }
653  }
654  else
655  {
656  /* we receive a NA so stop the probe timer or delay timer if any */
657  entry->StopProbeTimer ();
658  entry->StopDelayTimer ();
659 
660  /* if the Flag O is clear and mac address differs from the cache */
661  if (!naHeader.GetFlagO () && lla.GetAddress () != entry->GetMacAddress ())
662  {
663  if (entry->IsReachable ())
664  {
665  entry->MarkStale ();
666  }
667  return;
668  }
669  else
670  {
671  if ((!naHeader.GetFlagO () && lla.GetAddress () == entry->GetMacAddress ()) || naHeader.GetFlagO ()) /* XXX lake "no target link-layer address option supplied" */
672  {
673  entry->SetMacAddress (lla.GetAddress ());
674 
675  if (naHeader.GetFlagS ())
676  {
677  if (!entry->IsReachable ())
678  {
679  if (entry->IsProbe ())
680  {
681  waiting = entry->MarkReachable (lla.GetAddress ());
682  for (std::list<Ptr<Packet> >::const_iterator it = waiting.begin (); it != waiting.end (); it++)
683  {
684  cache->GetInterface ()->Send (*it, src);
685  }
686  entry->ClearWaitingPacket ();
687  }
688  else
689  {
690  entry->MarkReachable (lla.GetAddress ());
691  }
692  }
693  entry->StopReachableTimer ();
694  entry->StartReachableTimer ();
695  }
696  else if (lla.GetAddress () != entry->GetMacAddress ())
697  {
698  entry->MarkStale ();
699  }
700  entry->SetRouter (naHeader.GetFlagR ());
701  }
702  }
703  }
704 }
705 
707 {
708  NS_LOG_FUNCTION (this << packet << src << dst << interface);
709  bool hasLla = false;
710  Ptr<Packet> p = packet->Copy ();
711  Icmpv6OptionLinkLayerAddress llOptionHeader (0);
712 
713  Icmpv6Redirection redirectionHeader;
714  p->RemoveHeader (redirectionHeader);
715 
716  /* little ugly try to find a better way */
717  uint8_t type;
718  p->CopyData (&type, sizeof(type));
720  {
721  hasLla = true;
722  p->RemoveHeader (llOptionHeader);
723  }
724 
725  Icmpv6OptionRedirected redirectedOptionHeader;
726  p->RemoveHeader (redirectedOptionHeader);
727 
728  Ipv6Address redirTarget = redirectionHeader.GetTarget ();
729  Ipv6Address redirDestination = redirectionHeader.GetDestination ();
730 
731  if (hasLla)
732  {
733  /* update the cache if needed */
734  NdiscCache::Entry* entry = 0;
735  Ptr<NdiscCache> cache = FindCache (interface->GetDevice ());
736 
737  entry = cache->Lookup (redirTarget);
738  if (!entry)
739  {
740  entry = cache->Add (redirTarget);
741  /* destination and target different => necessarily a router */
742  entry->SetRouter (!redirTarget.IsEqual (redirDestination) ? true : false);
743  entry->SetMacAddress (llOptionHeader.GetAddress ());
744  entry->MarkStale ();
745  }
746  else
747  {
748  if (entry->IsIncomplete () || entry->GetMacAddress () != llOptionHeader.GetAddress ())
749  {
750  /* update entry to STALE */
751  if (entry->GetMacAddress () != llOptionHeader.GetAddress ())
752  {
753  entry->SetMacAddress (llOptionHeader.GetAddress ());
754  entry->MarkStale ();
755  }
756  }
757  else
758  {
759  /* stay unchanged */
760  }
761  }
762  }
763 
764  /* add redirection in routing table */
765  Ptr<Ipv6> ipv6 = m_node->GetObject<Ipv6> ();
766 
767  if (redirTarget.IsEqual (redirDestination))
768  {
769  ipv6->GetRoutingProtocol ()->NotifyAddRoute (redirDestination, Ipv6Prefix (128), Ipv6Address ("::"), ipv6->GetInterfaceForAddress (dst));
770  }
771  else
772  {
773  uint32_t ifIndex = ipv6->GetInterfaceForAddress (dst);
774  ipv6->GetRoutingProtocol ()->NotifyAddRoute (redirDestination, Ipv6Prefix (128), redirTarget, ifIndex);
775  }
776 }
777 
779 {
780  NS_LOG_FUNCTION (this << *p << src << dst);
781  Ptr<Packet> pkt = p->Copy ();
782 
784  pkt->RemoveHeader (unreach);
785  Ptr<Packet> origPkt = unreach.GetPacket ();
786 
787  Ipv6Header ipHeader;
788  if ( origPkt->GetSerializedSize () > ipHeader.GetSerializedSize () )
789  {
790  origPkt->RemoveHeader (ipHeader);
791  uint8_t payload[8];
792  origPkt->CopyData (payload, 8);
793  Forward (src, unreach, unreach.GetCode (), ipHeader, payload);
794  }
795 }
796 
798 {
799  NS_LOG_FUNCTION (this << *p << src << dst);
800  Ptr<Packet> pkt = p->Copy ();
801 
802  Icmpv6TimeExceeded timeexceeded;
803  pkt->RemoveHeader (timeexceeded);
804  Ptr<Packet> origPkt = timeexceeded.GetPacket ();
805  Ipv6Header ipHeader;
806  uint8_t payload[8];
807  origPkt->RemoveHeader (ipHeader);
808  origPkt->CopyData (payload, 8);
809 
810  Forward (src, timeexceeded, timeexceeded.GetCode (), ipHeader, payload);
811 }
812 
814 {
815  NS_LOG_FUNCTION (this << *p << src << dst);
816  Ptr<Packet> pkt = p->Copy ();
817 
818  Icmpv6TooBig tooBig;
819  pkt->RemoveHeader (tooBig);
820  Ptr<Packet> origPkt = tooBig.GetPacket ();
821 
822  Ipv6Header ipHeader;
823  origPkt->RemoveHeader (ipHeader);
824  uint8_t payload[8];
825  origPkt->CopyData (payload, 8);
826  Forward (src, tooBig, tooBig.GetMtu (), ipHeader, payload);
827 }
828 
830 {
831  NS_LOG_FUNCTION (this << *p << src << dst);
832  Ptr<Packet> pkt = p->Copy ();
833 
834  Icmpv6ParameterError paramErr;
835  pkt->RemoveHeader (paramErr);
836  Ptr<Packet> origPkt = paramErr.GetPacket ();
837 
838  Ipv6Header ipHeader;
839  origPkt->RemoveHeader (ipHeader);
840  uint8_t payload[8];
841  origPkt->CopyData (payload, 8);
842  Forward (src, paramErr, paramErr.GetCode (), ipHeader, payload);
843 }
844 
846 {
847  NS_LOG_FUNCTION (this << packet << src << dst << (uint32_t)ttl);
849  SocketIpTtlTag tag;
850  NS_ASSERT (ipv6 != 0);
851 
852  tag.SetTtl (ttl);
853  packet->AddPacketTag (tag);
854  m_downTarget (packet, src, dst, PROT_NUMBER, 0);
855 }
856 
857 void Icmpv6L4Protocol::SendMessage (Ptr<Packet> packet, Ipv6Address dst, Icmpv6Header& icmpv6Hdr, uint8_t ttl)
858 {
859  NS_LOG_FUNCTION (this << packet << dst << icmpv6Hdr << (uint32_t)ttl);
861  NS_ASSERT (ipv6 != 0 && ipv6->GetRoutingProtocol () != 0);
862  Ipv6Header header;
863  SocketIpTtlTag tag;
865  Ptr<Ipv6Route> route;
866  Ptr<NetDevice> oif (0); //specify non-zero if bound to a source address
867 
868  header.SetDestinationAddress (dst);
869  route = ipv6->GetRoutingProtocol ()->RouteOutput (packet, header, oif, err);
870 
871  if (route != 0)
872  {
873  NS_LOG_LOGIC ("Route exists");
874  tag.SetTtl (ttl);
875  packet->AddPacketTag (tag);
876  Ipv6Address src = route->GetSource ();
877 
878  icmpv6Hdr.CalculatePseudoHeaderChecksum (src, dst, packet->GetSize () + icmpv6Hdr.GetSerializedSize (), PROT_NUMBER);
879  packet->AddHeader (icmpv6Hdr);
880  m_downTarget (packet, src, dst, PROT_NUMBER, route);
881  }
882  else
883  {
884  NS_LOG_WARN ("drop icmp message");
885  }
886 }
887 
888 void Icmpv6L4Protocol::SendNA (Ipv6Address src, Ipv6Address dst, Address* hardwareAddress, uint8_t flags)
889 {
890  NS_LOG_FUNCTION (this << src << dst << hardwareAddress << flags);
891  Ptr<Packet> p = Create<Packet> ();
892  Icmpv6NA na;
893  Icmpv6OptionLinkLayerAddress llOption (0, *hardwareAddress); /* not a source link layer */
894 
895  NS_LOG_LOGIC ("Send NA ( from " << src << " to " << dst << " target " << src << ")");
896  na.SetIpv6Target (src);
897 
898  if ((flags & 1))
899  {
900  na.SetFlagO (true);
901  }
902  if ((flags & 2) && src != Ipv6Address::GetAny ())
903  {
904  na.SetFlagS (true);
905  }
906  if ((flags & 4))
907  {
908  na.SetFlagR (true);
909  }
910 
911  p->AddHeader (llOption);
912  na.CalculatePseudoHeaderChecksum (src, dst, p->GetSize () + na.GetSerializedSize (), PROT_NUMBER);
913  p->AddHeader (na);
914 
915  SendMessage (p, src, dst, 255);
916 }
917 
918 void Icmpv6L4Protocol::SendEchoReply (Ipv6Address src, Ipv6Address dst, uint16_t id, uint16_t seq, Ptr<Packet> data)
919 {
920  NS_LOG_FUNCTION (this << src << dst << id << seq << data);
921  Ptr<Packet> p = data->Copy ();
922  Icmpv6Echo reply (0); /* echo reply */
923 
924  reply.SetId (id);
925  reply.SetSeq (seq);
926 
927  reply.CalculatePseudoHeaderChecksum (src, dst, p->GetSize () + reply.GetSerializedSize (), PROT_NUMBER);
928  p->AddHeader (reply);
929  SendMessage (p, src, dst, 64);
930 }
931 
932 void Icmpv6L4Protocol::SendNS (Ipv6Address src, Ipv6Address dst, Ipv6Address target, Address hardwareAddress)
933 {
934  NS_LOG_FUNCTION (this << src << dst << target << hardwareAddress);
935  Ptr<Packet> p = Create<Packet> ();
936  /* Ipv6Header ipHeader; */
937  Icmpv6NS ns (target);
938  Icmpv6OptionLinkLayerAddress llOption (1, hardwareAddress); /* we give our mac address in response */
939 
940  /* if the source is unspec, multicast the NA to all-nodes multicast */
941  if (src == Ipv6Address::GetAny ())
942  {
944  }
945 
946  NS_LOG_LOGIC ("Send NS ( from " << src << " to " << dst << " target " << target << ")");
947 
948  p->AddHeader (llOption);
949  ns.CalculatePseudoHeaderChecksum (src, dst, p->GetSize () + ns.GetSerializedSize (), PROT_NUMBER);
950  p->AddHeader (ns);
951  SendMessage (p, src, dst, 255);
952 }
953 
954 void Icmpv6L4Protocol::SendRS (Ipv6Address src, Ipv6Address dst, Address hardwareAddress)
955 {
956  NS_LOG_FUNCTION (this << src << dst << hardwareAddress);
957  Ptr<Packet> p = Create<Packet> ();
958  Icmpv6RS rs;
959  Icmpv6OptionLinkLayerAddress llOption (1, hardwareAddress); /* we give our mac address in response */
960 
961  /* if the source is unspec, multicast the NA to all-nodes multicast */
962  if (src != Ipv6Address::GetAny ())
963  {
964  p->AddHeader (llOption);
965  }
966 
967  NS_LOG_LOGIC ("Send RS ( from " << src << " to " << dst << ")");
968 
969  rs.CalculatePseudoHeaderChecksum (src, dst, p->GetSize () + rs.GetSerializedSize (), PROT_NUMBER);
970  p->AddHeader (rs);
971  SendMessage (p, src, dst, 255);
972 }
973 
975 {
976  NS_LOG_FUNCTION (this << malformedPacket << dst << (uint32_t)code);
977  Ptr<Packet> p = Create<Packet> ();
978  uint32_t malformedPacketSize = malformedPacket->GetSize ();
980 
981  NS_LOG_LOGIC ("Send Destination Unreachable ( to " << dst << " code " << (uint32_t)code << " )");
982 
983  /* 48 = sizeof IPv6 header + sizeof ICMPv6 error header */
984  if (malformedPacketSize <= 1280 - 48)
985  {
986  header.SetPacket (malformedPacket);
987  }
988  else
989  {
990  Ptr<Packet> fragment = malformedPacket->CreateFragment (0, 1280 - 48);
991  header.SetPacket (fragment);
992  }
993 
994  header.SetCode (code);
995  SendMessage (p, dst, header, 255);
996 }
997 
998 void Icmpv6L4Protocol::SendErrorTooBig (Ptr<Packet> malformedPacket, Ipv6Address dst, uint32_t mtu)
999 {
1000  NS_LOG_FUNCTION (this << malformedPacket << dst << mtu);
1001  Ptr<Packet> p = Create<Packet> ();
1002  uint32_t malformedPacketSize = malformedPacket->GetSize ();
1003  Icmpv6TooBig header;
1004 
1005  NS_LOG_LOGIC ("Send Too Big ( to " << dst << " )");
1006 
1007  /* 48 = sizeof IPv6 header + sizeof ICMPv6 error header */
1008  if (malformedPacketSize <= 1280 - 48)
1009  {
1010  header.SetPacket (malformedPacket);
1011  }
1012  else
1013  {
1014  Ptr<Packet> fragment = malformedPacket->CreateFragment (0, 1280 - 48);
1015  header.SetPacket (fragment);
1016  }
1017 
1018  header.SetCode (0);
1019  header.SetMtu (mtu);
1020  SendMessage (p, dst, header, 255);
1021 }
1022 
1023 void Icmpv6L4Protocol::SendErrorTimeExceeded (Ptr<Packet> malformedPacket, Ipv6Address dst, uint8_t code)
1024 {
1025  NS_LOG_FUNCTION (this << malformedPacket << dst << code);
1026  Ptr<Packet> p = Create<Packet> ();
1027  uint32_t malformedPacketSize = malformedPacket->GetSize ();
1028  Icmpv6TimeExceeded header;
1029 
1030  NS_LOG_LOGIC ("Send Time Exceeded ( to " << dst << " code " << (uint32_t)code << " )");
1031 
1032  /* 48 = sizeof IPv6 header + sizeof ICMPv6 error header */
1033  if (malformedPacketSize <= 1280 - 48)
1034  {
1035  header.SetPacket (malformedPacket);
1036  }
1037  else
1038  {
1039  Ptr<Packet> fragment = malformedPacket->CreateFragment (0, 1280 - 48);
1040  header.SetPacket (fragment);
1041  }
1042 
1043  header.SetCode (code);
1044  SendMessage (p, dst, header, 255);
1045 }
1046 
1047 void Icmpv6L4Protocol::SendErrorParameterError (Ptr<Packet> malformedPacket, Ipv6Address dst, uint8_t code, uint32_t ptr)
1048 {
1049  NS_LOG_FUNCTION (this << malformedPacket << dst << code << ptr);
1050  Ptr<Packet> p = Create<Packet> ();
1051  uint32_t malformedPacketSize = malformedPacket->GetSize ();
1052  Icmpv6ParameterError header;
1053 
1054  NS_LOG_LOGIC ("Send Parameter Error ( to " << dst << " code " << (uint32_t)code << " )");
1055 
1056  /* 48 = sizeof IPv6 header + sizeof ICMPv6 error header */
1057  if (malformedPacketSize <= 1280 - 48 )
1058  {
1059  header.SetPacket (malformedPacket);
1060  }
1061  else
1062  {
1063  Ptr<Packet> fragment = malformedPacket->CreateFragment (0, 1280 - 48);
1064  header.SetPacket (fragment);
1065  }
1066 
1067  header.SetCode (code);
1068  header.SetPtr (ptr);
1069  SendMessage (p, dst, header, 255);
1070 }
1071 
1072 void Icmpv6L4Protocol::SendRedirection (Ptr<Packet> redirectedPacket, Ipv6Address dst, Ipv6Address redirTarget, Ipv6Address redirDestination, Address redirHardwareTarget)
1073 {
1074  NS_LOG_FUNCTION (this << redirectedPacket << dst << redirTarget << redirDestination << redirHardwareTarget);
1075  uint32_t llaSize = 0;
1076  Ptr<Packet> p = Create<Packet> ();
1077  uint32_t redirectedPacketSize = redirectedPacket->GetSize ();
1078  Icmpv6OptionLinkLayerAddress llOption (0);
1079 
1080  NS_LOG_LOGIC ("Send Redirection ( to " << dst << " target " << redirTarget << " destination " << redirDestination << " )");
1081 
1082  Icmpv6OptionRedirected redirectedOptionHeader;
1083 
1084  if ((redirectedPacketSize % 8) != 0)
1085  {
1086  Ptr<Packet> pad = Create<Packet> (8 - (redirectedPacketSize % 8));
1087  redirectedPacket->AddAtEnd (pad);
1088  }
1089 
1090  if (redirHardwareTarget.GetLength ())
1091  {
1092  llOption.SetAddress (redirHardwareTarget);
1093  llaSize = llOption.GetSerializedSize ();
1094  }
1095 
1096  /* 56 = sizeof IPv6 header + sizeof ICMPv6 error header + sizeof redirected option */
1097  if (redirectedPacketSize <= (1280 - 56 - llaSize))
1098  {
1099  redirectedOptionHeader.SetPacket (redirectedPacket);
1100  }
1101  else
1102  {
1103  Ptr<Packet> fragment = redirectedPacket->CreateFragment (0, 1280 - 56 - llaSize);
1104  redirectedOptionHeader.SetPacket (fragment);
1105  }
1106 
1107  p->AddHeader (redirectedOptionHeader);
1108 
1109  if (llaSize)
1110  {
1111  p->AddHeader (llOption);
1112  }
1113 
1114  Icmpv6Redirection redirectionHeader;
1115  redirectionHeader.SetTarget (redirTarget);
1116  redirectionHeader.SetDestination (redirDestination);
1117  SendMessage (p, dst, redirectionHeader, 64);
1118 }
1119 
1120 Ptr<Packet> Icmpv6L4Protocol::ForgeNA (Ipv6Address src, Ipv6Address dst, Address* hardwareAddress, uint8_t flags)
1121 {
1122  NS_LOG_FUNCTION (this << src << dst << hardwareAddress << (uint32_t)flags);
1123  Ptr<Packet> p = Create<Packet> ();
1124  Ipv6Header ipHeader;
1125  Icmpv6NA na;
1126  Icmpv6OptionLinkLayerAddress llOption (0, *hardwareAddress); /* we give our mac address in response */
1127 
1128  NS_LOG_LOGIC ("Send NA ( from " << src << " to " << dst << ")");
1129 
1130  /* forge the entire NA packet from IPv6 header to ICMPv6 link-layer option, so that the packet does not pass by Icmpv6L4Protocol::Lookup again */
1131 
1132  p->AddHeader (llOption);
1133  na.SetIpv6Target (src);
1134 
1135  if ((flags & 1))
1136  {
1137  na.SetFlagO (true);
1138  }
1139  if ((flags & 2) && src != Ipv6Address::GetAny ())
1140  {
1141  na.SetFlagS (true);
1142  }
1143  if ((flags & 4))
1144  {
1145  na.SetFlagR (true);
1146  }
1147 
1149  p->AddHeader (na);
1150 
1151  ipHeader.SetSourceAddress (src);
1152  ipHeader.SetDestinationAddress (dst);
1153  ipHeader.SetNextHeader (PROT_NUMBER);
1154  ipHeader.SetPayloadLength (p->GetSize ());
1155  ipHeader.SetHopLimit (255);
1156 
1157  p->AddHeader (ipHeader);
1158 
1159  return p;
1160 }
1161 
1163 {
1164  NS_LOG_FUNCTION (this << src << dst << target << hardwareAddress);
1165  Ptr<Packet> p = Create<Packet> ();
1166  Ipv6Header ipHeader;
1167  Icmpv6NS ns (target);
1168  Icmpv6OptionLinkLayerAddress llOption (1, hardwareAddress); /* we give our mac address in response */
1169 
1170  /* if the source is unspec, multicast the NA to all-nodes multicast */
1171  if (src == Ipv6Address::GetAny ())
1172  {
1174  }
1175 
1176  NS_LOG_LOGIC ("Send NS ( from " << src << " to " << dst << " target " << target << ")");
1177 
1178  p->AddHeader (llOption);
1180  p->AddHeader (ns);
1181 
1182  ipHeader.SetSourceAddress (src);
1183  ipHeader.SetDestinationAddress (dst);
1184  ipHeader.SetNextHeader (PROT_NUMBER);
1185  ipHeader.SetPayloadLength (p->GetSize ());
1186  ipHeader.SetHopLimit (255);
1187 
1188  p->AddHeader (ipHeader);
1189 
1190  return p;
1191 }
1192 
1194 {
1195  NS_LOG_FUNCTION (this << device);
1196 
1197  for (CacheList::const_iterator i = m_cacheList.begin (); i != m_cacheList.end (); i++)
1198  {
1199  if ((*i)->GetDevice () == device)
1200  {
1201  return *i;
1202  }
1203  }
1204 
1205  NS_ASSERT (false);
1206  /* quiet compiler */
1207  return 0;
1208 }
1209 
1211 {
1212  Ptr<NdiscCache> cache = CreateObject<NdiscCache> ();
1213 
1214  cache->SetDevice (device, interface);
1216  m_cacheList.push_back (cache);
1217  return cache;
1218 }
1219 
1220 bool Icmpv6L4Protocol::Lookup (Ipv6Address dst, Ptr<NetDevice> device, Ptr<NdiscCache> cache, Address* hardwareDestination)
1221 {
1222  NS_LOG_FUNCTION (this << dst << device << hardwareDestination);
1223 
1224  if (!cache)
1225  {
1226  /* try to find the cache */
1227  cache = FindCache (device);
1228  }
1229 
1230  return cache->Lookup (dst);
1231 }
1232 
1233 bool Icmpv6L4Protocol::Lookup (Ptr<Packet> p, Ipv6Address dst, Ptr<NetDevice> device, Ptr<NdiscCache> cache, Address* hardwareDestination)
1234 {
1235  NS_LOG_FUNCTION (this << p << dst << device << hardwareDestination);
1236 
1237  if (!cache)
1238  {
1239  /* try to find the cache */
1240  cache = FindCache (device);
1241  }
1242 
1243  NdiscCache::Entry* entry = cache->Lookup (dst);
1244  if (entry)
1245  {
1246  if (entry->IsReachable () || entry->IsDelay ())
1247  {
1248  /* XXX check reachability time */
1249  /* send packet */
1250  *hardwareDestination = entry->GetMacAddress ();
1251  return true;
1252  }
1253  else if (entry->IsStale ())
1254  {
1255  /* start delay timer */
1256  entry->StartDelayTimer ();
1257  entry->MarkDelay ();
1258  *hardwareDestination = entry->GetMacAddress ();
1259  return true;
1260  }
1261  else /* PROBE */
1262  {
1263  /* queue packet */
1264  entry->AddWaitingPacket (p);
1265  return false;
1266  }
1267  }
1268  else
1269  {
1270  /* we contact this node for the first time
1271  * add it to the cache and send an NS
1272  */
1273  Ipv6Address addr;
1274  NdiscCache::Entry* entry = cache->Add (dst);
1275  entry->MarkIncomplete (p);
1276  entry->SetRouter (false);
1277 
1278  if (dst.IsLinkLocal ())
1279  {
1280  addr = cache->GetInterface ()->GetLinkLocalAddress ().GetAddress ();
1281  }
1282  else if (cache->GetInterface ()->GetNAddresses () == 1) /* an interface have at least one address (link-local) */
1283  {
1284  /* try to resolve global address without having global address so return! */
1285  cache->Remove (entry);
1286  return false;
1287  }
1288  else
1289  {
1290  /* find source address that match destination */
1291  addr = cache->GetInterface ()->GetAddressMatchingDestination (dst).GetAddress ();
1292  }
1293 
1294  SendNS (addr, Ipv6Address::MakeSolicitedAddress (dst), dst, cache->GetDevice ()->GetAddress ());
1295 
1296  /* start retransmit timer */
1297  entry->StartRetransmitTimer ();
1298  return false;
1299  }
1300 
1301  return false;
1302 }
1303 
1305 {
1307  NS_LOG_LOGIC (interface << " " << addr);
1308  Ipv6InterfaceAddress ifaddr;
1309  bool found = false;
1310  uint32_t i = 0;
1311  uint32_t nb = interface->GetNAddresses ();
1312 
1313  for (i = 0; i < nb; i++)
1314  {
1315  ifaddr = interface->GetAddress (i);
1316 
1317  if (ifaddr.GetAddress () == addr)
1318  {
1319  found = true;
1320  break;
1321  }
1322  }
1323 
1324  /* for the moment, this function is always called, if we was victim of a DAD the address is INVALID
1325  * and we do not set it to PREFERRED
1326  */
1327  if (found && ifaddr.GetState () != Ipv6InterfaceAddress::INVALID)
1328  {
1329  interface->SetState (ifaddr.GetAddress (), Ipv6InterfaceAddress::PREFERRED);
1330  NS_LOG_LOGIC ("DAD OK, interface in state PREFERRED");
1331 
1332  /* send an RS if our interface is not forwarding (router) and if address is a link-local ones
1333  * (because we will send RS with it)
1334  */
1335  Ptr<Ipv6> ipv6 = icmpv6->m_node->GetObject<Ipv6> ();
1336 
1337  if (!ipv6->IsForwarding (ipv6->GetInterfaceForDevice (interface->GetDevice ())) && addr.IsLinkLocal ())
1338  {
1339  /* XXX because all nodes start at the same time, there will be many of RS arround 1 second of simulation time
1340  * TODO Add random delays before sending RS
1341  */
1343  }
1344  }
1345 }
1346 
1347 void
1349 {
1350 }
1351 
1352 void
1354 {
1355  m_downTarget = callback;
1356 }
1357 
1360 {
1361  return (IpL4Protocol::DownTargetCallback)NULL;
1362 }
1363 
1366 {
1367  return m_downTarget;
1368 }
1369 
1370 } /* namespace ns3 */
1371