in simulation/src/internet/model/icmpv6-l4-protocol.cc [488:613]
void Icmpv6L4Protocol::HandleNS (Ptr<Packet> packet, Ipv6Address const &src, Ipv6Address const &dst, Ptr<Ipv6Interface> interface)
{
NS_LOG_FUNCTION (this << packet << src << dst << interface);
Icmpv6NS nsHeader ("::");
Ipv6InterfaceAddress ifaddr;
uint32_t nb = interface->GetNAddresses ();
uint32_t i = 0;
bool found = false;
packet->RemoveHeader (nsHeader);
Ipv6Address target = nsHeader.GetIpv6Target ();
for (i = 0; i < nb; i++)
{
ifaddr = interface->GetAddress (i);
if (ifaddr.GetAddress () == target)
{
found = true;
break;
}
}
if (!found)
{
NS_LOG_LOGIC ("Not a NS for us");
return;
}
if (packet->GetUid () == ifaddr.GetNsDadUid ())
{
/* don't process our own DAD probe */
NS_LOG_LOGIC ("Hey we receive our DAD probe!");
return;
}
NdiscCache::Entry* entry = 0;
Ptr<NdiscCache> cache = FindCache (interface->GetDevice ());
uint8_t flags = 0;
/* search all options following the NS header */
Icmpv6OptionLinkLayerAddress sllaoHdr (true);
bool next = true;
bool hasSllao = false;
while (next == true)
{
uint8_t type;
packet->CopyData (&type, sizeof (type));
switch (type)
{
case Icmpv6Header::ICMPV6_OPT_LINK_LAYER_SOURCE:
if (!hasSllao)
{
packet->RemoveHeader (sllaoHdr);
hasSllao = true;
}
break;
default:
/* unknow option, quit */
next = false;
}
if (packet->GetSize () == 0)
{
next = false;
}
}
Address replyMacAddress;
if (src != Ipv6Address::GetAny ())
{
entry = cache->Lookup (src);
if (!entry)
{
if (!hasSllao)
{
NS_LOG_LOGIC ("Icmpv6L4Protocol::HandleNS: NS without SLLAO and we do not have a NCE, discarding.");
return;
}
entry = cache->Add (src);
entry->SetRouter (false);
entry->MarkStale (sllaoHdr.GetAddress ());
replyMacAddress = sllaoHdr.GetAddress ();
}
else if (hasSllao && (entry->GetMacAddress () != sllaoHdr.GetAddress ()))
{
entry->MarkStale (sllaoHdr.GetAddress ());
replyMacAddress = sllaoHdr.GetAddress ();
}
else
{
replyMacAddress = entry->GetMacAddress ();
}
flags = 3; /* S + O flags */
}
else
{
/* it's a DAD */
flags = 1; /* O flag */
replyMacAddress = interface->GetDevice ()->GetMulticast (dst);
}
/* send a NA to src */
Ptr<Ipv6L3Protocol> ipv6 = m_node->GetObject<Ipv6L3Protocol> ();
if (ipv6->IsForwarding (ipv6->GetInterfaceForDevice (interface->GetDevice ())))
{
flags += 4; /* R flag */
}
Address hardwareAddress = interface->GetDevice ()->GetAddress ();
NdiscCache::Ipv6PayloadHeaderPair p = ForgeNA (target.IsLinkLocal () ? interface->GetLinkLocalAddress ().GetAddress () : ifaddr.GetAddress (),
src.IsAny () ? dst : src, // DAD replies must go to the multicast group it was sent to.
&hardwareAddress,
flags );
// We must bypass the IPv6 layer, as a NA must be sent regardless of the NCE status (and not change it beyond what we did already).
Ptr<Packet> pkt = p.first;
pkt->AddHeader (p.second);
interface->GetDevice ()->Send (pkt, replyMacAddress, Ipv6L3Protocol::PROT_NUMBER);
}