void Ipv6L3Protocol::Receive()

in simulation/src/internet/model/ipv6-l3-protocol.cc [934:1085]


void Ipv6L3Protocol::Receive (Ptr<NetDevice> device, Ptr<const Packet> p, uint16_t protocol, const Address &from, const Address &to, NetDevice::PacketType packetType)
{
  NS_LOG_FUNCTION (this << device << p << protocol << from << to << packetType);
  NS_LOG_LOGIC ("Packet from " << from << " received on node " << m_node->GetId ());

  NS_ASSERT_MSG (GetInterfaceForDevice(device) != -1, "Received a packet from an interface that is not known to IPv6");
  uint32_t interface = GetInterfaceForDevice(device);

  Ptr<Ipv6Interface> ipv6Interface = m_interfaces[interface];
  Ptr<Packet> packet = p->Copy ();

  if (ipv6Interface->IsUp ())
    {
      m_rxTrace (packet, this, interface);
    }
  else
    {
      NS_LOG_LOGIC ("Dropping received packet-- interface is down");
      Ipv6Header hdr;
      packet->RemoveHeader (hdr);
      m_dropTrace (hdr, packet, DROP_INTERFACE_DOWN, this, interface);
      return;
    }

  Ipv6Header hdr;
  packet->RemoveHeader (hdr);

  // Trim any residual frame padding from underlying devices
  if (hdr.GetPayloadLength () < packet->GetSize ())
    {
      packet->RemoveAtEnd (packet->GetSize () - hdr.GetPayloadLength ());
    }

  // the packet is valid, we update the NDISC cache entry (if present)
  Ptr<NdiscCache> ndiscCache = ipv6Interface->GetNdiscCache ();
  if (ndiscCache)
    {
      // case one, it's a a direct routing.
      NdiscCache::Entry *entry = ndiscCache->Lookup (hdr.GetSource ());
      if (entry)
        {
          entry->UpdateReachableTimer ();
        }
      else
        {
          // It's not in the direct routing, so it's the router, and it could have multiple IP addresses.
          // In doubt, update all of them.
          // Note: it's a confirmed behavior for Linux routers.
          std::list<NdiscCache::Entry *> entryList = ndiscCache->LookupInverse (from);
          std::list<NdiscCache::Entry *>::iterator iter;
          for (iter = entryList.begin (); iter != entryList.end (); iter ++)
            {
              (*iter)->UpdateReachableTimer ();
            }
        }
    }



  /* forward up to IPv6 raw sockets */
  for (SocketList::iterator it = m_sockets.begin (); it != m_sockets.end (); ++it)
    {
      Ptr<Ipv6RawSocketImpl> socket = *it;
      socket->ForwardUp (packet, hdr, device);
    }

  Ptr<Ipv6ExtensionDemux> ipv6ExtensionDemux = m_node->GetObject<Ipv6ExtensionDemux> ();
  Ptr<Ipv6Extension> ipv6Extension = 0;
  uint8_t nextHeader = hdr.GetNextHeader ();
  bool stopProcessing = false;
  bool isDropped = false;
  DropReason dropReason;

  if (nextHeader == Ipv6Header::IPV6_EXT_HOP_BY_HOP)
    {
      ipv6Extension = ipv6ExtensionDemux->GetExtension (nextHeader);

      if (ipv6Extension)
        {
          ipv6Extension->Process (packet, 0, hdr, hdr.GetDestination (), (uint8_t *)0, stopProcessing, isDropped, dropReason);
        }

      if (isDropped)
        {
          m_dropTrace (hdr, packet, dropReason, this, interface);
        }

      if (stopProcessing)
        {
          return;
        }
    }

  if (hdr.GetDestination ().IsAllNodesMulticast ())
    {
      LocalDeliver (packet, hdr, interface);
      return;
    }
  else if (hdr.GetDestination ().IsAllRoutersMulticast() && ipv6Interface->IsForwarding ())
    {
      LocalDeliver (packet, hdr, interface);
      return;
    }
  else if (hdr.GetDestination ().IsMulticast ())
    {
      bool isSolicited = ipv6Interface->IsSolicitedMulticastAddress (hdr.GetDestination ());
      bool isRegisteredOnInterface = IsRegisteredMulticastAddress (hdr.GetDestination (), interface);
      bool isRegisteredGlobally = IsRegisteredMulticastAddress (hdr.GetDestination ());
      if (isSolicited || isRegisteredGlobally || isRegisteredOnInterface)
        {
          LocalDeliver (packet, hdr, interface);
          // do not return, the packet could be handled by a routing protocol
        }
    }


  for (uint32_t j = 0; j < GetNInterfaces (); j++)
    {
      if (j == interface || !m_strongEndSystemModel)
        {
          for (uint32_t i = 0; i < GetNAddresses (j); i++)
            {
              Ipv6InterfaceAddress iaddr = GetAddress (j, i);
              Ipv6Address addr = iaddr.GetAddress ();
              if (addr == hdr.GetDestination ())
                {
                  if (j == interface)
                    {
                      NS_LOG_LOGIC ("For me (destination " << addr << " match)");
                    }
                  else
                    {
                      NS_LOG_LOGIC ("For me (destination " << addr << " match) on another interface " << hdr.GetDestination ());
                    }
                  LocalDeliver (packet, hdr, interface);
                  return;
                }
              NS_LOG_LOGIC ("Address " << addr << " not a match");
            }
        }
    }

  if (!m_routingProtocol->RouteInput (packet, hdr, device,
                                      MakeCallback (&Ipv6L3Protocol::IpForward, this),
                                      MakeCallback (&Ipv6L3Protocol::IpMulticastForward, this),
                                      MakeCallback (&Ipv6L3Protocol::LocalDeliver, this),
                                      MakeCallback (&Ipv6L3Protocol::RouteInputError, this)))
    {
      NS_LOG_WARN ("No route found for forwarding packet.  Drop.");
      // Drop trace and ICMPs are courtesy of RouteInputError
    }
}