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 ());
}
}
}
}