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 (std::list<int>::iterator nackIt = m_nackSnList.begin(); nackIt != m_nackSnList.end();
252 ++nackIt)
253 {
254 if ((*nackIt) == nack.GetValue())
255 {
256 return true;
257 }
258 }
259 return false;
260}
261
262int
264{
265 NS_LOG_FUNCTION(this);
267 "method allowed only for STATUS PDUs");
268 if (m_nackSnList.empty())
269 {
270 return -1;
271 }
272
273 int nack = m_nackSnList.front();
274 m_nackSnList.pop_front();
275
276 return nack;
277}
278
281{
282 return m_ackSn;
283}
284
285TypeId
287{
288 static TypeId tid = TypeId("ns3::LteRlcAmHeader")
289 .SetParent<Header>()
290 .SetGroupName("Lte")
291 .AddConstructor<LteRlcAmHeader>();
292 return tid;
293}
294
295TypeId
297{
298 return GetTypeId();
299}
300
301void
302LteRlcAmHeader::Print(std::ostream& os) const
303{
304 std::list<uint8_t>::const_iterator it1 = m_extensionBits.begin();
305 std::list<uint16_t>::const_iterator it2 = m_lengthIndicators.begin();
306 std::list<int>::const_iterator it3 = m_nackSnList.begin();
307
308 os << "Len=" << m_headerLength;
309 os << " D/C=" << (uint16_t)m_dataControlBit;
310
312 {
313 os << " RF=" << (uint16_t)m_resegmentationFlag;
314 os << " P=" << (uint16_t)m_pollingBit;
315 os << " FI=" << (uint16_t)m_framingInfo;
316 os << " E=" << (uint16_t)(*it1);
317 os << " SN=" << m_sequenceNumber;
318 os << " LSF=" << (uint16_t)(m_lastSegmentFlag);
319 os << " SO=" << m_segmentOffset;
320
321 it1++;
322 if (it1 != m_extensionBits.end())
323 {
324 os << " E=";
325 }
326 while (it1 != m_extensionBits.end())
327 {
328 os << (uint16_t)(*it1);
329 it1++;
330 }
331
332 if (it2 != m_lengthIndicators.end())
333 {
334 os << " LI=";
335 }
336 while (it2 != m_lengthIndicators.end())
337 {
338 os << (uint16_t)(*it2) << " ";
339 it2++;
340 }
341 }
342 else // if ( m_dataControlBit == CONTROL_PDU )
343 {
344 os << " ACK_SN=" << m_ackSn;
345
346 while (it3 != m_nackSnList.end())
347 {
348 os << " NACK_SN=" << (int)(*it3);
349 it3++;
350 }
351 }
352}
353
356{
357 return m_headerLength;
358}
359
360void
362{
363 Buffer::Iterator i = start;
364
365 std::list<uint8_t>::const_iterator it1 = m_extensionBits.begin();
366 std::list<uint16_t>::const_iterator it2 = m_lengthIndicators.begin();
367 std::list<int>::const_iterator it3 = m_nackSnList.begin();
368
370 {
371 i.WriteU8(((DATA_PDU << 7) & 0x80) | ((m_resegmentationFlag << 6) & 0x40) |
372 ((m_pollingBit << 5) & 0x20) | ((m_framingInfo << 3) & 0x18) |
373 (((*it1) << 2) & 0x04) | ((m_sequenceNumber.GetValue() >> 8) & 0x0003));
374 i.WriteU8(m_sequenceNumber.GetValue() & 0x00FF);
375 i.WriteU8(((m_lastSegmentFlag << 7) & 0x80) | ((m_segmentOffset >> 8) & 0x007F));
376 i.WriteU8(m_segmentOffset & 0x00FF);
377 it1++;
378
379 while (it1 != m_extensionBits.end() && it2 != m_lengthIndicators.end())
380 {
381 uint16_t oddLi;
382 uint16_t evenLi;
383 uint8_t oddE;
384 uint8_t evenE;
385
386 oddE = *it1;
387 oddLi = *it2;
388
389 it1++;
390 it2++;
391
392 if (it1 != m_extensionBits.end() && it2 != m_lengthIndicators.end())
393 {
394 evenE = *it1;
395 evenLi = *it2;
396
397 i.WriteU8(((oddE << 7) & 0x80) | ((oddLi >> 4) & 0x007F));
398 i.WriteU8(((oddLi << 4) & 0x00F0) | ((evenE << 3) & 0x08) |
399 ((evenLi >> 8) & 0x0007));
400 i.WriteU8(evenLi & 0x00FF);
401
402 it1++;
403 it2++;
404 }
405 else
406 {
407 i.WriteU8(((oddE << 7) & 0x80) | ((oddLi >> 4) & 0x007F));
408 i.WriteU8(((oddLi << 4) & 0x00F0)); // Padding is implicit
409 }
410 }
411 }
412 else // if ( m_dataControlBit == CONTROL_PDU )
413 {
414 i.WriteU8(((CONTROL_PDU << 7) & 0x80) | ((m_controlPduType << 4) & 0x70) |
415 ((m_ackSn.GetValue() >> 6) & 0x0F));
416 // note: second part of ackSn will be written later
417
418 // serialize the NACKs
419 if (it3 == m_nackSnList.end())
420 {
421 NS_LOG_LOGIC(this << " no NACKs");
422 // If there are no NACKs then this line adds the rest of the ACK
423 // along with 0x00, indicating an E1 value of 0 or no NACKs follow.
424 i.WriteU8(((m_ackSn.GetValue() << 2) & 0xFC));
425 }
426 else
427 {
428 int oddNack = *it3;
429 int evenNack = -1;
430 // Else write out a series of E1 = 1 and NACK values. Note since we
431 // are not supporting SO start/end the value of E2 will always be 0.
432
433 // First write out the ACK along with the very first NACK
434 // And the remaining NACK with 0x02 or 10 in binary to set
435 // E1 to 1, then Or in the first bit of the NACK
436 i.WriteU8(((m_ackSn.GetValue() << 2) & 0xFC) | (0x02) | ((*it3 >> 9) & 0x01));
437
438 while (it3 != m_nackSnList.end())
439 {
440 // The variable oddNack has the current NACK value to write, also
441 // either the setup to enter this loop or the previous loop would
442 // have written the highest order bit to the previous octet.
443 // Write the next set of bits (2 - 9) into the next octet
444 i.WriteU8(((oddNack >> 1) & 0xFF));
445
446 // Next check to see if there is going to be another NACK after
447 // this
448 it3++;
449 if (it3 != m_nackSnList.end())
450 {
451 // Yes there will be another NACK after this, so E1 will be 1
452 evenNack = *it3;
453 i.WriteU8(((oddNack << 7) & 0x80) | (0x40) // E1 = 1 E2 = 0, more NACKs
454 | ((evenNack >> 5) & 0x1F));
455
456 // The final octet of this loop will have the rest of the
457 // NACK and another E1, E2. Check to see if there will be
458 // one more NACK after this.
459 it3++;
460 if (it3 != m_nackSnList.end())
461 {
462 // Yes there is at least one more NACK. Finish writing
463 // this octet and the next iteration will do the rest.
464 oddNack = *it3;
465 i.WriteU8(((evenNack << 3) & 0xF8) | (0x04) | ((oddNack >> 9) & 0x01));
466 }
467 else
468 {
469 // No, there are no more NACKs
470 i.WriteU8(((evenNack << 3) & 0xF8));
471 }
472 }
473 else
474 {
475 // No, this is the last NACK so E1 will be 0
476 i.WriteU8(((oddNack << 7) & 0x80));
477 }
478 }
479 }
480 }
481}
482
485{
486 Buffer::Iterator i = start;
487 uint8_t byte_1;
488 uint8_t byte_2;
489 uint8_t byte_3;
490 uint8_t byte_4;
491 uint8_t extensionBit;
492
493 byte_1 = i.ReadU8();
494 m_headerLength = 1;
495 m_dataControlBit = (byte_1 & 0x80) >> 7;
496
498 {
499 byte_2 = i.ReadU8();
500 byte_3 = i.ReadU8();
501 byte_4 = i.ReadU8();
502 m_headerLength += 3;
503
504 m_resegmentationFlag = (byte_1 & 0x40) >> 6;
505 m_pollingBit = (byte_1 & 0x20) >> 5;
506 m_framingInfo = (byte_1 & 0x18) >> 3;
507 m_sequenceNumber = ((byte_1 & 0x03) << 8) | byte_2;
508
509 m_lastSegmentFlag = (byte_3 & 0x80) >> 7;
510 m_segmentOffset = (byte_3 & 0x7F) | byte_4;
511
512 extensionBit = (byte_1 & 0x04) >> 2;
513 m_extensionBits.push_back(extensionBit);
514
515 if (extensionBit == DATA_FIELD_FOLLOWS)
516 {
517 return GetSerializedSize();
518 }
519
520 uint16_t oddLi;
521 uint16_t evenLi;
522 uint8_t oddE;
523 uint8_t evenE;
524 bool moreLiFields = (extensionBit == E_LI_FIELDS_FOLLOWS);
525
526 while (moreLiFields)
527 {
528 byte_1 = i.ReadU8();
529 byte_2 = i.ReadU8();
530
531 oddE = (byte_1 & 0x80) >> 7;
532 oddLi = ((byte_1 & 0x7F) << 4) | ((byte_2 & 0xF0) >> 4);
533 moreLiFields = (oddE == E_LI_FIELDS_FOLLOWS);
534
535 m_extensionBits.push_back(oddE);
536 m_lengthIndicators.push_back(oddLi);
537 m_headerLength += 2;
538
539 if (moreLiFields)
540 {
541 byte_3 = i.ReadU8();
542
543 evenE = (byte_2 & 0x08) >> 3;
544 evenLi = ((byte_2 & 0x07) << 8) | (byte_3 & 0xFF);
545 moreLiFields = (evenE == E_LI_FIELDS_FOLLOWS);
546
547 m_extensionBits.push_back(evenE);
548 m_lengthIndicators.push_back(evenLi);
549
550 m_headerLength += 1;
551 }
552 }
553
555 {
556 m_lastOffset = m_segmentOffset + start.GetSize() - m_headerLength;
557 }
558 }
559 else // if ( m_dataControlBit == CONTROL_PDU )
560 {
561 byte_2 = i.ReadU8();
562
563 m_controlPduType = (byte_1 & 0x70) >> 4;
564 m_ackSn = ((byte_1 & 0x0F) << 6) | ((byte_2 & 0xFC) >> 2);
565
566 int moreNacks = (byte_2 & 0x02) >> 1;
567 // Get the first NACK outside the loop as it is not preceded by an E2
568 // field but all following NACKs will.
569 if (moreNacks == 1)
570 {
571 byte_3 = i.ReadU8();
572 byte_4 = i.ReadU8();
573 m_headerLength = 4;
574
575 m_nackSnList.push_back(((byte_2 & 0x01) << 9) | (byte_3 << 1) | ((byte_4 & 0x80) >> 7));
576
577 // Loop until all NACKs are found
578 moreNacks = ((byte_4 & 0x40) >> 6);
579 uint8_t byte = byte_4;
580 uint8_t nextByte;
581 uint8_t finalByte;
582 while (moreNacks == 1)
583 {
584 // Ignore E2, read next NACK
585 nextByte = i.ReadU8();
586 m_nackSnList.push_back(((byte & 0x1F) << 5) | ((nextByte & 0xF8) >> 3));
587
588 // Check for another NACK, after this any following NACKs will
589 // be aligned properly for the next iteration of this loop.
590 moreNacks = (nextByte & 0x04) >> 2;
591 byte = nextByte;
592 if (moreNacks == 1)
593 {
594 nextByte = i.ReadU8();
595 finalByte = i.ReadU8();
596
597 m_nackSnList.push_back(((byte & 0x01) << 9) | (nextByte << 1) |
598 ((finalByte & 0x80) >> 7));
599
600 moreNacks = ((finalByte & 0x40) >> 6);
601 byte = finalByte;
602 m_headerLength += 3;
603 }
604 else
605 {
607 }
608 }
609 }
610 else
611 {
613 }
614 }
615
616 return GetSerializedSize();
617}
618
619}; // 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:936
#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.