A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
lte-rlc-am-header.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2011 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 *
17 * Author: Manuel Requena <manuel.requena@cttc.es>
18 */
19
20#include "lte-rlc-am-header.h"
21
22#include "ns3/log.h"
23
24namespace ns3
25{
26
27NS_LOG_COMPONENT_DEFINE("LteRlcAmHeader");
28
29NS_OBJECT_ENSURE_REGISTERED(LteRlcAmHeader);
30
32 : m_headerLength(0),
33 m_dataControlBit(0xff),
34 m_resegmentationFlag(0xff),
35 m_pollingBit(0xff),
36 m_framingInfo(0xff),
37 m_sequenceNumber(0xfffa),
38 m_segmentOffset(0xffff),
39 m_lastOffset(0xffff),
40 m_controlPduType(0xff),
41 m_ackSn(0xffff)
42{
43}
44
46{
48 m_dataControlBit = 0xff;
50 m_pollingBit = 0xff;
51 m_framingInfo = 0xff;
52 m_sequenceNumber = 0xfffb;
53 m_segmentOffset = 0xffff;
54 m_lastOffset = 0xffff;
55 m_controlPduType = 0xff;
56 m_ackSn = 0xffff;
57}
58
59void
61{
64}
65
66void
67LteRlcAmHeader::SetControlPdu(uint8_t controlPduType)
68{
71 m_controlPduType = controlPduType;
72}
73
74bool
76{
77 return m_dataControlBit == DATA_PDU;
78}
79
80bool
82{
84}
85
86void
88{
89 m_framingInfo = framingInfo & 0x03;
90}
91
92void
94{
95 m_sequenceNumber = sequenceNumber;
96}
97
98uint8_t
100{
101 return m_framingInfo;
102}
103
106{
107 return m_sequenceNumber;
108}
109
110void
112{
113 m_extensionBits.push_back(extensionBit);
114 if (m_extensionBits.size() > 1)
115 {
116 if (m_extensionBits.size() % 2)
117 {
118 m_headerLength += 1;
119 }
120 else
121 {
122 m_headerLength += 2;
123 }
124 }
125}
126
127void
128LteRlcAmHeader::PushLengthIndicator(uint16_t lengthIndicator)
129{
130 m_lengthIndicators.push_back(lengthIndicator);
131}
132
133uint8_t
135{
136 uint8_t extensionBit = m_extensionBits.front();
137 m_extensionBits.pop_front();
138
139 return extensionBit;
140}
141
142uint16_t
144{
145 uint16_t lengthIndicator = m_lengthIndicators.front();
146 m_lengthIndicators.pop_front();
147
148 return lengthIndicator;
149}
150
151void
153{
154 m_resegmentationFlag = resegFlag & 0x01;
155}
156
157uint8_t
159{
161}
162
163void
165{
166 m_pollingBit = pollingBit & 0x01;
167}
168
169uint8_t
171{
172 return m_pollingBit;
173}
174
175void
177{
178 m_lastSegmentFlag = lsf & 0x01;
179}
180
181uint8_t
183{
184 return m_lastSegmentFlag;
185}
186
187void
188LteRlcAmHeader::SetSegmentOffset(uint16_t segmentOffset)
189{
190 m_segmentOffset = segmentOffset & 0x7FFF;
191}
192
193uint16_t
195{
196 return m_segmentOffset;
197}
198
199uint16_t
201{
202 return m_lastOffset;
203}
204
205void
207{
208 m_ackSn = ackSn;
209}
210
211bool
213{
214 NS_LOG_FUNCTION(this << bytes);
216 "method allowed only for STATUS PDUs");
217 if (m_nackSnList.size() % 2 == 0)
218 {
219 return (m_headerLength < bytes);
220 }
221 else
222 {
223 return (m_headerLength < (bytes - 1));
224 }
225}
226
227void
229{
230 NS_LOG_FUNCTION(this << nack);
232 "method allowed only for STATUS PDUs");
233 m_nackSnList.push_back(nack);
234
235 if (m_nackSnList.size() % 2 == 0)
236 {
238 }
239 else
240 {
241 m_headerLength += 2;
242 }
243}
244
245bool
247{
248 NS_LOG_FUNCTION(this);
250 "method allowed only for STATUS PDUs");
251 for (auto nackIt = m_nackSnList.begin(); nackIt != m_nackSnList.end(); ++nackIt)
252 {
253 if ((*nackIt) == nack.GetValue())
254 {
255 return true;
256 }
257 }
258 return false;
259}
260
261int
263{
264 NS_LOG_FUNCTION(this);
266 "method allowed only for STATUS PDUs");
267 if (m_nackSnList.empty())
268 {
269 return -1;
270 }
271
272 int nack = m_nackSnList.front();
273 m_nackSnList.pop_front();
274
275 return nack;
276}
277
280{
281 return m_ackSn;
282}
283
284TypeId
286{
287 static TypeId tid = TypeId("ns3::LteRlcAmHeader")
288 .SetParent<Header>()
289 .SetGroupName("Lte")
290 .AddConstructor<LteRlcAmHeader>();
291 return tid;
292}
293
294TypeId
296{
297 return GetTypeId();
298}
299
300void
301LteRlcAmHeader::Print(std::ostream& os) const
302{
303 auto it1 = m_extensionBits.begin();
304 auto it2 = m_lengthIndicators.begin();
305 auto it3 = m_nackSnList.begin();
306
307 os << "Len=" << m_headerLength;
308 os << " D/C=" << (uint16_t)m_dataControlBit;
309
311 {
312 os << " RF=" << (uint16_t)m_resegmentationFlag;
313 os << " P=" << (uint16_t)m_pollingBit;
314 os << " FI=" << (uint16_t)m_framingInfo;
315 os << " E=" << (uint16_t)(*it1);
316 os << " SN=" << m_sequenceNumber;
317 os << " LSF=" << (uint16_t)(m_lastSegmentFlag);
318 os << " SO=" << m_segmentOffset;
319
320 it1++;
321 if (it1 != m_extensionBits.end())
322 {
323 os << " E=";
324 }
325 while (it1 != m_extensionBits.end())
326 {
327 os << (uint16_t)(*it1);
328 it1++;
329 }
330
331 if (it2 != m_lengthIndicators.end())
332 {
333 os << " LI=";
334 }
335 while (it2 != m_lengthIndicators.end())
336 {
337 os << (uint16_t)(*it2) << " ";
338 it2++;
339 }
340 }
341 else // if ( m_dataControlBit == CONTROL_PDU )
342 {
343 os << " ACK_SN=" << m_ackSn;
344
345 while (it3 != m_nackSnList.end())
346 {
347 os << " NACK_SN=" << (int)(*it3);
348 it3++;
349 }
350 }
351}
352
355{
356 return m_headerLength;
357}
358
359void
361{
362 Buffer::Iterator i = start;
363
364 auto it1 = m_extensionBits.begin();
365 auto it2 = m_lengthIndicators.begin();
366 auto it3 = m_nackSnList.begin();
367
369 {
370 i.WriteU8(((DATA_PDU << 7) & 0x80) | ((m_resegmentationFlag << 6) & 0x40) |
371 ((m_pollingBit << 5) & 0x20) | ((m_framingInfo << 3) & 0x18) |
372 (((*it1) << 2) & 0x04) | ((m_sequenceNumber.GetValue() >> 8) & 0x0003));
373 i.WriteU8(m_sequenceNumber.GetValue() & 0x00FF);
374 i.WriteU8(((m_lastSegmentFlag << 7) & 0x80) | ((m_segmentOffset >> 8) & 0x007F));
375 i.WriteU8(m_segmentOffset & 0x00FF);
376 it1++;
377
378 while (it1 != m_extensionBits.end() && it2 != m_lengthIndicators.end())
379 {
380 uint16_t oddLi;
381 uint16_t evenLi;
382 uint8_t oddE;
383 uint8_t evenE;
384
385 oddE = *it1;
386 oddLi = *it2;
387
388 it1++;
389 it2++;
390
391 if (it1 != m_extensionBits.end() && it2 != m_lengthIndicators.end())
392 {
393 evenE = *it1;
394 evenLi = *it2;
395
396 i.WriteU8(((oddE << 7) & 0x80) | ((oddLi >> 4) & 0x007F));
397 i.WriteU8(((oddLi << 4) & 0x00F0) | ((evenE << 3) & 0x08) |
398 ((evenLi >> 8) & 0x0007));
399 i.WriteU8(evenLi & 0x00FF);
400
401 it1++;
402 it2++;
403 }
404 else
405 {
406 i.WriteU8(((oddE << 7) & 0x80) | ((oddLi >> 4) & 0x007F));
407 i.WriteU8((oddLi << 4) & 0x00F0); // Padding is implicit
408 }
409 }
410 }
411 else // if ( m_dataControlBit == CONTROL_PDU )
412 {
413 i.WriteU8(((CONTROL_PDU << 7) & 0x80) | ((m_controlPduType << 4) & 0x70) |
414 ((m_ackSn.GetValue() >> 6) & 0x0F));
415 // note: second part of ackSn will be written later
416
417 // serialize the NACKs
418 if (it3 == m_nackSnList.end())
419 {
420 NS_LOG_LOGIC(this << " no NACKs");
421 // If there are no NACKs then this line adds the rest of the ACK
422 // along with 0x00, indicating an E1 value of 0 or no NACKs follow.
423 i.WriteU8((m_ackSn.GetValue() << 2) & 0xFC);
424 }
425 else
426 {
427 int oddNack = *it3;
428 int evenNack = -1;
429 // Else write out a series of E1 = 1 and NACK values. Note since we
430 // are not supporting SO start/end the value of E2 will always be 0.
431
432 // First write out the ACK along with the very first NACK
433 // And the remaining NACK with 0x02 or 10 in binary to set
434 // E1 to 1, then Or in the first bit of the NACK
435 i.WriteU8(((m_ackSn.GetValue() << 2) & 0xFC) | (0x02) | ((*it3 >> 9) & 0x01));
436
437 while (it3 != m_nackSnList.end())
438 {
439 // The variable oddNack has the current NACK value to write, also
440 // either the setup to enter this loop or the previous loop would
441 // have written the highest order bit to the previous octet.
442 // Write the next set of bits (2 - 9) into the next octet
443 i.WriteU8((oddNack >> 1) & 0xFF);
444
445 // Next check to see if there is going to be another NACK after
446 // this
447 it3++;
448 if (it3 != m_nackSnList.end())
449 {
450 // Yes there will be another NACK after this, so E1 will be 1
451 evenNack = *it3;
452 i.WriteU8(((oddNack << 7) & 0x80) | (0x40) // E1 = 1 E2 = 0, more NACKs
453 | ((evenNack >> 5) & 0x1F));
454
455 // The final octet of this loop will have the rest of the
456 // NACK and another E1, E2. Check to see if there will be
457 // one more NACK after this.
458 it3++;
459 if (it3 != m_nackSnList.end())
460 {
461 // Yes there is at least one more NACK. Finish writing
462 // this octet and the next iteration will do the rest.
463 oddNack = *it3;
464 i.WriteU8(((evenNack << 3) & 0xF8) | (0x04) | ((oddNack >> 9) & 0x01));
465 }
466 else
467 {
468 // No, there are no more NACKs
469 i.WriteU8((evenNack << 3) & 0xF8);
470 }
471 }
472 else
473 {
474 // No, this is the last NACK so E1 will be 0
475 i.WriteU8((oddNack << 7) & 0x80);
476 }
477 }
478 }
479 }
480}
481
484{
485 Buffer::Iterator i = start;
486 uint8_t byte_1;
487 uint8_t byte_2;
488 uint8_t byte_3;
489 uint8_t byte_4;
490 uint8_t extensionBit;
491
492 byte_1 = i.ReadU8();
493 m_headerLength = 1;
494 m_dataControlBit = (byte_1 & 0x80) >> 7;
495
497 {
498 byte_2 = i.ReadU8();
499 byte_3 = i.ReadU8();
500 byte_4 = i.ReadU8();
501 m_headerLength += 3;
502
503 m_resegmentationFlag = (byte_1 & 0x40) >> 6;
504 m_pollingBit = (byte_1 & 0x20) >> 5;
505 m_framingInfo = (byte_1 & 0x18) >> 3;
506 m_sequenceNumber = ((byte_1 & 0x03) << 8) | byte_2;
507
508 m_lastSegmentFlag = (byte_3 & 0x80) >> 7;
509 m_segmentOffset = (byte_3 & 0x7F) | byte_4;
510
511 extensionBit = (byte_1 & 0x04) >> 2;
512 m_extensionBits.push_back(extensionBit);
513
514 if (extensionBit == DATA_FIELD_FOLLOWS)
515 {
516 return GetSerializedSize();
517 }
518
519 uint16_t oddLi;
520 uint16_t evenLi;
521 uint8_t oddE;
522 uint8_t evenE;
523 bool moreLiFields = (extensionBit == E_LI_FIELDS_FOLLOWS);
524
525 while (moreLiFields)
526 {
527 byte_1 = i.ReadU8();
528 byte_2 = i.ReadU8();
529
530 oddE = (byte_1 & 0x80) >> 7;
531 oddLi = ((byte_1 & 0x7F) << 4) | ((byte_2 & 0xF0) >> 4);
532 moreLiFields = (oddE == E_LI_FIELDS_FOLLOWS);
533
534 m_extensionBits.push_back(oddE);
535 m_lengthIndicators.push_back(oddLi);
536 m_headerLength += 2;
537
538 if (moreLiFields)
539 {
540 byte_3 = i.ReadU8();
541
542 evenE = (byte_2 & 0x08) >> 3;
543 evenLi = ((byte_2 & 0x07) << 8) | (byte_3 & 0xFF);
544 moreLiFields = (evenE == E_LI_FIELDS_FOLLOWS);
545
546 m_extensionBits.push_back(evenE);
547 m_lengthIndicators.push_back(evenLi);
548
549 m_headerLength += 1;
550 }
551 }
552
554 {
555 m_lastOffset = m_segmentOffset + start.GetSize() - m_headerLength;
556 }
557 }
558 else // if ( m_dataControlBit == CONTROL_PDU )
559 {
560 byte_2 = i.ReadU8();
561
562 m_controlPduType = (byte_1 & 0x70) >> 4;
563 m_ackSn = ((byte_1 & 0x0F) << 6) | ((byte_2 & 0xFC) >> 2);
564
565 int moreNacks = (byte_2 & 0x02) >> 1;
566 // Get the first NACK outside the loop as it is not preceded by an E2
567 // field but all following NACKs will.
568 if (moreNacks == 1)
569 {
570 byte_3 = i.ReadU8();
571 byte_4 = i.ReadU8();
572 m_headerLength = 4;
573
574 m_nackSnList.push_back(((byte_2 & 0x01) << 9) | (byte_3 << 1) | ((byte_4 & 0x80) >> 7));
575
576 // Loop until all NACKs are found
577 moreNacks = ((byte_4 & 0x40) >> 6);
578 uint8_t byte = byte_4;
579 uint8_t nextByte;
580 uint8_t finalByte;
581 while (moreNacks == 1)
582 {
583 // Ignore E2, read next NACK
584 nextByte = i.ReadU8();
585 m_nackSnList.push_back(((byte & 0x1F) << 5) | ((nextByte & 0xF8) >> 3));
586
587 // Check for another NACK, after this any following NACKs will
588 // be aligned properly for the next iteration of this loop.
589 moreNacks = (nextByte & 0x04) >> 2;
590 byte = nextByte;
591 if (moreNacks == 1)
592 {
593 nextByte = i.ReadU8();
594 finalByte = i.ReadU8();
595
596 m_nackSnList.push_back(((byte & 0x01) << 9) | (nextByte << 1) |
597 ((finalByte & 0x80) >> 7));
598
599 moreNacks = ((finalByte & 0x40) >> 6);
600 byte = finalByte;
601 m_headerLength += 3;
602 }
603 else
604 {
606 }
607 }
608 }
609 else
610 {
612 }
613 }
614
615 return GetSerializedSize();
616}
617
618}; // namespace ns3
iterator in a Buffer instance
Definition: buffer.h:100
uint8_t ReadU8()
Definition: buffer.h:1027
void WriteU8(uint8_t data)
Definition: buffer.h:881
Protocol header serialization and deserialization.
Definition: header.h:44
The packet header for the AM Radio Link Control (RLC) protocol packets.
uint8_t GetPollingBit() const
Get polling bit function.
uint8_t PopExtensionBit()
Pop extension bit function.
void SetSegmentOffset(uint16_t segmentOffset)
Set segment offset function.
void PushExtensionBit(uint8_t extensionBit)
Push extension bit function.
uint32_t Deserialize(Buffer::Iterator start) override
bool IsDataPdu() const
Is data PDU function.
SequenceNumber10 GetAckSn() const
Get ack sn function.
void SetPollingBit(uint8_t pollingBit)
Set polling bit function.
bool OneMoreNackWouldFitIn(uint16_t bytes)
uint32_t GetSerializedSize() const override
uint16_t m_headerLength
header length
void SetLastSegmentFlag(uint8_t lsf)
Set last segment flag function.
void Print(std::ostream &os) const override
uint16_t GetLastOffset() const
Get last offset function.
SequenceNumber10 m_sequenceNumber
sequence number
uint16_t m_lastOffset
last offset
LteRlcAmHeader()
Constructor.
void PushNack(int nack)
Add one more NACK to the CONTROL PDU.
uint8_t m_dataControlBit
data control bit
std::list< uint8_t > m_extensionBits
Includes extensionBit of the fixed part.
void SetFramingInfo(uint8_t framingInfo)
Set sequence number.
static constexpr uint8_t STATUS_PDU
Control PDU type status.
uint8_t GetLastSegmentFlag() const
Get last segment flag function.
TypeId GetInstanceTypeId() const override
Get the most derived TypeId for this Object.
void Serialize(Buffer::Iterator start) const override
SequenceNumber10 m_ackSn
ack sn
uint16_t PopLengthIndicator()
Pop length indicator function.
uint8_t m_controlPduType
control PDU type
uint16_t m_segmentOffset
segment offset
void SetAckSn(SequenceNumber10 ackSn)
Set ack sn function.
bool IsControlPdu() const
Is control PDU function.
void SetDataPdu()
Set data PDU function.
uint8_t m_framingInfo
2 bits
uint8_t m_resegmentationFlag
resegmentation flag
void PushLengthIndicator(uint16_t lengthIndicator)
Push length indicator function.
uint8_t GetResegmentationFlag() const
Get resegmentation flag function.
void SetResegmentationFlag(uint8_t resegFlag)
Pop extension bit function.
uint16_t GetSegmentOffset() const
Get segment offset function.
uint8_t m_pollingBit
polling bit
static TypeId GetTypeId()
Get the type ID.
uint8_t m_lastSegmentFlag
last segment flag
bool IsNackPresent(SequenceNumber10 nack)
std::list< int > m_nackSnList
nack sn list
uint8_t GetFramingInfo() const
Get framing info.
SequenceNumber10 GetSequenceNumber() const
Get sequence number.
int PopNack()
Retrieve one NACK from the CONTROL PDU.
void SetControlPdu(uint8_t controlPduType)
Set control PDU function.
std::list< uint16_t > m_lengthIndicators
length indicators
void SetSequenceNumber(SequenceNumber10 sequenceNumber)
Set sequence number.
SequenceNumber10 class.
uint16_t GetValue() const
Extracts the numeric value of the sequence number.
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:932
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition: assert.h:86
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:282
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:46
Every class exported by the ns3 library is enclosed in the ns3 namespace.