From 63c4a669b91dc7a12e90850dad7121263881bc35 Mon Sep 17 00:00:00 2001 From: Manuel Requena Date: Mon, 5 Dec 2011 12:57:24 +0100 Subject: [PATCH] Add AM RLC header --- src/lte/model/lte-rlc-am-header.cc | 440 +++++++++++++++++++++++++++++ src/lte/model/lte-rlc-am-header.h | 168 +++++++++++ 2 files changed, 608 insertions(+) create mode 100644 src/lte/model/lte-rlc-am-header.cc create mode 100644 src/lte/model/lte-rlc-am-header.h diff --git a/src/lte/model/lte-rlc-am-header.cc b/src/lte/model/lte-rlc-am-header.cc new file mode 100644 index 000000000..25cb27204 --- /dev/null +++ b/src/lte/model/lte-rlc-am-header.cc @@ -0,0 +1,440 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2011 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC) + * + * 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: Manuel Requena + */ + +#include "ns3/log.h" + +#include "ns3/lte-rlc-am-header.h" + +NS_LOG_COMPONENT_DEFINE ("LteRlcAmHeader"); + +namespace ns3 { + +NS_OBJECT_ENSURE_REGISTERED (LteRlcAmHeader); + +LteRlcAmHeader::LteRlcAmHeader () + : m_headerLength (0), + m_dataControlBit (0xff), + m_resegmentationFlag (0xff), + m_pollingBit (0xff), + m_framingInfo (0xff), + m_sequenceNumber (0xfffa), + m_segmentOffset (0xffff), + m_lastOffset (0xffff), + m_controlPduType (0xff), + m_ackSn (0xffff), + m_nackSn (0xffff) +{ +} + +LteRlcAmHeader::~LteRlcAmHeader () +{ + m_headerLength = 0; + m_dataControlBit = 0xff; + m_resegmentationFlag = 0xff; + m_pollingBit = 0xff; + m_framingInfo = 0xff; + m_sequenceNumber = 0xfffb; + m_segmentOffset = 0xffff; + m_lastOffset = 0xffff; + m_controlPduType = 0xff; + m_ackSn = 0xffff; + m_nackSn = 0xffff; +} + +void +LteRlcAmHeader::SetDataPdu (void) +{ + m_headerLength = 4; + m_dataControlBit = DATA_PDU; +} +void +LteRlcAmHeader::SetControlPdu (uint8_t controlPduType) +{ + m_headerLength = 2; + m_dataControlBit = CONTROL_PDU; + m_controlPduType = controlPduType; +} +bool +LteRlcAmHeader::IsDataPdu (void) const +{ + return (m_dataControlBit == DATA_PDU) ? true : false; +} +bool +LteRlcAmHeader::IsControlPdu (void) const +{ + return (m_dataControlBit == CONTROL_PDU) ? true : false; +} + +void +LteRlcAmHeader::SetFramingInfo (uint8_t framingInfo) +{ + m_framingInfo = framingInfo & 0x03; +} + +void +LteRlcAmHeader::SetSequenceNumber (uint16_t sequenceNumber) +{ + m_sequenceNumber = sequenceNumber & 0x03FF; +} + +uint8_t +LteRlcAmHeader::GetFramingInfo () const +{ + return m_framingInfo; +} + +uint16_t +LteRlcAmHeader::GetSequenceNumber () const +{ + return m_sequenceNumber; +} + + +void +LteRlcAmHeader::PushExtensionBit (uint8_t extensionBit) +{ + m_extensionBits.push_back (extensionBit); + if (m_extensionBits.size() > 1) + { + if (m_extensionBits.size() % 2) + { + m_headerLength += 1; + } + else + { + m_headerLength += 2; + } + } +} + +void +LteRlcAmHeader::PushLengthIndicator (uint16_t lengthIndicator) +{ + m_lengthIndicators.push_back (lengthIndicator); +} + + +uint8_t +LteRlcAmHeader::PopExtensionBit (void) +{ + uint8_t extensionBit = m_extensionBits.front (); + m_extensionBits.pop_front (); + + return extensionBit; +} + +uint16_t +LteRlcAmHeader::PopLengthIndicator (void) +{ + uint16_t lengthIndicator = m_lengthIndicators.front (); + m_lengthIndicators.pop_front (); + + return lengthIndicator; +} + + +void +LteRlcAmHeader::SetResegmentationFlag (uint8_t resegFlag) +{ + m_resegmentationFlag = resegFlag & 0x01; +} + +uint8_t +LteRlcAmHeader::GetResegmentationFlag () const +{ + return m_resegmentationFlag; +} + + +void +LteRlcAmHeader::SetPollingBit (uint8_t pollingBit) +{ + m_pollingBit = pollingBit & 0x01; +} + +uint8_t +LteRlcAmHeader::GetPollingBit (void) const +{ + return m_pollingBit; +} + + +void +LteRlcAmHeader::SetLastSegmentFlag (uint8_t lsf) +{ + m_lastSegmentFlag = lsf & 0x01; +} + +uint8_t +LteRlcAmHeader::GetLastSegmentFlag (void) const +{ + return m_lastSegmentFlag; +} + + +void +LteRlcAmHeader::SetSegmentOffset (uint16_t segmentOffset) +{ + m_segmentOffset = segmentOffset & 0x7FFF; +} + +uint16_t +LteRlcAmHeader::GetSegmentOffset (void) const +{ + return m_segmentOffset; +} + +uint16_t +LteRlcAmHeader::GetLastOffset (void) const +{ + return m_lastOffset; +} + + +void +LteRlcAmHeader::SetAckSn (uint16_t ackSn) +{ + m_ackSn = ackSn & 0x03FF; +} + +uint16_t +LteRlcAmHeader::GetAckSn (void) const +{ + return m_ackSn; +} + + +TypeId +LteRlcAmHeader::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::LteRlcAmHeader") + .SetParent
() + .AddConstructor () + ; + return tid; +} + +TypeId +LteRlcAmHeader::GetInstanceTypeId (void) const +{ + return GetTypeId (); +} + +void +LteRlcAmHeader::Print (std::ostream &os) const +{ + std::list ::const_iterator it1 = m_extensionBits.begin (); + std::list ::const_iterator it2 = m_lengthIndicators.begin (); + + os << "Len=" << m_headerLength; + os << " D/C=" << (uint16_t)m_dataControlBit; + + if ( m_dataControlBit == DATA_PDU ) + { + os << " RF=" << (uint16_t)m_resegmentationFlag; + os << " P=" << (uint16_t)m_pollingBit; + os << " FI=" << (uint16_t)m_framingInfo; + os << " E=" << (uint16_t)(*it1); + os << " SN=" << m_sequenceNumber; + os << " LSF=" << (uint16_t)(m_lastSegmentFlag); + os << " SO=" << m_segmentOffset; + + it1++; + if (it1 != m_extensionBits.end ()) + { + os << " E="; + } + while ( it1 != m_extensionBits.end () ) + { + os << (uint16_t)(*it1); + it1++; + } + + if (it2 != m_lengthIndicators.end ()) + { + os << " LI="; + } + while ( it2 != m_lengthIndicators.end () ) + { + os << (uint16_t)(*it2) << " "; + it2++; + } + } + else // if ( m_dataControlBit == CONTROL_PDU ) + { + os << " ACK_SN=" << m_ackSn; + os << " NACK_SN=" << m_nackSn; + } +} + +uint32_t LteRlcAmHeader::GetSerializedSize (void) const +{ + return m_headerLength; +} + +void LteRlcAmHeader::Serialize (Buffer::Iterator start) const +{ + Buffer::Iterator i = start; + + std::list ::const_iterator it1 = m_extensionBits.begin (); + std::list ::const_iterator it2 = m_lengthIndicators.begin (); + + if ( m_dataControlBit == DATA_PDU ) + { + i.WriteU8 ( ((DATA_PDU << 7) & 0x80) | + ((m_resegmentationFlag << 6) & 0x40) | + ((m_pollingBit << 5) & 0x20) | + ((m_framingInfo << 3) & 0x18) | + (((*it1) << 2) & 0x04) | + ((m_sequenceNumber >> 8) & 0x0003) ); + i.WriteU8 ( m_sequenceNumber & 0x00FF ); + i.WriteU8 ( ((m_lastSegmentFlag << 7) & 0x80) | + ((m_segmentOffset >> 8) & 0x007F) ); + i.WriteU8 ( m_segmentOffset & 0x00FF ); + it1++; + + while ( it1 != m_extensionBits.end () && + it2 != m_lengthIndicators.end () ) + { + uint16_t oddLi, evenLi; + uint8_t oddE, evenE; + + oddE = *it1; + oddLi = *it2; + + it1++; + it2++; + + if ( it1 != m_extensionBits.end () && + it2 != m_lengthIndicators.end () ) + { + evenE = *it1; + evenLi = *it2; + + i.WriteU8 ( ((oddE << 7) & 0x80) | ((oddLi >> 4) & 0x007F) ); + i.WriteU8 ( ((oddLi << 4) & 0x00F0) | ((evenE << 3) & 0x08) | ((evenLi >> 8) & 0x0007) ); + i.WriteU8 ( evenLi & 0x00FF ); + + it1++; + it2++; + } + else + { + i.WriteU8 ( ((oddE << 7) & 0x80) | ((oddLi >> 4) & 0x007F) ); + i.WriteU8 ( ((oddLi << 4) & 0x00F0) ); // Padding is implicit + } + } + } + else // if ( m_dataControlBit == CONTROL_PDU ) + { + i.WriteU8 ( ((CONTROL_PDU << 7) & 0x80) | + ((m_controlPduType << 4) & 0x70) | + ((m_ackSn >> 6) & 0x0F) ); + i.WriteU8 ( ((m_ackSn << 2) & 0xC0) ); + } +} + +uint32_t LteRlcAmHeader::Deserialize (Buffer::Iterator start) +{ + Buffer::Iterator i = start; + uint8_t byte_1; + uint8_t byte_2; + uint8_t byte_3; + uint8_t byte_4; + uint8_t extensionBit; + + byte_1 = i.ReadU8 (); + m_headerLength = 1; + m_dataControlBit = (byte_1 & 0x80) >> 7; + + if ( m_dataControlBit == DATA_PDU ) + { + byte_2 = i.ReadU8 (); + byte_3 = i.ReadU8 (); + byte_4 = i.ReadU8 (); + m_headerLength += 3; + + m_resegmentationFlag = (byte_1 & 0x40) >> 6; + m_pollingBit = (byte_1 & 0x20) >> 5; + m_framingInfo = (byte_1 & 0x18) >> 3; + m_sequenceNumber = ((byte_1 & 0x03) << 8) | byte_2; + + m_lastSegmentFlag = (byte_3 & 0x80) >> 7; + m_segmentOffset = (byte_3 & 0x7F) | byte_4; + + extensionBit = (byte_1 & 0x04) >> 2; + m_extensionBits.push_back (extensionBit); + + if (extensionBit == DATA_FIELD_FOLLOWS) + { + return GetSerializedSize (); + } + + uint16_t oddLi, evenLi; + uint8_t oddE, evenE; + bool moreLiFields = (extensionBit == E_LI_FIELDS_FOLLOWS); + + while (moreLiFields) + { + byte_1 = i.ReadU8 (); + byte_2 = i.ReadU8 (); + + oddE = (byte_1 & 0x80) >> 7; + oddLi = ((byte_1 & 0x7F) << 4) | ((byte_2 & 0xF0) >> 4); + moreLiFields = (oddE == E_LI_FIELDS_FOLLOWS); + + m_extensionBits.push_back (oddE); + m_lengthIndicators.push_back (oddLi); + m_headerLength += 2; + + if (moreLiFields) + { + byte_3 = i.ReadU8 (); + + evenE = (byte_2 & 0x08) >> 3; + evenLi = ((byte_2 & 0x07) << 8) | (byte_3 & 0xFF); + moreLiFields = (evenE == E_LI_FIELDS_FOLLOWS); + + m_extensionBits.push_back (evenE); + m_lengthIndicators.push_back (evenLi); + + m_headerLength += 1; + } + } + + if (m_resegmentationFlag == SEGMENT) + { + m_lastOffset = m_segmentOffset + start.GetSize () - m_headerLength; + } + } + else // if ( m_dataControlBit == CONTROL_PDU ) + { + byte_2 = i.ReadU8 (); + + m_controlPduType = (byte_1 & 0x70) >> 4; + m_ackSn = ((byte_1 & 0x0F) << 6 ) | ((byte_2 & 0xFC) >> 2); + + m_headerLength++; + } + + return GetSerializedSize (); +} + +}; // namespace ns3 diff --git a/src/lte/model/lte-rlc-am-header.h b/src/lte/model/lte-rlc-am-header.h new file mode 100644 index 000000000..05b8dfe27 --- /dev/null +++ b/src/lte/model/lte-rlc-am-header.h @@ -0,0 +1,168 @@ +/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2011 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC) + * + * 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: Manuel Requena + */ + +#ifndef LTE_RLC_AM_HEADER_H +#define LTE_RLC_AM_HEADER_H + +#include "ns3/header.h" + +#include + +namespace ns3 { + +/** + * \ingroup lte + * \brief The packet header for the AM Radio Link Control (RLC) protocol packets + * + * This class has fields corresponding to those in an RLC header as well as + * methods for serialization to and deserialization from a byte buffer. + * It follows 3GPP TS 36.322 Radio Link Control (RLC) protocol specification. + */ +class LteRlcAmHeader : public Header +{ +public: + + /** + * \brief Constructor + * + * Creates a null header + */ + LteRlcAmHeader (); + ~LteRlcAmHeader (); + + void SetDataPdu (void); + void SetControlPdu (uint8_t controlPduType); + bool IsDataPdu (void) const; + bool IsControlPdu (void) const; + + typedef enum { + CONTROL_PDU = 0, + DATA_PDU = 1 + } DataControlPdu_t; + + typedef enum { + STATUS_PDU = 000, + } ControPduType_t; + + // + // DATA PDU + // + + void SetSequenceNumber (uint16_t sequenceNumber); + uint16_t GetSequenceNumber () const; + + void SetFramingInfo (uint8_t framingInfo); + uint8_t GetFramingInfo () const; + + typedef enum { + FIRST_BYTE = 0x00, + NO_FIRST_BYTE = 0x02 + } FramingInfoFirstByte_t; + + typedef enum { + LAST_BYTE = 0x00, + NO_LAST_BYTE = 0x01 + } FramingInfoLastByte_t; + + void PushExtensionBit (uint8_t extensionBit); + void PushLengthIndicator (uint16_t lengthIndicator); + + uint8_t PopExtensionBit (void); + uint16_t PopLengthIndicator (void); + + typedef enum { + DATA_FIELD_FOLLOWS = 0, + E_LI_FIELDS_FOLLOWS = 1 + } ExtensionBit_t; + + void SetResegmentationFlag (uint8_t resegFlag); + uint8_t GetResegmentationFlag () const; + + typedef enum { + PDU = 0, + SEGMENT = 1 + } ResegmentationFlag_t; + + void SetPollingBit (uint8_t pollingBit); + uint8_t GetPollingBit () const; + + typedef enum { + STATUS_REPORT_NOT_REQUESTED = 0, + STATUS_REPORT_IS_REQUESTED = 1 + } PollingBit_t; + + void SetLastSegmentFlag (uint8_t lsf); + uint8_t GetLastSegmentFlag () const; + + typedef enum { + NO_LAST_PDU_SEGMENT = 0, + LAST_PDU_SEGMENT = 1 + } LastSegmentFlag_t; + + void SetSegmentOffset (uint16_t segmentOffset); + uint16_t GetSegmentOffset () const; + uint16_t GetLastOffset () const; + + // + // CONTROL PDU + // + + void SetAckSn (uint16_t ackSn); + uint16_t GetAckSn () const; + + + static TypeId GetTypeId (void); + virtual TypeId GetInstanceTypeId (void) const; + virtual void Print (std::ostream &os) const; + virtual uint32_t GetSerializedSize (void) const; + virtual void Serialize (Buffer::Iterator start) const; + virtual uint32_t Deserialize (Buffer::Iterator start); + +private: + uint16_t m_headerLength; + uint8_t m_dataControlBit; + + // Data PDU fields + uint8_t m_resegmentationFlag; + uint8_t m_pollingBit; + uint8_t m_framingInfo; // 2 bits + uint16_t m_sequenceNumber; // 10 bits + uint8_t m_lastSegmentFlag; + uint16_t m_segmentOffset; + uint16_t m_lastOffset; + + std::list m_extensionBits; // Includes extensionBit of the fixed part + std::list m_lengthIndicators; + + // Control PDU fields + uint8_t m_controlPduType; + + // Status PDU fields + uint16_t m_ackSn; + uint16_t m_nackSn; + + std::list m_extensionBits1; // Includes E1 after ACK_SN + std::list m_extensionBits2; + +}; + +}; // namespace ns3 + +#endif // LTE_RLC_AM_HEADER_H