void Ipv6ExtensionFragment::GetFragments()

in simulation/src/internet/model/ipv6-extension.cc [419:590]


void Ipv6ExtensionFragment::GetFragments (Ptr<Packet> packet, Ipv6Header ipv6Header, uint32_t maxFragmentSize, std::list<Ipv6PayloadHeaderPair>& listFragments)
{
  NS_LOG_FUNCTION (this << packet << ipv6Header << maxFragmentSize);
  Ptr<Packet> p = packet->Copy ();

  uint8_t nextHeader = ipv6Header.GetNextHeader ();
  uint8_t ipv6HeaderSize = ipv6Header.GetSerializedSize ();

  uint8_t type;
  p->CopyData (&type, sizeof(type));

  bool moreHeader = true;
  if (!(nextHeader == Ipv6Header::IPV6_EXT_HOP_BY_HOP || nextHeader == Ipv6Header::IPV6_EXT_ROUTING
        || (nextHeader == Ipv6Header::IPV6_EXT_DESTINATION && type == Ipv6Header::IPV6_EXT_ROUTING)))
    {
      moreHeader = false;
      ipv6Header.SetNextHeader (Ipv6Header::IPV6_EXT_FRAGMENTATION);
    }

  std::list<std::pair<Ipv6ExtensionHeader *, uint8_t> > unfragmentablePart;
  uint32_t unfragmentablePartSize = 0;

  Ptr<Ipv6ExtensionDemux> extensionDemux = GetNode ()->GetObject<Ipv6ExtensionDemux> ();
  Ptr<Ipv6Extension> extension = extensionDemux->GetExtension (nextHeader);
  uint8_t extensionHeaderLength;

  while (moreHeader)
    {
      if (nextHeader == Ipv6Header::IPV6_EXT_HOP_BY_HOP)
        {
          Ipv6ExtensionHopByHopHeader *hopbyhopHeader = new Ipv6ExtensionHopByHopHeader ();
          p->RemoveHeader (*hopbyhopHeader);

          nextHeader = hopbyhopHeader->GetNextHeader ();
          extensionHeaderLength = hopbyhopHeader->GetLength ();

          uint8_t type;
          p->CopyData (&type, sizeof(type));

          if (!(nextHeader == Ipv6Header::IPV6_EXT_HOP_BY_HOP || nextHeader == Ipv6Header::IPV6_EXT_ROUTING
                || (nextHeader == Ipv6Header::IPV6_EXT_DESTINATION && type == Ipv6Header::IPV6_EXT_ROUTING)))
            {
              moreHeader = false;
              hopbyhopHeader->SetNextHeader (Ipv6Header::IPV6_EXT_FRAGMENTATION);
            }

          unfragmentablePart.emplace_back (hopbyhopHeader, Ipv6Header::IPV6_EXT_HOP_BY_HOP);
          unfragmentablePartSize += extensionHeaderLength;
        }
      else if (nextHeader == Ipv6Header::IPV6_EXT_ROUTING)
        {
          uint8_t buf[2];
          p->CopyData (buf, sizeof(buf));
          uint8_t numberAddress = buf[1] / 2;
          Ipv6ExtensionLooseRoutingHeader *routingHeader = new Ipv6ExtensionLooseRoutingHeader ();
          routingHeader->SetNumberAddress (numberAddress);
          p->RemoveHeader (*routingHeader);

          nextHeader = routingHeader->GetNextHeader ();
          extensionHeaderLength = routingHeader->GetLength ();

          uint8_t type;
          p->CopyData (&type, sizeof(type));
          if (!(nextHeader == Ipv6Header::IPV6_EXT_HOP_BY_HOP || nextHeader == Ipv6Header::IPV6_EXT_ROUTING
                || (nextHeader == Ipv6Header::IPV6_EXT_DESTINATION && type == Ipv6Header::IPV6_EXT_ROUTING)))
            {
              moreHeader = false;
              routingHeader->SetNextHeader (Ipv6Header::IPV6_EXT_FRAGMENTATION);
            }

          unfragmentablePart.emplace_back (routingHeader, Ipv6Header::IPV6_EXT_ROUTING);
          unfragmentablePartSize += extensionHeaderLength;
        }
      else if (nextHeader == Ipv6Header::IPV6_EXT_DESTINATION)
        {
          Ipv6ExtensionDestinationHeader *destinationHeader = new Ipv6ExtensionDestinationHeader ();
          p->RemoveHeader (*destinationHeader);

          nextHeader = destinationHeader->GetNextHeader ();
          extensionHeaderLength = destinationHeader->GetLength ();

          uint8_t type;
          p->CopyData (&type, sizeof(type));
          if (!(nextHeader == Ipv6Header::IPV6_EXT_HOP_BY_HOP || nextHeader == Ipv6Header::IPV6_EXT_ROUTING
                || (nextHeader == Ipv6Header::IPV6_EXT_DESTINATION && type == Ipv6Header::IPV6_EXT_ROUTING)))
            {
              moreHeader = false;
              destinationHeader->SetNextHeader (Ipv6Header::IPV6_EXT_FRAGMENTATION);
            }

          unfragmentablePart.emplace_back (destinationHeader, Ipv6Header::IPV6_EXT_DESTINATION);
          unfragmentablePartSize += extensionHeaderLength;
        }
    }

  Ipv6ExtensionFragmentHeader fragmentHeader;
  uint8_t fragmentHeaderSize = fragmentHeader.GetSerializedSize ();

  uint32_t maxFragmentablePartSize = maxFragmentSize - ipv6HeaderSize - unfragmentablePartSize - fragmentHeaderSize;
  uint32_t currentFragmentablePartSize = 0;

  bool moreFragment = true;
  uint32_t identification = (uint32_t) m_uvar->GetValue (0, (uint32_t)-1);
  uint16_t offset = 0;

  do
    {
      if (p->GetSize () > offset + maxFragmentablePartSize)
        {
          moreFragment = true;
          currentFragmentablePartSize = maxFragmentablePartSize;
          currentFragmentablePartSize -= currentFragmentablePartSize % 8;
        }
      else
        {
          moreFragment = false;
          currentFragmentablePartSize = p->GetSize () - offset;
        }


      fragmentHeader.SetNextHeader (nextHeader);
      fragmentHeader.SetOffset (offset);
      fragmentHeader.SetMoreFragment (moreFragment);
      fragmentHeader.SetIdentification (identification);

      Ptr<Packet> fragment = p->CreateFragment (offset, currentFragmentablePartSize);
      offset += currentFragmentablePartSize;

      fragment->AddHeader (fragmentHeader);

      for (std::list<std::pair<Ipv6ExtensionHeader *, uint8_t> >::iterator it = unfragmentablePart.begin (); it != unfragmentablePart.end (); it++)
        {
          if (it->second == Ipv6Header::IPV6_EXT_HOP_BY_HOP)
            {
              Ipv6ExtensionHopByHopHeader * p =
                dynamic_cast<Ipv6ExtensionHopByHopHeader *> (it->first);
              NS_ASSERT (p != 0);
              fragment->AddHeader (*p);
            }
          else if (it->second == Ipv6Header::IPV6_EXT_ROUTING)
            {
              Ipv6ExtensionLooseRoutingHeader * p =
                dynamic_cast<Ipv6ExtensionLooseRoutingHeader *> (it->first);
              NS_ASSERT (p != 0);
              fragment->AddHeader (*p);
            }
          else if (it->second == Ipv6Header::IPV6_EXT_DESTINATION)
            {
              Ipv6ExtensionDestinationHeader * p =
                dynamic_cast<Ipv6ExtensionDestinationHeader *> (it->first);
              NS_ASSERT (p != 0);
              fragment->AddHeader (*p);
            }
        }

      ipv6Header.SetPayloadLength (fragment->GetSize ());

      std::ostringstream oss;
      oss << ipv6Header;
      fragment->Print (oss);

      listFragments.emplace_back (fragment, ipv6Header);
    }
  while (moreFragment);

  for (std::list<std::pair<Ipv6ExtensionHeader *, uint8_t> >::iterator it = unfragmentablePart.begin (); it != unfragmentablePart.end (); it++)
    {
      delete it->first;
    }

  unfragmentablePart.clear ();
}