/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /* vim: set ts=2 sw=2 sta expandtab ai si cin: */ /* * Copyright (c) 2009 Drexel University * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation; * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Author: Tom Wambold */ /* These classes implement RFC 5444 - The Generalized Mobile Ad Hoc Network * (MANET) Packet/PbbMessage Format * See: http://tools.ietf.org/html/rfc5444 for details */ #include "ns3/ipv4-address.h" #include "ns3/ipv6-address.h" #include "ns3/assert.h" #include "packetbb.h" static const uint8_t VERSION = 0; /* Packet flags */ static const uint8_t PHAS_SEQ_NUM = 0x8; static const uint8_t PHAS_TLV = 0x4; /* PbbMessage flags */ static const uint8_t MHAS_ORIG = 0x80; static const uint8_t MHAS_HOP_LIMIT = 0x40; static const uint8_t MHAS_HOP_COUNT = 0x20; static const uint8_t MHAS_SEQ_NUM = 0x10; /* Address block flags */ static const uint8_t AHAS_HEAD = 0x80; static const uint8_t AHAS_FULL_TAIL = 0x40; static const uint8_t AHAS_ZERO_TAIL = 0x20; static const uint8_t AHAS_SINGLE_PRE_LEN = 0x10; static const uint8_t AHAS_MULTI_PRE_LEN = 0x08; /* TLV Flags */ static const uint8_t THAS_TYPE_EXT = 0x80; static const uint8_t THAS_SINGLE_INDEX = 0x40; static const uint8_t THAS_MULTI_INDEX = 0x20; static const uint8_t THAS_VALUE = 0x10; static const uint8_t THAS_EXT_LEN = 0x08; static const uint8_t TIS_MULTIVALUE = 0x04; namespace ns3 { NS_OBJECT_ENSURE_REGISTERED (PbbPacket); PbbTlvBlock::PbbTlvBlock (void) { return; } PbbTlvBlock::~PbbTlvBlock (void) { Clear (); } PbbTlvBlock::Iterator PbbTlvBlock::Begin (void) { return m_tlvList.begin (); } PbbTlvBlock::ConstIterator PbbTlvBlock::Begin (void) const { return m_tlvList.begin (); } PbbTlvBlock::Iterator PbbTlvBlock::End (void) { return m_tlvList.end (); } PbbTlvBlock::ConstIterator PbbTlvBlock::End (void) const { return m_tlvList.end (); } int PbbTlvBlock::Size (void) const { return m_tlvList.size (); } bool PbbTlvBlock::Empty (void) const { return m_tlvList.empty (); } Ptr PbbTlvBlock::Front (void) const { return m_tlvList.front (); } Ptr PbbTlvBlock::Back (void) const { return m_tlvList.back (); } void PbbTlvBlock::PushFront (Ptr tlv) { m_tlvList.push_front (tlv); } void PbbTlvBlock::PopFront (void) { m_tlvList.pop_front (); } void PbbTlvBlock::PushBack (Ptr tlv) { m_tlvList.push_back (tlv); } void PbbTlvBlock::PopBack (void) { m_tlvList.pop_back (); } PbbTlvBlock::Iterator PbbTlvBlock::Insert (PbbTlvBlock::Iterator position, const Ptr tlv) { return m_tlvList.insert (position, tlv); } PbbTlvBlock::Iterator PbbTlvBlock::Erase (PbbTlvBlock::Iterator position) { return m_tlvList.erase (position); } PbbTlvBlock::Iterator PbbTlvBlock::Erase (PbbTlvBlock::Iterator first, PbbTlvBlock::Iterator last) { return m_tlvList.erase (first, last); } void PbbTlvBlock::Clear (void) { for (Iterator iter = Begin (); iter != End (); iter++) { *iter = 0; } m_tlvList.clear (); } uint32_t PbbTlvBlock::GetSerializedSize (void) const { /* tlv size */ uint32_t size = 2; for (ConstIterator iter = Begin (); iter != End (); iter++) { size += (*iter)->GetSerializedSize (); } return size; } void PbbTlvBlock::Serialize (Buffer::Iterator &start) const { if (Empty ()) { start.WriteHtonU16 (0); return; } /* We need to write the size of the TLV block in front, so save its * position. */ Buffer::Iterator tlvsize = start; start.Next (2); for (ConstIterator iter = Begin (); iter != End (); iter++) { (*iter)->Serialize (start); } /* - 2 to not include the size field */ uint16_t size = start.GetDistanceFrom (tlvsize) - 2; tlvsize.WriteHtonU16 (size); } void PbbTlvBlock::Deserialize (Buffer::Iterator &start) { uint16_t size = start.ReadNtohU16 (); Buffer::Iterator tlvstart = start; if (size > 0) { while (start.GetDistanceFrom (tlvstart) < size) { Ptr newtlv = Create (); newtlv->Deserialize (start); PushBack (newtlv); } } } void PbbTlvBlock::Print (std::ostream &os) const { Print (os, 0); } void PbbTlvBlock::Print (std::ostream &os, int level) const { std::string prefix = ""; for (int i = 0; i < level; i++) { prefix.append("\t"); } os << prefix << "TLV Block {" << std::endl; os << prefix << "\tsize = " << Size () << std::endl; os << prefix << "\tmembers [" << std::endl; for (ConstIterator iter = Begin (); iter != End (); iter++) { (*iter)->Print (os, level+2); } os << prefix << "\t]" << std::endl; os << prefix << "}" << std::endl; } bool PbbTlvBlock::operator== (const PbbTlvBlock &other) const { if (Size () != other.Size ()) { return false; } ConstIterator ti, oi; for (ti = Begin (), oi = other.Begin (); ti != End () && oi != other.End (); ti++, oi++) { if (**ti != **oi) { return false; } } return true; } bool PbbTlvBlock::operator!= (const PbbTlvBlock &other) const { return !(*this == other); } /* End PbbTlvBlock class */ PbbAddressTlvBlock::PbbAddressTlvBlock (void) { return; } PbbAddressTlvBlock::~PbbAddressTlvBlock (void) { Clear (); } PbbAddressTlvBlock::Iterator PbbAddressTlvBlock::Begin (void) { return m_tlvList.begin (); } PbbAddressTlvBlock::ConstIterator PbbAddressTlvBlock::Begin (void) const { return m_tlvList.begin (); } PbbAddressTlvBlock::Iterator PbbAddressTlvBlock::End (void) { return m_tlvList.end (); } PbbAddressTlvBlock::ConstIterator PbbAddressTlvBlock::End (void) const { return m_tlvList.end (); } int PbbAddressTlvBlock::Size (void) const { return m_tlvList.size (); } bool PbbAddressTlvBlock::Empty (void) const { return m_tlvList.empty (); } Ptr PbbAddressTlvBlock::Front (void) const { return m_tlvList.front (); } Ptr PbbAddressTlvBlock::Back (void) const { return m_tlvList.back (); } void PbbAddressTlvBlock::PushFront (Ptr tlv) { m_tlvList.push_front (tlv); } void PbbAddressTlvBlock::PopFront (void) { m_tlvList.pop_front (); } void PbbAddressTlvBlock::PushBack (Ptr tlv) { m_tlvList.push_back (tlv); } void PbbAddressTlvBlock::PopBack (void) { m_tlvList.pop_back (); } PbbAddressTlvBlock::Iterator PbbAddressTlvBlock::Insert (PbbAddressTlvBlock::Iterator position, const Ptr tlv) { return m_tlvList.insert (position, tlv); } PbbAddressTlvBlock::Iterator PbbAddressTlvBlock::Erase (PbbAddressTlvBlock::Iterator position) { return m_tlvList.erase (position); } PbbAddressTlvBlock::Iterator PbbAddressTlvBlock::Erase (PbbAddressTlvBlock::Iterator first, PbbAddressTlvBlock::Iterator last) { return m_tlvList.erase (first, last); } void PbbAddressTlvBlock::Clear (void) { for (Iterator iter = Begin (); iter != End (); iter++) { *iter = 0; } m_tlvList.clear (); } uint32_t PbbAddressTlvBlock::GetSerializedSize (void) const { /* tlv size */ uint32_t size = 2; for (ConstIterator iter = Begin (); iter != End (); iter++) { size += (*iter)->GetSerializedSize (); } return size; } void PbbAddressTlvBlock::Serialize (Buffer::Iterator &start) const { if (Empty ()) { start.WriteHtonU16 (0); return; } /* We need to write the size of the TLV block in front, so save its * position. */ Buffer::Iterator tlvsize = start; start.Next (2); for (ConstIterator iter = Begin (); iter != End (); iter++) { (*iter)->Serialize (start); } /* - 2 to not include the size field */ uint16_t size = start.GetDistanceFrom (tlvsize) - 2; tlvsize.WriteHtonU16 (size); } void PbbAddressTlvBlock::Deserialize (Buffer::Iterator &start) { uint16_t size = start.ReadNtohU16 (); Buffer::Iterator tlvstart = start; if (size > 0) { while (start.GetDistanceFrom (tlvstart) < size) { Ptr newtlv = Create (); newtlv->Deserialize (start); PushBack (newtlv); } } } void PbbAddressTlvBlock::Print (std::ostream &os) const { Print (os, 0); } void PbbAddressTlvBlock::Print (std::ostream &os, int level) const { std::string prefix = ""; for (int i = 0; i < level; i++) { prefix.append("\t"); } os << prefix << "TLV Block {" << std::endl; os << prefix << "\tsize = " << Size () << std::endl; os << prefix << "\tmembers [" << std::endl; for (ConstIterator iter = Begin (); iter != End (); iter++) { (*iter)->Print (os, level+2); } os << prefix << "\t]" << std::endl; os << prefix << "}" << std::endl; } bool PbbAddressTlvBlock::operator== (const PbbAddressTlvBlock &other) const { if (Size () != other.Size ()) { return false; } ConstIterator it, ot; for (it = Begin (), ot = other.Begin (); it != End () && ot != other.End (); it++, ot++) { if (**it != **ot) { return false; } } return true; } bool PbbAddressTlvBlock::operator!= (const PbbAddressTlvBlock &other) const { return !(*this == other); } /* End PbbAddressTlvBlock Class */ PbbPacket::PbbPacket (void) { m_refCount = 1; m_version = VERSION; m_hasseqnum = false; } PbbPacket::~PbbPacket (void) { MessageClear (); } uint8_t PbbPacket::GetVersion (void) const { return m_version; } void PbbPacket::SetSequenceNumber (uint16_t number) { m_seqnum = number; m_hasseqnum = true; } uint16_t PbbPacket::GetSequenceNumber (void) const { NS_ASSERT (HasSequenceNumber ()); return m_seqnum; } bool PbbPacket::HasSequenceNumber (void) const { return m_hasseqnum; } /* Manipulating Packet TLVs */ PbbPacket::TlvIterator PbbPacket::TlvBegin (void) { return m_tlvList.Begin (); } PbbPacket::ConstTlvIterator PbbPacket::TlvBegin (void) const { return m_tlvList.Begin (); } PbbPacket::TlvIterator PbbPacket::TlvEnd (void) { return m_tlvList.End (); } PbbPacket::ConstTlvIterator PbbPacket::TlvEnd (void) const { return m_tlvList.End (); } int PbbPacket::TlvSize (void) const { return m_tlvList.Size (); } bool PbbPacket::TlvEmpty (void) const { return m_tlvList.Empty (); } Ptr PbbPacket::TlvFront (void) { return m_tlvList.Front (); } const Ptr PbbPacket::TlvFront (void) const { return m_tlvList.Front (); } Ptr PbbPacket::TlvBack (void) { return m_tlvList.Back (); } const Ptr PbbPacket::TlvBack (void) const { return m_tlvList.Back (); } void PbbPacket::TlvPushFront (Ptr tlv) { m_tlvList.PushFront (tlv); } void PbbPacket::TlvPopFront (void) { m_tlvList.PopFront (); } void PbbPacket::TlvPushBack (Ptr tlv) { m_tlvList.PushBack (tlv); } void PbbPacket::TlvPopBack (void) { m_tlvList.PopBack (); } PbbPacket::TlvIterator PbbPacket::Erase (PbbPacket::TlvIterator position) { return m_tlvList.Erase (position); } PbbPacket::TlvIterator PbbPacket::Erase (PbbPacket::TlvIterator first, PbbPacket::TlvIterator last) { return m_tlvList.Erase (first, last); } void PbbPacket::TlvClear (void) { m_tlvList.Clear (); } /* Manipulating Packet Messages */ PbbPacket::MessageIterator PbbPacket::MessageBegin (void) { return m_messageList.begin (); } PbbPacket::ConstMessageIterator PbbPacket::MessageBegin (void) const { return m_messageList.begin (); } PbbPacket::MessageIterator PbbPacket::MessageEnd (void) { return m_messageList.end (); } PbbPacket::ConstMessageIterator PbbPacket::MessageEnd (void) const { return m_messageList.end (); } int PbbPacket::MessageSize (void) const { return m_messageList.size (); } bool PbbPacket::MessageEmpty (void) const { return m_messageList.empty (); } Ptr PbbPacket::MessageFront (void) { return m_messageList.front (); } const Ptr PbbPacket::MessageFront (void) const { return m_messageList.front (); } Ptr PbbPacket::MessageBack (void) { return m_messageList.back (); } const Ptr PbbPacket::MessageBack (void) const { return m_messageList.back (); } void PbbPacket::MessagePushFront (Ptr tlv) { m_messageList.push_front (tlv); } void PbbPacket::MessagePopFront (void) { m_messageList.pop_front (); } void PbbPacket::MessagePushBack (Ptr tlv) { m_messageList.push_back (tlv); } void PbbPacket::MessagePopBack (void) { m_messageList.pop_back (); } PbbPacket::MessageIterator PbbPacket::Erase (PbbPacket::MessageIterator position) { return m_messageList.erase (position); } PbbPacket::MessageIterator PbbPacket::Erase (PbbPacket::MessageIterator first, PbbPacket::MessageIterator last) { return m_messageList.erase (first, last); } void PbbPacket::MessageClear (void) { for (MessageIterator iter = MessageBegin (); iter != MessageEnd (); iter++) { *iter = 0; } m_messageList.clear (); } void PbbPacket::Ref (void) const { m_refCount++; } void PbbPacket::Unref (void) const { m_refCount--; if (m_refCount == 0) { delete this; } } TypeId PbbPacket::GetTypeId (void) { static TypeId tid = TypeId ("ns3::PbbPacket") .SetParent
() .AddConstructor () ; return tid; } TypeId PbbPacket::GetInstanceTypeId (void) const { return GetTypeId (); } uint32_t PbbPacket::GetSerializedSize (void) const { /* Version number + flags */ uint32_t size = 1; if (HasSequenceNumber()) { size += 2; } if (!TlvEmpty ()) { size += m_tlvList.GetSerializedSize (); } for (ConstMessageIterator iter = MessageBegin (); iter != MessageEnd (); iter++) { size += (*iter)->GetSerializedSize (); } return size; } void PbbPacket::Serialize (Buffer::Iterator start) const { /* We remember the start, so we can write the flags after we check for a * sequence number and TLV. */ Buffer::Iterator bufref = start; start.Next (); uint8_t flags = VERSION; /* Make room for 4 bit flags */ flags <<= 4; if (HasSequenceNumber ()) { flags |= PHAS_SEQ_NUM; start.WriteHtonU16 (GetSequenceNumber ()); } if (!TlvEmpty ()) { flags |= PHAS_TLV; m_tlvList.Serialize (start); } bufref.WriteU8(flags); for (ConstMessageIterator iter = MessageBegin (); iter != MessageEnd (); iter++) { (*iter)->Serialize (start); } } uint32_t PbbPacket::Deserialize (Buffer::Iterator start) { Buffer::Iterator begin = start; uint8_t flags = start.ReadU8 (); if (flags & PHAS_SEQ_NUM) { SetSequenceNumber (start.ReadNtohU16 ()); } if (flags & PHAS_TLV) { m_tlvList.Deserialize (start); } while (!start.IsEnd()) { Ptr newmsg = PbbMessage::DeserializeMessage (start); if (newmsg == 0) { return start.GetDistanceFrom (begin); } MessagePushBack (newmsg); } flags >>= 4; m_version = flags; return start.GetDistanceFrom (begin); } void PbbPacket::Print (std::ostream &os) const { os << "PbbPacket {" << std::endl; if (HasSequenceNumber ()) { os << "\tsequence number = " << GetSequenceNumber (); } os << std::endl; m_tlvList.Print (os, 1); for (ConstMessageIterator iter = MessageBegin (); iter != MessageEnd (); iter++) { (*iter)->Print (os, 1); } os << "}" << std::endl; } bool PbbPacket::operator== (const PbbPacket &other) const { if (GetVersion () != other.GetVersion ()) { return false; } if (HasSequenceNumber () != other.HasSequenceNumber ()) { return false; } if (HasSequenceNumber ()) { if (GetSequenceNumber () != other.GetSequenceNumber ()) return false; } if (m_tlvList != other.m_tlvList) { return false; } if (MessageSize () != other.MessageSize ()) { return false; } ConstMessageIterator tmi, omi; for (tmi = MessageBegin (), omi = other.MessageBegin (); tmi != MessageEnd () && omi != other.MessageEnd (); tmi++, omi++) { if (**tmi != **omi) { return false; } } return true; } bool PbbPacket::operator!= (const PbbPacket &other) const { return !(*this == other); } /* End PbbPacket class */ PbbMessage::PbbMessage () { m_refCount = 1; /* Default to IPv4 */ m_addrSize = IPV4; m_hasOriginatorAddress = false; m_hasHopLimit = false; m_hasHopCount = false; m_hasSequenceNumber = false; } PbbMessage::~PbbMessage () { AddressBlockClear (); } void PbbMessage::SetType (uint8_t type) { m_type = type; } uint8_t PbbMessage::GetType (void) const { return m_type; } PbbAddressLength PbbMessage::GetAddressLength (void) const { return m_addrSize; } void PbbMessage::SetOriginatorAddress (Address address) { m_originatorAddress = address; m_hasOriginatorAddress = true; } Address PbbMessage::GetOriginatorAddress (void) const { NS_ASSERT (HasOriginatorAddress ()); return m_originatorAddress; } bool PbbMessage::HasOriginatorAddress (void) const { return m_hasOriginatorAddress; } void PbbMessage::SetHopLimit (uint8_t hopLimit) { m_hopLimit = hopLimit; m_hasHopLimit = true; } uint8_t PbbMessage::GetHopLimit (void) const { NS_ASSERT (HasHopLimit ()); return m_hopLimit; } bool PbbMessage::HasHopLimit (void) const { return m_hasHopLimit; } void PbbMessage::SetHopCount (uint8_t hopCount) { m_hopCount = hopCount; m_hasHopCount = true; } uint8_t PbbMessage::GetHopCount (void) const { NS_ASSERT (HasHopCount ()); return m_hopCount; } bool PbbMessage::HasHopCount (void) const { return m_hasHopCount; } void PbbMessage::SetSequenceNumber (uint16_t sequenceNumber) { m_sequenceNumber = sequenceNumber; m_hasSequenceNumber = true; } uint16_t PbbMessage::GetSequenceNumber (void) const { NS_ASSERT (HasSequenceNumber ()); return m_sequenceNumber; } bool PbbMessage::HasSequenceNumber (void) const { return m_hasSequenceNumber; } /* Manipulating PbbMessage TLVs */ PbbMessage::TlvIterator PbbMessage::TlvBegin (void) { return m_tlvList.Begin(); } PbbMessage::ConstTlvIterator PbbMessage::TlvBegin (void) const { return m_tlvList.Begin(); } PbbMessage::TlvIterator PbbMessage::TlvEnd (void) { return m_tlvList.End(); } PbbMessage::ConstTlvIterator PbbMessage::TlvEnd (void) const { return m_tlvList.End(); } int PbbMessage::TlvSize (void) const { return m_tlvList.Size(); } bool PbbMessage::TlvEmpty (void) const { return m_tlvList.Empty(); } Ptr PbbMessage::TlvFront (void) { return m_tlvList.Front(); } const Ptr PbbMessage::TlvFront (void) const { return m_tlvList.Front(); } Ptr PbbMessage::TlvBack (void) { return m_tlvList.Back(); } const Ptr PbbMessage::TlvBack (void) const { return m_tlvList.Back(); } void PbbMessage::TlvPushFront (Ptr tlv) { m_tlvList.PushFront(tlv); } void PbbMessage::TlvPopFront (void) { m_tlvList.PopFront(); } void PbbMessage::TlvPushBack (Ptr tlv) { m_tlvList.PushBack(tlv); } void PbbMessage::TlvPopBack (void) { m_tlvList.PopBack(); } PbbMessage::TlvIterator PbbMessage::TlvErase (PbbMessage::TlvIterator position) { return m_tlvList.Erase(position); } PbbMessage::TlvIterator PbbMessage::TlvErase (PbbMessage::TlvIterator first, PbbMessage::TlvIterator last) { return m_tlvList.Erase(first, last); } void PbbMessage::TlvClear (void) { m_tlvList.Clear(); } /* Manipulating Address Block and Address TLV pairs */ PbbMessage::AddressBlockIterator PbbMessage::AddressBlockBegin (void) { return m_addressBlockList.begin(); } PbbMessage::ConstAddressBlockIterator PbbMessage::AddressBlockBegin (void) const { return m_addressBlockList.begin(); } PbbMessage::AddressBlockIterator PbbMessage::AddressBlockEnd (void) { return m_addressBlockList.end(); } PbbMessage::ConstAddressBlockIterator PbbMessage::AddressBlockEnd (void) const { return m_addressBlockList.end(); } int PbbMessage::AddressBlockSize (void) const { return m_addressBlockList.size(); } bool PbbMessage::AddressBlockEmpty (void) const { return m_addressBlockList.empty(); } Ptr PbbMessage::AddressBlockFront (void) { return m_addressBlockList.front(); } const Ptr PbbMessage::AddressBlockFront (void) const { return m_addressBlockList.front(); } Ptr PbbMessage::AddressBlockBack (void) { return m_addressBlockList.back(); } const Ptr PbbMessage::AddressBlockBack (void) const { return m_addressBlockList.back(); } void PbbMessage::AddressBlockPushFront (Ptr tlv) { m_addressBlockList.push_front(tlv); } void PbbMessage::AddressBlockPopFront (void) { m_addressBlockList.pop_front(); } void PbbMessage::AddressBlockPushBack (Ptr tlv) { m_addressBlockList.push_back(tlv); } void PbbMessage::AddressBlockPopBack (void) { m_addressBlockList.pop_back(); } PbbMessage::AddressBlockIterator PbbMessage::AddressBlockErase (PbbMessage::AddressBlockIterator position) { return m_addressBlockList.erase(position); } PbbMessage::AddressBlockIterator PbbMessage::AddressBlockErase (PbbMessage::AddressBlockIterator first, PbbMessage::AddressBlockIterator last) { return m_addressBlockList.erase(first, last); } void PbbMessage::AddressBlockClear (void) { for (AddressBlockIterator iter = AddressBlockBegin (); iter != AddressBlockEnd (); iter++) { *iter = 0; } return m_addressBlockList.clear(); } void PbbMessage::Ref (void) const { m_refCount++; } void PbbMessage::Unref (void) const { m_refCount--; if (m_refCount == 0) { delete this; } } uint32_t PbbMessage::GetSerializedSize (void) const { /* msg-type + (msg-flags + msg-addr-length) + 2msg-size */ uint32_t size = 4; if (HasOriginatorAddress()) { size += GetAddressLength() + 1; } if (HasHopLimit()) { size++; } if (HasHopCount()) { size++; } if (HasSequenceNumber()) { size += 2; } size += m_tlvList.GetSerializedSize (); for (ConstAddressBlockIterator iter = AddressBlockBegin (); iter != AddressBlockEnd (); iter++) { size += (*iter)->GetSerializedSize (); } return size; } void PbbMessage::Serialize (Buffer::Iterator &start) const { Buffer::Iterator front = start; start.WriteU8 (GetType()); /* Save a reference to the spot where we will later write the flags */ Buffer::Iterator bufref = start; start.Next (1); uint8_t flags = 0; flags = GetAddressLength (); Buffer::Iterator sizeref = start; start.Next (2); if (HasOriginatorAddress ()) { flags |= MHAS_ORIG; SerializeOriginatorAddress (start); } if (HasHopLimit ()) { flags |= MHAS_HOP_LIMIT; start.WriteU8 (GetHopLimit ()); } if (HasHopCount ()) { flags |= MHAS_HOP_COUNT; start.WriteU8 (GetHopCount ()); } if (HasSequenceNumber ()) { flags |= MHAS_SEQ_NUM; start.WriteHtonU16 (GetSequenceNumber ()); } bufref.WriteU8(flags); m_tlvList.Serialize (start); for (ConstAddressBlockIterator iter = AddressBlockBegin (); iter != AddressBlockEnd (); iter++) { (*iter)->Serialize (start); } sizeref.WriteHtonU16 (front.GetDistanceFrom (start)); } Ptr PbbMessage::DeserializeMessage (Buffer::Iterator &start) { /* We need to read the msg-addr-len field to determine what kind of object to * construct. */ start.Next (); uint8_t addrlen = start.ReadU8 (); start.Prev (2); /* Go back to the start */ /* The first four bytes of the flag is the address length. Set the last four * bytes to 0 to read it. */ addrlen = (addrlen & 0xf); Ptr newmsg; switch (addrlen) { case 0: case IPV4: newmsg = Create (); break; case IPV6: newmsg = Create (); break; default: return 0; break; } newmsg->Deserialize (start); return newmsg; } void PbbMessage::Deserialize (Buffer::Iterator &start) { Buffer::Iterator front = start; SetType (start.ReadU8 ()); uint8_t flags = start.ReadU8 (); uint16_t size = start.ReadNtohU16 (); if (flags & MHAS_ORIG) { SetOriginatorAddress (DeserializeOriginatorAddress (start)); } if (flags & MHAS_HOP_LIMIT) { SetHopLimit (start.ReadU8 ()); } if (flags & MHAS_HOP_COUNT) { SetHopCount (start.ReadU8 ()); } if (flags & MHAS_SEQ_NUM) { SetSequenceNumber (start.ReadNtohU16 ()); } m_tlvList.Deserialize (start); if (size > 0) { while (start.GetDistanceFrom(front) < size) { Ptr newab = AddressBlockDeserialize (start); AddressBlockPushBack (newab); } } } void PbbMessage::Print (std::ostream &os) const { Print (os, 0); } void PbbMessage::Print (std::ostream &os, int level) const { std::string prefix = ""; for (int i = 0; i < level; i++) { prefix.append ("\t"); } os << prefix << "PbbMessage {" << std::endl; os << prefix << "\tmessage type = " << (int)GetType () << std::endl; os << prefix << "\taddress size = " << GetAddressLength () << std::endl; if (HasOriginatorAddress ()) { os << prefix << "\toriginator address = "; PrintOriginatorAddress (os); os << std::endl; } if (HasHopLimit ()) { os << prefix << "\thop limit = " << (int)GetHopLimit () << std::endl; } if (HasHopCount ()) { os << prefix << "\thop count = " << (int)GetHopCount () << std::endl; } if (HasSequenceNumber ()) { os << prefix << "\tseqnum = " << GetSequenceNumber () << std::endl; } m_tlvList.Print (os, level+1); for (ConstAddressBlockIterator iter = AddressBlockBegin (); iter != AddressBlockEnd (); iter++) { (*iter)->Print (os, level+1); } os << prefix << "}" << std::endl; } bool PbbMessage::operator== (const PbbMessage &other) const { if (GetAddressLength () != other.GetAddressLength ()) { return false; } if (GetType () != other.GetType ()) { return false; } if (HasOriginatorAddress () != other.HasOriginatorAddress ()) { return false; } if (HasOriginatorAddress ()) { if (GetOriginatorAddress () != other.GetOriginatorAddress ()) { return false; } } if (HasHopLimit () != other.HasHopLimit ()) { return false; } if (HasHopLimit ()) { if (GetHopLimit () != other.GetHopLimit ()) { return false; } } if (HasHopCount () != other.HasHopCount ()) { return false; } if (HasHopCount ()) { if (GetHopCount () != other.GetHopCount ()) { return false; } } if (HasSequenceNumber () != other.HasSequenceNumber ()) { return false; } if (HasSequenceNumber ()) { if (GetSequenceNumber () != other.GetSequenceNumber ()) { return false; } } if (m_tlvList != other.m_tlvList) { return false; } if (AddressBlockSize () != other.AddressBlockSize ()) { return false; } ConstAddressBlockIterator tai, oai; for (tai = AddressBlockBegin (), oai = other.AddressBlockBegin (); tai != AddressBlockEnd () && oai != other.AddressBlockEnd (); tai++, oai++) { if (**tai != **oai) { return false; } } return true; } bool PbbMessage::operator!= (const PbbMessage &other) const { return !(*this == other); } /* End PbbMessage Class */ PbbMessageIpv4::PbbMessageIpv4 () { } PbbMessageIpv4::~PbbMessageIpv4 () { } PbbAddressLength PbbMessageIpv4::GetAddressLength (void) const { return IPV4; } void PbbMessageIpv4::SerializeOriginatorAddress (Buffer::Iterator &start) const { uint8_t buffer[GetAddressLength () + 1]; Ipv4Address::ConvertFrom (GetOriginatorAddress ()).Serialize(buffer); start.Write (buffer, GetAddressLength () + 1); } Address PbbMessageIpv4::DeserializeOriginatorAddress (Buffer::Iterator &start) const { uint8_t buffer[GetAddressLength () + 1]; start.Read(buffer, GetAddressLength () + 1); return Ipv4Address::Deserialize (buffer); } void PbbMessageIpv4::PrintOriginatorAddress (std::ostream &os) const { Ipv4Address::ConvertFrom (GetOriginatorAddress ()).Print (os); } Ptr PbbMessageIpv4::AddressBlockDeserialize (Buffer::Iterator &start) const { Ptr newab = Create (); newab->Deserialize (start); return newab; } /* End PbbMessageIpv4 Class */ PbbMessageIpv6::PbbMessageIpv6 () { } PbbMessageIpv6::~PbbMessageIpv6 () { } PbbAddressLength PbbMessageIpv6::GetAddressLength (void) const { return IPV6; } void PbbMessageIpv6::SerializeOriginatorAddress (Buffer::Iterator &start) const { uint8_t buffer[GetAddressLength () + 1]; Ipv6Address::ConvertFrom (GetOriginatorAddress ()).Serialize(buffer); start.Write (buffer, GetAddressLength () + 1); } Address PbbMessageIpv6::DeserializeOriginatorAddress (Buffer::Iterator &start) const { uint8_t buffer[GetAddressLength () + 1]; start.Read(buffer, GetAddressLength () + 1); return Ipv6Address::Deserialize (buffer); } void PbbMessageIpv6::PrintOriginatorAddress (std::ostream &os) const { Ipv6Address::ConvertFrom (GetOriginatorAddress ()).Print (os); } Ptr PbbMessageIpv6::AddressBlockDeserialize (Buffer::Iterator &start) const { Ptr newab = Create (); newab->Deserialize (start); return newab; } /* End PbbMessageIpv6 Class */ PbbAddressBlock::PbbAddressBlock () { m_refCount = 1; } PbbAddressBlock::~PbbAddressBlock () { } /* Manipulating the address block */ PbbAddressBlock::AddressIterator PbbAddressBlock::AddressBegin (void) { return m_addressList.begin(); } PbbAddressBlock::ConstAddressIterator PbbAddressBlock::AddressBegin (void) const { return m_addressList.begin(); } PbbAddressBlock::AddressIterator PbbAddressBlock::AddressEnd (void) { return m_addressList.end(); } PbbAddressBlock::ConstAddressIterator PbbAddressBlock::AddressEnd (void) const { return m_addressList.end(); } int PbbAddressBlock::AddressSize (void) const { return m_addressList.size(); } bool PbbAddressBlock::AddressEmpty (void) const { return m_addressList.empty(); } Address PbbAddressBlock::AddressFront (void) const { return m_addressList.front(); } Address PbbAddressBlock::AddressBack (void) const { return m_addressList.back(); } void PbbAddressBlock::AddressPushFront (Address tlv) { m_addressList.push_front(tlv); } void PbbAddressBlock::AddressPopFront (void) { m_addressList.pop_front(); } void PbbAddressBlock::AddressPushBack (Address tlv) { m_addressList.push_back(tlv); } void PbbAddressBlock::AddressPopBack (void) { m_addressList.pop_back(); } PbbAddressBlock::AddressIterator PbbAddressBlock::AddressErase (PbbAddressBlock::AddressIterator position) { return m_addressList.erase(position); } PbbAddressBlock::AddressIterator PbbAddressBlock::AddressErase (PbbAddressBlock::AddressIterator first, PbbAddressBlock::AddressIterator last) { return m_addressList.erase(first, last); } void PbbAddressBlock::AddressClear (void) { return m_addressList.clear(); } /* Manipulating the prefix list */ PbbAddressBlock::PrefixIterator PbbAddressBlock::PrefixBegin (void) { return m_prefixList.begin (); } PbbAddressBlock::ConstPrefixIterator PbbAddressBlock::PrefixBegin (void) const { return m_prefixList.begin (); } PbbAddressBlock::PrefixIterator PbbAddressBlock::PrefixEnd (void) { return m_prefixList.end (); } PbbAddressBlock::ConstPrefixIterator PbbAddressBlock::PrefixEnd (void) const { return m_prefixList.end (); } int PbbAddressBlock::PrefixSize (void) const { return m_prefixList.size (); } bool PbbAddressBlock::PrefixEmpty (void) const { return m_prefixList.empty (); } uint8_t PbbAddressBlock::PrefixFront (void) const { return m_prefixList.front (); } uint8_t PbbAddressBlock::PrefixBack (void) const { return m_prefixList.back (); } void PbbAddressBlock::PrefixPushFront (uint8_t prefix) { m_prefixList.push_front (prefix); } void PbbAddressBlock::PrefixPopFront (void) { m_prefixList.pop_front (); } void PbbAddressBlock::PrefixPushBack (uint8_t prefix) { m_prefixList.push_back (prefix); } void PbbAddressBlock::PrefixPopBack (void) { m_prefixList.pop_back (); } PbbAddressBlock::PrefixIterator PbbAddressBlock::PrefixInsert (PbbAddressBlock::PrefixIterator position, const uint8_t value) { return m_prefixList.insert (position, value); } PbbAddressBlock::PrefixIterator PbbAddressBlock::PrefixErase (PbbAddressBlock::PrefixIterator position) { return m_prefixList.erase (position); } PbbAddressBlock::PrefixIterator PbbAddressBlock::PrefixErase (PbbAddressBlock::PrefixIterator first, PbbAddressBlock::PrefixIterator last) { return m_prefixList.erase (first, last); } void PbbAddressBlock::PrefixClear (void) { m_prefixList.clear (); } /* Manipulating the TLV block */ PbbAddressBlock::TlvIterator PbbAddressBlock::TlvBegin (void) { return m_addressTlvList.Begin(); } PbbAddressBlock::ConstTlvIterator PbbAddressBlock::TlvBegin (void) const { return m_addressTlvList.Begin(); } PbbAddressBlock::TlvIterator PbbAddressBlock::TlvEnd (void) { return m_addressTlvList.End(); } PbbAddressBlock::ConstTlvIterator PbbAddressBlock::TlvEnd (void) const { return m_addressTlvList.End(); } int PbbAddressBlock::TlvSize (void) const { return m_addressTlvList.Size(); } bool PbbAddressBlock::TlvEmpty (void) const { return m_addressTlvList.Empty(); } Ptr PbbAddressBlock::TlvFront (void) { return m_addressTlvList.Front(); } const Ptr PbbAddressBlock::TlvFront (void) const { return m_addressTlvList.Front(); } Ptr PbbAddressBlock::TlvBack (void) { return m_addressTlvList.Back(); } const Ptr PbbAddressBlock::TlvBack (void) const { return m_addressTlvList.Back(); } void PbbAddressBlock::TlvPushFront (Ptr tlv) { m_addressTlvList.PushFront(tlv); } void PbbAddressBlock::TlvPopFront (void) { m_addressTlvList.PopFront(); } void PbbAddressBlock::TlvPushBack (Ptr tlv) { m_addressTlvList.PushBack(tlv); } void PbbAddressBlock::TlvPopBack (void) { m_addressTlvList.PopBack(); } PbbAddressBlock::TlvIterator PbbAddressBlock::TlvErase (PbbAddressBlock::TlvIterator position) { return m_addressTlvList.Erase(position); } PbbAddressBlock::TlvIterator PbbAddressBlock::TlvErase (PbbAddressBlock::TlvIterator first, PbbAddressBlock::TlvIterator last) { return m_addressTlvList.Erase(first, last); } void PbbAddressBlock::TlvClear (void) { m_addressTlvList.Clear(); } void PbbAddressBlock::Ref (void) const { m_refCount++; } void PbbAddressBlock::Unref (void) const { m_refCount--; if (m_refCount == 0) { delete this; } } uint32_t PbbAddressBlock::GetSerializedSize (void) const { /* num-addr + flags */ uint32_t size = 2; if (AddressSize () == 1) { size += GetAddressLength () + PrefixSize(); } else if (AddressSize () > 0) { uint8_t head[GetAddressLength ()]; uint8_t headlen = 0; uint8_t tail[GetAddressLength ()]; uint8_t taillen = 0; GetHeadTail (head, headlen, tail, taillen); if (headlen > 0) { size += 1 + headlen; } if (taillen > 0) { size++; if (!HasZeroTail (tail, taillen)) { size += taillen; } } /* mid size */ size += (GetAddressLength () - headlen - taillen) * AddressSize (); size += PrefixSize (); } size += m_addressTlvList.GetSerializedSize (); return size; } void PbbAddressBlock::Serialize (Buffer::Iterator &start) const { start.WriteU8 (AddressSize ()); if (AddressSize () == 1) { start.WriteU8 (0); uint8_t buf[GetAddressLength ()]; SerializeAddress (buf, AddressBegin ()); start.Write (buf, GetAddressLength ()); if (PrefixSize () == 1) { start.WriteU8 (PrefixFront ()); } } else if (AddressSize () > 0) { Buffer::Iterator bufref = start; uint8_t flags = 0; start.Next (); uint8_t head[GetAddressLength ()]; uint8_t tail[GetAddressLength ()]; uint8_t headlen = 0; uint8_t taillen = 0; GetHeadTail (head, headlen, tail, taillen); if (headlen > 0) { flags |= AHAS_HEAD; start.WriteU8 (headlen); start.Write (head, headlen); } if (taillen > 0) { start.WriteU8 (taillen); if (HasZeroTail (tail, taillen)) { flags |= AHAS_ZERO_TAIL; } else { flags |= AHAS_FULL_TAIL; start.Write (tail, taillen); } } if (headlen + taillen < GetAddressLength ()) { uint8_t mid[GetAddressLength ()]; for (PbbAddressBlock::ConstAddressIterator iter = AddressBegin (); iter != AddressEnd (); iter++) { SerializeAddress (mid, iter); start.Write (mid + headlen, GetAddressLength () - headlen - taillen); } } flags |= GetPrefixFlags (); bufref.WriteU8 (flags); for (ConstPrefixIterator iter = PrefixBegin (); iter != PrefixEnd (); iter++) { start.WriteU8 (*iter); } } m_addressTlvList.Serialize (start); } void PbbAddressBlock::Deserialize (Buffer::Iterator &start) { uint8_t numaddr = start.ReadU8 (); uint8_t flags = start.ReadU8 (); if (numaddr > 0) { uint8_t headlen = 0; uint8_t taillen = 0; uint8_t addrtmp[GetAddressLength ()]; memset(addrtmp, 0, GetAddressLength ()); if (flags & AHAS_HEAD) { headlen = start.ReadU8 (); start.Read (addrtmp, headlen); } if ((flags & AHAS_FULL_TAIL) ^ (flags & AHAS_ZERO_TAIL)) { taillen = start.ReadU8 (); if (flags & AHAS_FULL_TAIL) { start.Read (addrtmp + GetAddressLength () - taillen, taillen); } } for (int i = 0; i < numaddr; i++) { start.Read (addrtmp + headlen, GetAddressLength () - headlen - taillen); AddressPushBack (DeserializeAddress (addrtmp)); } if (flags & AHAS_SINGLE_PRE_LEN) { PrefixPushBack (start.ReadU8 ()); } else if (flags & AHAS_MULTI_PRE_LEN) { for (int i = 0; i < numaddr; i++) { PrefixPushBack (start.ReadU8 ()); } } } m_addressTlvList.Deserialize (start); } void PbbAddressBlock::Print (std::ostream &os) const { Print (os, 0); } void PbbAddressBlock::Print (std::ostream &os, int level) const { std::string prefix = ""; for (int i = 0; i < level; i++) { prefix.append ("\t"); } os << prefix << "PbbAddressBlock {" << std::endl; os << prefix << "\taddresses = " << std::endl; for (ConstAddressIterator iter = AddressBegin (); iter != AddressEnd (); iter++) { os << prefix << "\t\t"; PrintAddress(os, iter); os << std::endl; } os << prefix << "\tprefixes = " << std::endl; for (ConstPrefixIterator iter = PrefixBegin (); iter != PrefixEnd (); iter++) { os << prefix << "\t\t" << (int)(*iter) << std::endl; } m_addressTlvList.Print (os, level+1); } bool PbbAddressBlock::operator== (const PbbAddressBlock &other) const { if (AddressSize () != other.AddressSize ()) { return false; } ConstAddressIterator tai, oai; for (tai = AddressBegin (), oai = other.AddressBegin (); tai != AddressEnd () && oai != other.AddressEnd (); tai++, oai++) { if (*tai != *oai) { return false; } } if (PrefixSize () != other.PrefixSize ()) { return false; } ConstPrefixIterator tpi, opi; for (tpi = PrefixBegin (), opi = other.PrefixBegin (); tpi != PrefixEnd () && opi != other.PrefixEnd (); tpi++, opi++) { if (*tpi != *opi) { return false; } } if (m_addressTlvList != other.m_addressTlvList) { return false; } return true; } bool PbbAddressBlock::operator!= (const PbbAddressBlock &other) const { return !(*this == other); } uint8_t PbbAddressBlock::GetPrefixFlags (void) const { switch (PrefixSize ()) { case 0: return 0; break; case 1: return AHAS_SINGLE_PRE_LEN; break; default: return AHAS_MULTI_PRE_LEN; break; } /* Quiet compiler */ return 0; } void PbbAddressBlock::GetHeadTail (uint8_t *head, uint8_t &headlen, uint8_t *tail, uint8_t &taillen) const { headlen = GetAddressLength (); taillen = headlen; /* Temporary automatic buffers to store serialized addresses */ uint8_t * buflast = new uint8_t[GetAddressLength ()]; uint8_t * bufcur = new uint8_t[GetAddressLength ()]; uint8_t * tmp; SerializeAddress (buflast, AddressBegin ()); /* Skip the first item */ for (PbbAddressBlock::ConstAddressIterator iter = AddressBegin ()++; iter != AddressEnd (); iter++) { SerializeAddress (bufcur, iter); int i; for (i = 0; i < headlen; i++) { if (buflast[i] != bufcur[i]) { headlen = i; break; } } /* If headlen == fulllen - 1, then tail is 0 */ if (headlen <= GetAddressLength () - 1) { for (i = GetAddressLength () - 1; GetAddressLength () - 1 - i <= taillen && i > headlen; i--) { if (buflast[i] != bufcur[i]) { break; } } taillen = GetAddressLength () - 1 - i; } else if (headlen == 0) { taillen = 0; break; } tmp = buflast; buflast = bufcur; bufcur = tmp; } memcpy(head, bufcur, headlen); memcpy(tail, bufcur + (GetAddressLength () - taillen), taillen); delete[] buflast; delete[] bufcur; } bool PbbAddressBlock::HasZeroTail (const uint8_t *tail, uint8_t taillen) const { int i; for (i = 0; i < taillen; i++) { if (tail[i] != 0) { break; } } return i == taillen; } /* End PbbAddressBlock Class */ PbbAddressBlockIpv4::PbbAddressBlockIpv4 () { } PbbAddressBlockIpv4::~PbbAddressBlockIpv4 () { } uint8_t PbbAddressBlockIpv4::GetAddressLength (void) const { return 4; } void PbbAddressBlockIpv4::SerializeAddress (uint8_t *buffer, ConstAddressIterator iter) const { Ipv4Address::ConvertFrom (*iter).Serialize (buffer); } Address PbbAddressBlockIpv4::DeserializeAddress (uint8_t *buffer) const { return Ipv4Address::Deserialize (buffer); } void PbbAddressBlockIpv4::PrintAddress (std::ostream &os, ConstAddressIterator iter) const { Ipv4Address::ConvertFrom (*iter).Print (os); } /* End PbbAddressBlockIpv4 Class */ PbbAddressBlockIpv6::PbbAddressBlockIpv6 () { } PbbAddressBlockIpv6::~PbbAddressBlockIpv6 () { } uint8_t PbbAddressBlockIpv6::GetAddressLength (void) const { return 16; } void PbbAddressBlockIpv6::SerializeAddress (uint8_t *buffer, ConstAddressIterator iter) const { Ipv6Address::ConvertFrom (*iter).Serialize (buffer); } Address PbbAddressBlockIpv6::DeserializeAddress (uint8_t *buffer) const { return Ipv6Address::Deserialize (buffer); } void PbbAddressBlockIpv6::PrintAddress (std::ostream &os, ConstAddressIterator iter) const { Ipv6Address::ConvertFrom (*iter).Print (os); } /* End PbbAddressBlockIpv6 Class */ PbbTlv::PbbTlv (void) { m_refCount = 1; m_hasTypeExt = false; m_hasIndexStart = false; m_hasIndexStop = false; m_isMultivalue = false; m_hasValue = false; } PbbTlv::~PbbTlv (void) { m_value.RemoveAtEnd (m_value.GetSize ()); } void PbbTlv::SetType (uint8_t type) { m_type = type; } uint8_t PbbTlv::GetType (void) const { return m_type; } void PbbTlv::SetTypeExt (uint8_t typeExt) { m_typeExt = typeExt; m_hasTypeExt = true; } uint8_t PbbTlv::GetTypeExt (void) const { NS_ASSERT (HasTypeExt ()); return m_typeExt; } bool PbbTlv::HasTypeExt (void) const { return m_hasTypeExt; } void PbbTlv::SetIndexStart (uint8_t index) { m_indexStart = index; m_hasIndexStart = true; } uint8_t PbbTlv::GetIndexStart (void) const { NS_ASSERT (HasIndexStart ()); return m_indexStart; } bool PbbTlv::HasIndexStart (void) const { return m_hasIndexStart; } void PbbTlv::SetIndexStop (uint8_t index) { m_indexStop = index; m_hasIndexStop = true; } uint8_t PbbTlv::GetIndexStop (void) const { NS_ASSERT (HasIndexStop ()); return m_indexStop; } bool PbbTlv::HasIndexStop (void) const { return m_hasIndexStop; } void PbbTlv::SetMultivalue (bool isMultivalue) { m_isMultivalue = isMultivalue; } bool PbbTlv::IsMultivalue (void) const { return m_isMultivalue; } void PbbTlv::SetValue (Buffer start) { m_hasValue = true; m_value = start; } void PbbTlv::SetValue (const uint8_t * buffer, uint32_t size) { m_hasValue = true; m_value.AddAtStart (size); m_value.Begin ().Write (buffer, size); } Buffer PbbTlv::GetValue (void) const { NS_ASSERT (HasValue ()); return m_value; } bool PbbTlv::HasValue (void) const { return m_hasValue; } void PbbTlv::Ref (void) const { m_refCount++; } void PbbTlv::Unref (void) const { m_refCount--; if (m_refCount == 0) { delete this; } } uint32_t PbbTlv::GetSerializedSize (void) const { /* type + flags */ uint32_t size = 2; if (HasTypeExt ()) { size++; } if (HasIndexStart ()) { size++; } if (HasIndexStop ()) { size++; } if (HasValue ()) { if (GetValue ().GetSize () > 255) { size += 2; } else { size++; } size += GetValue ().GetSize (); } return size; } void PbbTlv::Serialize (Buffer::Iterator &start) const { start.WriteU8 (GetType ()); Buffer::Iterator bufref = start; uint8_t flags = 0; start.Next(); if (HasTypeExt()) { flags |= THAS_TYPE_EXT; start.WriteU8 (GetTypeExt ()); } if (HasIndexStart ()) { start.WriteU8 (GetIndexStart ()); if (HasIndexStop ()) { flags |= THAS_MULTI_INDEX; start.WriteU8 (GetIndexStop ()); } else { flags |= THAS_SINGLE_INDEX; } } if (HasValue ()) { flags |= THAS_VALUE; uint32_t size = GetValue ().GetSize (); if (size > 255) { flags |= THAS_EXT_LEN; start.WriteHtonU16 (size); } else { start.WriteU8 (size); } if (IsMultivalue ()) { flags |= TIS_MULTIVALUE; } start.Write(GetValue ().Begin (), GetValue ().End ()); } bufref.WriteU8 (flags); } void PbbTlv::Deserialize (Buffer::Iterator &start) { SetType (start.ReadU8 ()); uint8_t flags = start.ReadU8 (); if (flags & THAS_TYPE_EXT) { SetTypeExt (start.ReadU8 ()); } if (flags & THAS_MULTI_INDEX) { SetIndexStart (start.ReadU8 ()); SetIndexStop (start.ReadU8 ()); } else if (flags & THAS_SINGLE_INDEX) { SetIndexStart (start.ReadU8 ()); } if (flags & THAS_VALUE) { uint16_t len = 0; if (flags & THAS_EXT_LEN) { len = start.ReadNtohU16 (); } else { len = start.ReadU8 (); } m_value.AddAtStart (len); Buffer::Iterator valueStart = start; start.Next (len); m_value.Begin ().Write (valueStart, start); m_hasValue = true; } } void PbbTlv::Print (std::ostream &os) const { Print (os, 0); } void PbbTlv::Print (std::ostream &os, int level) const { std::string prefix = ""; for (int i = 0; i < level; i++) { prefix.append ("\t"); } os << prefix << "PbbTlv {" << std::endl; os << prefix << "\ttype = " << (int)GetType () << std::endl; if (HasTypeExt ()) { os << prefix << "\ttypeext = " << (int)GetTypeExt () << std::endl; } if (HasIndexStart ()) { os << prefix << "\tindexStart = " << (int)GetIndexStart () << std::endl; } if (HasIndexStop ()) { os << prefix << "\tindexStop = " << (int)GetIndexStop () << std::endl; } os << prefix << "\tisMultivalue = " << IsMultivalue () << std::endl; if (HasValue ()) { os << prefix << "\thas value; size = " << GetValue (). GetSize () << std::endl; } os << prefix << "}" << std::endl; } bool PbbTlv::operator== (const PbbTlv &other) const { if (GetType () != other.GetType ()) { return false; } if (HasTypeExt () != other.HasTypeExt ()) { return false; } if (HasTypeExt ()) { if (GetTypeExt () != other.GetTypeExt ()) { return false; } } if (HasValue () != other.HasValue ()) { return false; } if (HasValue ()) { Buffer tv = GetValue (); Buffer ov = other.GetValue (); if (tv.GetSize () != ov.GetSize ()) { return false; } /* The docs say I probably shouldn't use Buffer::PeekData, but I think it * is justified in this case. */ if (memcmp (tv.PeekData (), ov.PeekData (), tv.GetSize ()) != 0) { return false; } } return true; } bool PbbTlv::operator!= (const PbbTlv &other) const { return !(*this == other); } /* End PbbTlv Class */ void PbbAddressTlv::SetIndexStart (uint8_t index) { PbbTlv::SetIndexStart (index); } uint8_t PbbAddressTlv::GetIndexStart (void) const { return PbbTlv::GetIndexStart (); } bool PbbAddressTlv::HasIndexStart (void) const { return PbbTlv::HasIndexStart (); } void PbbAddressTlv::SetIndexStop (uint8_t index) { PbbTlv::SetIndexStop (index); } uint8_t PbbAddressTlv::GetIndexStop (void) const { return PbbTlv::GetIndexStop (); } bool PbbAddressTlv::HasIndexStop (void) const { return PbbTlv::HasIndexStop (); } void PbbAddressTlv::SetMultivalue (bool isMultivalue) { PbbTlv::SetMultivalue (isMultivalue); } bool PbbAddressTlv::IsMultivalue (void) const { return PbbTlv::IsMultivalue (); } } /* namespace ns3 */