void Icmpv6L4Protocol::HandleNA()

in simulation/src/internet/model/icmpv6-l4-protocol.cc [666:803]


void Icmpv6L4Protocol::HandleNA (Ptr<Packet> packet, Ipv6Address const &src, Ipv6Address const &dst, Ptr<Ipv6Interface> interface)
{
  NS_LOG_FUNCTION (this << packet << src << dst << interface);
  Icmpv6NA naHeader;
  Icmpv6OptionLinkLayerAddress lla (1);

  packet->RemoveHeader (naHeader);
  Ipv6Address target = naHeader.GetIpv6Target ();

  Address hardwareAddress;
  NdiscCache::Entry* entry = 0;
  Ptr<NdiscCache> cache = FindCache (interface->GetDevice ());
  std::list<NdiscCache::Ipv6PayloadHeaderPair> waiting;

  /* check if we have something in our cache */
  entry = cache->Lookup (target);

  if (!entry)
    {
      /* ouch!! we might be victim of a DAD */
      
      Ipv6InterfaceAddress ifaddr;
      bool found = false;
      uint32_t i = 0;
      uint32_t nb = interface->GetNAddresses ();

      for (i = 0; i < nb; i++)
        {
          ifaddr = interface->GetAddress (i);
          if (ifaddr.GetAddress () == target)
            {
              found = true;
              break;
            }
        }

      if (found)
        {
          if (ifaddr.GetState () == Ipv6InterfaceAddress::TENTATIVE || ifaddr.GetState () == Ipv6InterfaceAddress::TENTATIVE_OPTIMISTIC)
            {
              interface->SetState (ifaddr.GetAddress (), Ipv6InterfaceAddress::INVALID);
            }
        }

      /* we have not initiated any communication with the target so... discard the NA */
      return;
    }

  /* XXX search all options following the NA header */
  /* Get LLA */
  uint8_t type;
  packet->CopyData (&type, sizeof(type));

  if (type != Icmpv6Header::ICMPV6_OPT_LINK_LAYER_TARGET)
    {
      return;
    }
  packet->RemoveHeader (lla);

  if (entry->IsIncomplete ())
    {
      /* we receive a NA so stop the retransmission timer */
      entry->StopNudTimer ();

      if (naHeader.GetFlagS ())
        {
          /* mark it to reachable */
          waiting = entry->MarkReachable (lla.GetAddress ());
          entry->StartReachableTimer ();
          /* send out waiting packet */
          for (std::list<NdiscCache::Ipv6PayloadHeaderPair>::const_iterator it = waiting.begin (); it != waiting.end (); it++)
            {
              cache->GetInterface ()->Send (it->first, it->second, src);
            }
          entry->ClearWaitingPacket ();
        }
      else
        {
          entry->MarkStale (lla.GetAddress ());
        }

      if (naHeader.GetFlagR ())
        {
          entry->SetRouter (true);
        }
    }
  else
    {
      /* we receive a NA so stop the probe timer or delay timer if any */
      entry->StopNudTimer ();

      /* if the Flag O is clear and mac address differs from the cache */
      if (!naHeader.GetFlagO () && lla.GetAddress () != entry->GetMacAddress ())
        {
          if (entry->IsReachable ())
            {
              entry->MarkStale ();
            }
          return;
        }
      else
        {
          if ((!naHeader.GetFlagO () && lla.GetAddress () == entry->GetMacAddress ()) || naHeader.GetFlagO ()) /* XXX lake "no target link-layer address option supplied" */
            {
              entry->SetMacAddress (lla.GetAddress ());

              if (naHeader.GetFlagS ())
                {
                  if (!entry->IsReachable () || !entry->IsPermanent ())
                    {
                      if (entry->IsProbe ())
                        {
                          waiting = entry->MarkReachable (lla.GetAddress ());
                          for (std::list<NdiscCache::Ipv6PayloadHeaderPair>::const_iterator it = waiting.begin (); it != waiting.end (); it++)
                            {
                              cache->GetInterface ()->Send (it->first, it->second, src);
                            }
                          entry->ClearWaitingPacket ();
                        }
                      else
                        {
                          entry->MarkReachable (lla.GetAddress ());
                        }
                    }
                  if (!entry->IsPermanent ())
                    {
                      entry->StartReachableTimer ();
                    }
                }
              else if (lla.GetAddress () != entry->GetMacAddress ())
                {
                  entry->MarkStale ();
                }
              entry->SetRouter (naHeader.GetFlagR ());
            }
        }
    }
}