A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
lte-rlc-am.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2011 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Manuel Requena <manuel.requena@cttc.es>
7 * Nicola Baldo <nbaldo@cttc.es>
8 */
9
10#include "lte-rlc-am.h"
11
12#include "lte-rlc-am-header.h"
14#include "lte-rlc-tag.h"
15
16#include "ns3/log.h"
17#include "ns3/simulator.h"
18
19namespace ns3
20{
21
22NS_LOG_COMPONENT_DEFINE("LteRlcAm");
23
25
27{
28 NS_LOG_FUNCTION(this);
29
30 // Buffers
32 m_retxBuffer.resize(1024);
34 m_txedBuffer.resize(1024);
36
39
40 // State variables: transmitting side
41 m_windowSize = 512;
42 m_vtA = 0;
44 m_vtS = 0;
45 m_pollSn = 0;
46
47 // State variables: receiving side
48 m_vrR = 0;
50 m_vrX = 0;
51 m_vrMs = 0;
52 m_vrH = 0;
53
54 // Counters
57
58 // Configurable parameters
60 m_pollPdu = 1;
61 m_pollByte = 50;
62
63 // SDU reassembling process
66
68}
69
74
77{
78 static TypeId tid =
79 TypeId("ns3::LteRlcAm")
81 .SetGroupName("Lte")
82 .AddConstructor<LteRlcAm>()
83 .AddAttribute("PollRetransmitTimer",
84 "Value of the t-PollRetransmit timer (See section 7.3 of 3GPP TS 36.322)",
88 .AddAttribute("ReorderingTimer",
89 "Value of the t-Reordering timer (See section 7.3 of 3GPP TS 36.322)",
93 .AddAttribute("StatusProhibitTimer",
94 "Value of the t-StatusProhibit timer (See section 7.3 of 3GPP TS 36.322)",
98 .AddAttribute(
99 "ReportBufferStatusTimer",
100 "How much to wait to issue a new Report Buffer Status since the last time "
101 "a new SDU was received",
105 .AddAttribute("TxOpportunityForRetxAlwaysBigEnough",
106 "If true, always pretend that the size of a TxOpportunity is big enough "
107 "for retransmission. If false (default and realistic behavior), no retx "
108 "is performed unless the corresponding TxOpportunity is big enough.",
109 BooleanValue(false),
112 .AddAttribute("MaxTxBufferSize",
113 "Maximum Size of the Transmission Buffer (in Bytes). If zero is "
114 "configured, the buffer is unlimited.",
115 UintegerValue(10 * 1024),
118 return tid;
119}
120
121void
123{
124 NS_LOG_FUNCTION(this);
129
131 m_txonBuffer.clear();
133 m_txedBuffer.clear();
135 m_retxBuffer.clear();
137 m_rxonBuffer.clear();
138 m_sdusBuffer.clear();
139 m_keepS0 = nullptr;
140 m_controlPduBuffer = nullptr;
141
143}
144
145/**
146 * RLC SAP
147 */
148
149void
151{
152 NS_LOG_FUNCTION(this << m_rnti << (uint32_t)m_lcid << p->GetSize());
153
154 if (m_txonBufferSize + p->GetSize() <= m_maxTxBufferSize || (m_maxTxBufferSize == 0))
155 {
156 /** Store PDCP PDU */
159 p->AddPacketTag(tag);
160
161 NS_LOG_LOGIC("Txon Buffer: New packet added");
162 m_txonBuffer.emplace_back(p, Simulator::Now());
163 m_txonBufferSize += p->GetSize();
164 NS_LOG_LOGIC("NumOfBuffers = " << m_txonBuffer.size());
165 NS_LOG_LOGIC("txonBufferSize = " << m_txonBufferSize);
166 }
167 else
168 {
169 // Discard full RLC SDU
170 NS_LOG_LOGIC("TxonBuffer is full. RLC SDU discarded");
171 NS_LOG_LOGIC("MaxTxBufferSize = " << m_maxTxBufferSize);
172 NS_LOG_LOGIC("txonBufferSize = " << m_txonBufferSize);
173 NS_LOG_LOGIC("packet size = " << p->GetSize());
174 m_txDropTrace(p);
175 }
176
177 /** Report Buffer Status */
181}
182
183/**
184 * MAC SAP
185 */
186
187void
189{
190 NS_LOG_FUNCTION(this << m_rnti << (uint32_t)m_lcid << txOpParams.bytes);
191
192 if (txOpParams.bytes < 4)
193 {
194 // Stingy MAC: In general, we need more bytes.
195 // There are a more restrictive test for each particular case
196 NS_LOG_LOGIC("TxOpportunity (size = " << txOpParams.bytes << ") too small");
197 NS_ASSERT_MSG(false,
198 "TxOpportunity (size = "
199 << txOpParams.bytes << ") too small.\n"
200 << "Your MAC scheduler is assigned too few resource blocks.");
201 return;
202 }
203
205 {
206 if (txOpParams.bytes < m_statusPduBufferSize)
207 {
208 // Stingy MAC: We need more bytes for the STATUS PDU
209 NS_LOG_LOGIC("TxOpportunity (size = " << txOpParams.bytes
210 << ") too small for the STATUS PDU (size = "
211 << m_statusPduBufferSize << ")");
212 NS_ASSERT_MSG(false,
213 "TxOpportunity (size = "
214 << txOpParams.bytes << ") too small for the STATUS PDU (size = "
215 << m_statusPduBufferSize << ")\n"
216 << "Your MAC scheduler is assigned too few resource blocks.");
217 return;
218 }
219
220 NS_LOG_LOGIC("Sending STATUS PDU");
221
222 Ptr<Packet> packet = Create<Packet>();
223 LteRlcAmHeader rlcAmHeader;
225
226 NS_LOG_LOGIC("Check for SNs to NACK from " << m_vrR.GetValue() << " to "
227 << m_vrMs.GetValue());
230 for (sn = m_vrR; sn < m_vrMs; sn++)
231 {
232 NS_LOG_LOGIC("SN = " << sn);
233 if (!rlcAmHeader.OneMoreNackWouldFitIn(txOpParams.bytes))
234 {
235 NS_LOG_LOGIC("Can't fit more NACKs in STATUS PDU");
236 break;
237 }
238 auto pduIt = m_rxonBuffer.find(sn.GetValue());
239 if (pduIt == m_rxonBuffer.end() || (!(pduIt->second.m_pduComplete)))
240 {
241 NS_LOG_LOGIC("adding NACK_SN " << sn.GetValue());
242 rlcAmHeader.PushNack(sn.GetValue());
243 }
244 }
245 NS_LOG_LOGIC("SN at end of NACK loop = " << sn);
246 // 3GPP TS 36.322 section 6.2.2.1.4 ACK SN
247 // find the SN of the next not received RLC Data PDU
248 // which is not reported as missing in the STATUS PDU.
249 auto pduIt = m_rxonBuffer.find(sn.GetValue());
250 while ((sn < m_vrMs) && (pduIt != m_rxonBuffer.end()) && (pduIt->second.m_pduComplete))
251 {
252 NS_LOG_LOGIC("SN = " << sn << " < " << m_vrMs << " = " << (sn < m_vrMs));
253 sn++;
254 NS_LOG_LOGIC("SN = " << sn);
255 pduIt = m_rxonBuffer.find(sn.GetValue());
256 }
257
258 NS_ASSERT_MSG(sn <= m_vrMs,
259 "first SN not reported as missing = " << sn << ", VR(MS) = " << m_vrMs);
260 rlcAmHeader.SetAckSn(sn);
261
262 NS_LOG_LOGIC("RLC header: " << rlcAmHeader);
263 packet->AddHeader(rlcAmHeader);
264
265 // Sender timestamp
266 RlcTag rlcTag(Simulator::Now());
267 packet->AddByteTag(rlcTag, 1, rlcAmHeader.GetSerializedSize());
268 m_txPdu(m_rnti, m_lcid, packet->GetSize());
269
270 // Send RLC PDU to MAC layer
272 params.pdu = packet;
273 params.rnti = m_rnti;
274 params.lcid = m_lcid;
275 params.layer = txOpParams.layer;
276 params.harqProcessId = txOpParams.harqId;
277 params.componentCarrierId = txOpParams.componentCarrierId;
278
280
281 m_statusPduRequested = false;
285 this);
286 return;
287 }
288 else if (m_retxBufferSize > 0)
289 {
290 NS_LOG_LOGIC("retxBufferSize = " << m_retxBufferSize);
291 NS_LOG_LOGIC("Sending data from Retransmission Buffer");
295 for (sn = m_vtA; sn < m_vtS; sn++)
296 {
297 uint16_t seqNumberValue = sn.GetValue();
298 NS_LOG_LOGIC("SN = " << seqNumberValue << " m_pdu "
299 << m_retxBuffer.at(seqNumberValue).m_pdu);
300
301 if (m_retxBuffer.at(seqNumberValue).m_pdu)
302 {
303 Ptr<Packet> packet = m_retxBuffer.at(seqNumberValue).m_pdu->Copy();
304
305 if ((packet->GetSize() <= txOpParams.bytes) ||
307 {
308 // According to 5.2.1, the data field is left as is, but we rebuild the header
309 LteRlcAmHeader rlcAmHeader;
310 packet->RemoveHeader(rlcAmHeader);
311 NS_LOG_LOGIC("old AM RLC header: " << rlcAmHeader);
312
313 // Calculate the Polling Bit (5.2.2.1)
315
316 NS_LOG_LOGIC("polling conditions: m_txonBuffer.empty="
317 << m_txonBuffer.empty() << " retxBufferSize=" << m_retxBufferSize
318 << " packet->GetSize ()=" << packet->GetSize());
319 if (((m_txonBuffer.empty()) &&
321 packet->GetSize() + rlcAmHeader.GetSerializedSize())) ||
323 {
328
329 m_pollSn = m_vtS - 1;
330 NS_LOG_LOGIC("New POLL_SN = " << m_pollSn);
331
333 {
334 NS_LOG_LOGIC("Start PollRetransmit timer");
335
339 this);
340 }
341 else
342 {
343 NS_LOG_LOGIC("Restart PollRetransmit timer");
344
349 this);
350 }
351 }
352
353 packet->AddHeader(rlcAmHeader);
354
355 RlcTag rlcTag;
357
358 packet->AddByteTag(rlcTag, 1, rlcAmHeader.GetSerializedSize());
359
360 NS_LOG_LOGIC("new AM RLC header: " << rlcAmHeader);
361
362 m_txPdu(m_rnti, m_lcid, packet->GetSize());
363
364 // Send RLC PDU to MAC layer
366 params.pdu = packet;
367 params.rnti = m_rnti;
368 params.lcid = m_lcid;
369 params.layer = txOpParams.layer;
370 params.harqProcessId = txOpParams.harqId;
371 params.componentCarrierId = txOpParams.componentCarrierId;
372
374
375 m_retxBuffer.at(seqNumberValue).m_retxCount++;
376 m_retxBuffer.at(seqNumberValue).m_waitingSince = Simulator::Now();
377 NS_LOG_INFO("Incr RETX_COUNT for SN = " << seqNumberValue);
378 if (m_retxBuffer.at(seqNumberValue).m_retxCount >= m_maxRetxThreshold)
379 {
380 NS_LOG_INFO("Max RETX_COUNT for SN = " << seqNumberValue);
381 }
382
383 NS_LOG_INFO("Move SN = " << seqNumberValue << " back to txedBuffer");
384 m_txedBuffer.at(seqNumberValue).m_pdu =
385 m_retxBuffer.at(seqNumberValue).m_pdu->Copy();
386 m_txedBuffer.at(seqNumberValue).m_retxCount =
387 m_retxBuffer.at(seqNumberValue).m_retxCount;
388 m_txedBuffer.at(seqNumberValue).m_waitingSince =
389 m_retxBuffer.at(seqNumberValue).m_waitingSince;
390 m_txedBufferSize += m_txedBuffer.at(seqNumberValue).m_pdu->GetSize();
391
392 m_retxBufferSize -= m_retxBuffer.at(seqNumberValue).m_pdu->GetSize();
393 m_retxBuffer.at(seqNumberValue).m_pdu = nullptr;
394 m_retxBuffer.at(seqNumberValue).m_retxCount = 0;
395 m_retxBuffer.at(seqNumberValue).m_waitingSince = MilliSeconds(0);
396
397 NS_LOG_LOGIC("retxBufferSize = " << m_retxBufferSize);
398
399 return;
400 }
401 else
402 {
403 NS_LOG_LOGIC("TxOpportunity (size = "
404 << txOpParams.bytes
405 << ") too small for retransmission of the packet (size = "
406 << packet->GetSize() << ")");
407 NS_LOG_LOGIC("Waiting for bigger TxOpportunity");
408 return;
409 }
410 }
411 }
412 NS_ASSERT_MSG(false, "m_retxBufferSize > 0, but no PDU considered for retx found");
413 }
414 else if (m_txonBufferSize > 0)
415 {
416 if (txOpParams.bytes < 7)
417 {
418 // Stingy MAC: We need more bytes for new DATA PDUs.
419 NS_LOG_LOGIC("TxOpportunity (size = " << txOpParams.bytes
420 << ") too small for DATA PDU");
421 NS_ASSERT_MSG(false,
422 "TxOpportunity (size = "
423 << txOpParams.bytes << ") too small for DATA PDU\n"
424 << "Your MAC scheduler is assigned too few resource blocks.");
425 return;
426 }
427
429 if (m_vtS == m_vtMs)
430 {
431 NS_LOG_INFO("cannot transmit new RLC PDU due to window stalling");
432 return;
433 }
434
435 NS_LOG_LOGIC("Sending data from Transmission Buffer");
436 }
437 else
438 {
439 NS_LOG_LOGIC("No data pending");
440 return;
441 }
442
443 //
444 //
445 // Build new PDU
446 //
447 //
448
449 Ptr<Packet> packet = Create<Packet>();
450 LteRlcAmHeader rlcAmHeader;
451 rlcAmHeader.SetDataPdu();
452
453 // Build Data field
454 uint32_t nextSegmentSize = txOpParams.bytes - 4;
455 uint32_t nextSegmentId = 1;
456 uint32_t dataFieldAddedSize = 0;
457 std::vector<Ptr<Packet>> dataField;
458
459 // Remove the first packet from the transmission buffer.
460 // If only a segment of the packet is taken, then the remaining is given back later
461 if (m_txonBuffer.empty())
462 {
463 NS_LOG_LOGIC("No data pending");
464 return;
465 }
466
467 NS_LOG_LOGIC("SDUs in TxonBuffer = " << m_txonBuffer.size());
468 NS_LOG_LOGIC("First SDU buffer = " << m_txonBuffer.begin()->m_pdu);
469 NS_LOG_LOGIC("First SDU size = " << m_txonBuffer.begin()->m_pdu->GetSize());
470 NS_LOG_LOGIC("Next segment size = " << nextSegmentSize);
471 NS_LOG_LOGIC("Remove SDU from TxBuffer");
472 Time firstSegmentTime = m_txonBuffer.begin()->m_waitingSince;
473 Ptr<Packet> firstSegment = m_txonBuffer.begin()->m_pdu->Copy();
474 m_txonBufferSize -= m_txonBuffer.begin()->m_pdu->GetSize();
475 NS_LOG_LOGIC("txBufferSize = " << m_txonBufferSize);
476 m_txonBuffer.erase(m_txonBuffer.begin());
477
478 while (firstSegment && (firstSegment->GetSize() > 0) && (nextSegmentSize > 0))
479 {
480 NS_LOG_LOGIC("WHILE ( firstSegment && firstSegment->GetSize > 0 && nextSegmentSize > 0 )");
481 NS_LOG_LOGIC(" firstSegment size = " << firstSegment->GetSize());
482 NS_LOG_LOGIC(" nextSegmentSize = " << nextSegmentSize);
483 if ((firstSegment->GetSize() > nextSegmentSize) ||
484 // Segment larger than 2047 octets can only be mapped to the end of the Data field
485 (firstSegment->GetSize() > 2047))
486 {
487 // Take the minimum size, due to the 2047-bytes 3GPP exception
488 // This exception is due to the length of the LI field (just 11 bits)
489 uint32_t currSegmentSize = std::min(firstSegment->GetSize(), nextSegmentSize);
490
491 NS_LOG_LOGIC(" IF ( firstSegment > nextSegmentSize ||");
492 NS_LOG_LOGIC(" firstSegment > 2047 )");
493
494 // Segment txBuffer.FirstBuffer and
495 // Give back the remaining segment to the transmission buffer
496 Ptr<Packet> newSegment = firstSegment->CreateFragment(0, currSegmentSize);
497 NS_LOG_LOGIC(" newSegment size = " << newSegment->GetSize());
498
499 // Status tag of the new and remaining segments
500 // Note: This is the only place where a PDU is segmented and
501 // therefore its status can change
502 LteRlcSduStatusTag oldTag;
503 LteRlcSduStatusTag newTag;
504 firstSegment->RemovePacketTag(oldTag);
505 newSegment->RemovePacketTag(newTag);
507 {
510 }
511 else if (oldTag.GetStatus() == LteRlcSduStatusTag::LAST_SEGMENT)
512 {
514 // oldTag.SetStatus (LteRlcSduStatusTag::LAST_SEGMENT);
515 }
516
517 // Give back the remaining segment to the transmission buffer
518 firstSegment->RemoveAtStart(currSegmentSize);
520 " firstSegment size (after RemoveAtStart) = " << firstSegment->GetSize());
521 if (firstSegment->GetSize() > 0)
522 {
523 firstSegment->AddPacketTag(oldTag);
524
525 m_txonBuffer.insert(m_txonBuffer.begin(), TxPdu(firstSegment, firstSegmentTime));
526 m_txonBufferSize += m_txonBuffer.begin()->m_pdu->GetSize();
527
528 NS_LOG_LOGIC(" Txon buffer: Give back the remaining segment");
529 NS_LOG_LOGIC(" Txon buffers = " << m_txonBuffer.size());
530 NS_LOG_LOGIC(" Front buffer size = " << m_txonBuffer.begin()->m_pdu->GetSize());
531 NS_LOG_LOGIC(" txonBufferSize = " << m_txonBufferSize);
532 }
533 else
534 {
535 // Whole segment was taken, so adjust tag
537 {
539 }
541 {
543 }
544 }
545 // Segment is completely taken or
546 // the remaining segment is given back to the transmission buffer
547 firstSegment = nullptr;
548
549 // Put status tag once it has been adjusted
550 newSegment->AddPacketTag(newTag);
551
552 // Add Segment to Data field
553 dataFieldAddedSize = newSegment->GetSize();
554 dataField.push_back(newSegment);
555 newSegment = nullptr;
556
557 // ExtensionBit (Next_Segment - 1) = 0
559
560 // no LengthIndicator for the last one
561
562 nextSegmentSize -= dataFieldAddedSize;
563 nextSegmentId++;
564
565 // nextSegmentSize MUST be zero (only if segment is smaller or equal to 2047)
566
567 // (NO more segments) ? exit
568 // break;
569 }
570 else if ((nextSegmentSize - firstSegment->GetSize() <= 2) || m_txonBuffer.empty())
571 {
573 " IF nextSegmentSize - firstSegment->GetSize () <= 2 || txonBuffer.size == 0");
574
575 // Add txBuffer.FirstBuffer to DataField
576 dataFieldAddedSize = firstSegment->GetSize();
577 dataField.push_back(firstSegment);
578 firstSegment = nullptr;
579
580 // ExtensionBit (Next_Segment - 1) = 0
582
583 // no LengthIndicator for the last one
584
585 nextSegmentSize -= dataFieldAddedSize;
586 nextSegmentId++;
587
588 NS_LOG_LOGIC(" SDUs in TxBuffer = " << m_txonBuffer.size());
589 if (!m_txonBuffer.empty())
590 {
591 NS_LOG_LOGIC(" First SDU buffer = " << m_txonBuffer.begin()->m_pdu);
593 " First SDU size = " << m_txonBuffer.begin()->m_pdu->GetSize());
594 }
595 NS_LOG_LOGIC(" Next segment size = " << nextSegmentSize);
596
597 // nextSegmentSize <= 2 (only if txBuffer is not empty)
598
599 // (NO more segments) ? exit
600 // break;
601 }
602 else // (firstSegment->GetSize () < m_nextSegmentSize) && (m_txBuffer.size () > 0)
603 {
604 NS_LOG_LOGIC(" IF firstSegment < NextSegmentSize && txonBuffer.size > 0");
605 // Add txBuffer.FirstBuffer to DataField
606 dataFieldAddedSize = firstSegment->GetSize();
607 dataField.push_back(firstSegment);
608
609 // ExtensionBit (Next_Segment - 1) = 1
611
612 // LengthIndicator (Next_Segment) = txBuffer.FirstBuffer.length()
613 rlcAmHeader.PushLengthIndicator(firstSegment->GetSize());
614
615 nextSegmentSize -= ((nextSegmentId % 2) ? (2) : (1)) + dataFieldAddedSize;
616 nextSegmentId++;
617
618 NS_LOG_LOGIC(" SDUs in TxBuffer = " << m_txonBuffer.size());
619 if (!m_txonBuffer.empty())
620 {
621 NS_LOG_LOGIC(" First SDU buffer = " << m_txonBuffer.begin()->m_pdu);
623 " First SDU size = " << m_txonBuffer.begin()->m_pdu->GetSize());
624 }
625 NS_LOG_LOGIC(" Next segment size = " << nextSegmentSize);
626 NS_LOG_LOGIC(" Remove SDU from TxBuffer");
627
628 // (more segments)
629 firstSegment = m_txonBuffer.begin()->m_pdu->Copy();
630 firstSegmentTime = m_txonBuffer.begin()->m_waitingSince;
631 m_txonBufferSize -= m_txonBuffer.begin()->m_pdu->GetSize();
632 m_txonBuffer.erase(m_txonBuffer.begin());
633 NS_LOG_LOGIC(" txBufferSize = " << m_txonBufferSize);
634 }
635 }
636
637 //
638 // Build RLC header
639 //
640
641 rlcAmHeader.SetSequenceNumber(m_vtS++);
644 rlcAmHeader.SetSegmentOffset(0);
645
646 NS_ASSERT_MSG(rlcAmHeader.GetSequenceNumber() < m_vtMs, "SN above TX window");
647 NS_ASSERT_MSG(rlcAmHeader.GetSequenceNumber() >= m_vtA, "SN below TX window");
648
649 // Calculate FramingInfo flag according the status of the SDUs in the DataField
650 uint8_t framingInfo = 0;
651 auto it = dataField.begin();
652
653 // FIRST SEGMENT
655 NS_ASSERT_MSG((*it)->PeekPacketTag(tag), "LteRlcSduStatusTag is missing");
656 (*it)->PeekPacketTag(tag);
659 {
660 framingInfo |= LteRlcAmHeader::FIRST_BYTE;
661 }
662 else
663 {
664 framingInfo |= LteRlcAmHeader::NO_FIRST_BYTE;
665 }
666
667 // Add all SDUs (in DataField) to the Packet
668 while (it < dataField.end())
669 {
670 NS_LOG_LOGIC("Adding SDU/segment to packet, length = " << (*it)->GetSize());
671
672 NS_ASSERT_MSG((*it)->PeekPacketTag(tag), "LteRlcSduStatusTag is missing");
673 (*it)->RemovePacketTag(tag);
674 if (packet->GetSize() > 0)
675 {
676 packet->AddAtEnd(*it);
677 }
678 else
679 {
680 packet = (*it);
681 }
682 it++;
683 }
684
685 // LAST SEGMENT (Note: There could be only one and be the first one)
686 it--;
689 {
690 framingInfo |= LteRlcAmHeader::LAST_BYTE;
691 }
692 else
693 {
694 framingInfo |= LteRlcAmHeader::NO_LAST_BYTE;
695 }
696
697 // Set the FramingInfo flag after the calculation
698 rlcAmHeader.SetFramingInfo(framingInfo);
699
700 // Calculate the Polling Bit (5.2.2.1)
702
704 NS_LOG_LOGIC("PDU_WITHOUT_POLL = " << m_pduWithoutPoll);
705 m_byteWithoutPoll += packet->GetSize();
706 NS_LOG_LOGIC("BYTE_WITHOUT_POLL = " << m_byteWithoutPoll);
707
709 ((m_txonBuffer.empty()) && (m_retxBufferSize == 0)) || (m_vtS >= m_vtMs) ||
711 {
716
717 m_pollSn = m_vtS - 1;
718 NS_LOG_LOGIC("New POLL_SN = " << m_pollSn);
719
721 {
722 NS_LOG_LOGIC("Start PollRetransmit timer");
723
726 this);
727 }
728 else
729 {
730 NS_LOG_LOGIC("Restart PollRetransmit timer");
731
735 this);
736 }
737 }
738
739 // Build RLC PDU with DataField and Header
740 NS_LOG_LOGIC("AM RLC header: " << rlcAmHeader);
741
742 RlcTag rlcTag;
744
745 packet->AddHeader(rlcAmHeader);
746 packet->AddByteTag(rlcTag, 1, rlcAmHeader.GetSerializedSize());
747
748 // Store new PDU into the Transmitted PDU Buffer
749 NS_LOG_LOGIC("Put transmitted PDU in the txedBuffer");
750 m_txedBufferSize += packet->GetSize();
751 m_txedBuffer.at(rlcAmHeader.GetSequenceNumber().GetValue()).m_pdu = packet->Copy();
752 m_txedBuffer.at(rlcAmHeader.GetSequenceNumber().GetValue()).m_retxCount = 0;
753 m_txedBuffer.at(rlcAmHeader.GetSequenceNumber().GetValue()).m_waitingSince = Simulator::Now();
754
755 m_txPdu(m_rnti, m_lcid, packet->GetSize());
756
757 // Send RLC PDU to MAC layer
759 params.pdu = packet;
760 params.rnti = m_rnti;
761 params.lcid = m_lcid;
762 params.layer = txOpParams.layer;
763 params.harqProcessId = txOpParams.harqId;
764 params.componentCarrierId = txOpParams.componentCarrierId;
765
767}
768
769void
774
775void
777{
778 NS_LOG_FUNCTION(this << m_rnti << (uint32_t)m_lcid << rxPduParams.p->GetSize());
779
780 // Get RLC header parameters
781 LteRlcAmHeader rlcAmHeader;
782 rxPduParams.p->PeekHeader(rlcAmHeader);
783 NS_LOG_LOGIC("RLC header: " << rlcAmHeader);
784
785 // Receiver timestamp
786 Time delay;
787 RlcTag rlcTag;
788
789 bool ret = rxPduParams.p->FindFirstMatchingByteTag(rlcTag);
790 NS_ASSERT_MSG(ret, "RlcTag not found in RLC Header. The packet went into a real network?");
791
792 delay = Simulator::Now() - rlcTag.GetSenderTimestamp();
793
794 m_rxPdu(m_rnti, m_lcid, rxPduParams.p->GetSize(), delay.GetNanoSeconds());
795
796 if (rlcAmHeader.IsDataPdu())
797 {
798 // 5.1.3.1 Transmit operations
799
800 // 5.1.3.1.1 General
801 //
802 // The transmitting side of an AM RLC entity shall prioritize transmission of RLC control
803 // PDUs over RLC data PDUs. The transmitting side of an AM RLC entity shall prioritize
804 // retransmission of RLC data PDUs over transmission of new AMD PDUs.
805 //
806 // The transmitting side of an AM RLC entity shall maintain a transmitting window according
807 // to state variables VT(A) and VT(MS) as follows:
808 // - a SN falls within the transmitting window if VT(A) <= SN < VT(MS);
809 // - a SN falls outside of the transmitting window otherwise.
810 //
811 // The transmitting side of an AM RLC entity shall not deliver to lower layer any RLC data
812 // PDU whose SN falls outside of the transmitting window.
813 //
814 // When delivering a new AMD PDU to lower layer, the transmitting side of an AM RLC entity
815 // shall:
816 // - set the SN of the AMD PDU to VT(S), and then increment VT(S) by one.
817 //
818 // The transmitting side of an AM RLC entity can receive a positive acknowledgement
819 // (confirmation of successful reception by its peer AM RLC entity) for a RLC data PDU by
820 // the following:
821 // - STATUS PDU from its peer AM RLC entity.
822 //
823 // When receiving a positive acknowledgement for an AMD PDU with SN = VT(A), the
824 // transmitting side of an AM RLC entity shall:
825 // - set VT(A) equal to the SN of the AMD PDU with the smallest SN, whose SN falls within
826 // the
827 // range VT(A) <= SN <= VT(S) and for which a positive acknowledgment has not been
828 // received yet.
829 // - if positive acknowledgements have been received for all AMD PDUs associated with
830 // a transmitted RLC SDU:
831 // - send an indication to the upper layers of successful delivery of the RLC SDU.
832
833 // 5.1.3.2 Receive operations
834 //
835 // 5.1.3.2.1 General
836 //
837 // The receiving side of an AM RLC entity shall maintain a receiving window according to
838 // state variables VR(R) and VR(MR) as follows:
839 // - a SN falls within the receiving window if VR(R) <= SN < VR(MR);
840 // - a SN falls outside of the receiving window otherwise.
841 //
842 // When receiving a RLC data PDU from lower layer, the receiving side of an AM RLC entity
843 // shall:
844 // - either discard the received RLC data PDU or place it in the reception buffer (see sub
845 // clause 5.1.3.2.2);
846 // - if the received RLC data PDU was placed in the reception buffer:
847 // - update state variables, reassemble and deliver RLC SDUs to upper layer and start/stop
848 // t-Reordering as needed (see sub clause 5.1.3.2.3).
849 //
850 // When t-Reordering expires, the receiving side of an AM RLC entity shall:
851 // - update state variables and start t-Reordering as needed (see sub clause 5.1.3.2.4).
852
853 SequenceNumber10 seqNumber = rlcAmHeader.GetSequenceNumber();
854 seqNumber.SetModulusBase(m_vrR);
855
857 {
858 NS_LOG_LOGIC("PDU segment received ( SN = " << seqNumber << " )");
859 }
860 else if (rlcAmHeader.GetResegmentationFlag() == LteRlcAmHeader::PDU)
861 {
862 NS_LOG_LOGIC("PDU received ( SN = " << seqNumber << " )");
863 }
864 else
865 {
866 NS_ASSERT_MSG(false, "Neither a PDU segment nor a PDU received");
867 return;
868 }
869
870 // STATUS PDU is requested
872 {
875
877 {
879 }
880 }
881
882 // 5.1.3.2.2 Actions when a RLC data PDU is received from lower layer
883 //
884 // When a RLC data PDU is received from lower layer, where the RLC data PDU contains
885 // byte segment numbers y to z of an AMD PDU with SN = x, the receiving side of an AM RLC
886 // entity shall:
887 // - if x falls outside of the receiving window; or
888 // - if byte segment numbers y to z of the AMD PDU with SN = x have been received before:
889 // - discard the received RLC data PDU;
890 // - else:
891 // - place the received RLC data PDU in the reception buffer;
892 // - if some byte segments of the AMD PDU contained in the RLC data PDU have been
893 // received before:
894 // - discard the duplicate byte segments.
895
896 NS_LOG_LOGIC("VR(R) = " << m_vrR);
897 NS_LOG_LOGIC("VR(MR) = " << m_vrMr);
898 NS_LOG_LOGIC("VR(X) = " << m_vrX);
899 NS_LOG_LOGIC("VR(MS) = " << m_vrMs);
900 NS_LOG_LOGIC("VR(H) = " << m_vrH);
901
902 // - if x falls outside of the receiving window; or
903 // - if byte segment numbers y to z of the AMD PDU with SN = x have been received before:
904 if (!IsInsideReceivingWindow(seqNumber))
905 {
906 NS_LOG_LOGIC("PDU discarded");
907 return;
908 }
909 else
910 {
911 // - if some byte segments of the AMD PDU contained in the RLC data PDU have been
912 // received before:
913 // - discard the duplicate byte segments.
914 // note: re-segmentation of AMD PDU is currently not supported,
915 // so we just check that the segment was not received before
916 auto it = m_rxonBuffer.find(seqNumber.GetValue());
917 if (it != m_rxonBuffer.end())
918 {
919 NS_ASSERT(!it->second.m_byteSegments.empty());
920 NS_ASSERT_MSG(it->second.m_byteSegments.size() == 1,
921 "re-segmentation not supported");
922 NS_LOG_LOGIC("PDU segment already received, discarded");
923 }
924 else
925 {
926 NS_LOG_LOGIC("Place PDU in the reception buffer ( SN = " << seqNumber << " )");
927 m_rxonBuffer[seqNumber.GetValue()].m_byteSegments.push_back(rxPduParams.p);
928 m_rxonBuffer[seqNumber.GetValue()].m_pduComplete = true;
929 }
930 }
931
932 // 5.1.3.2.3 Actions when a RLC data PDU is placed in the reception buffer
933 // When a RLC data PDU with SN = x is placed in the reception buffer,
934 // the receiving side of an AM RLC entity shall:
935
936 // - if x >= VR(H)
937 // - update VR(H) to x+ 1;
938
939 if (seqNumber >= m_vrH)
940 {
941 m_vrH = seqNumber + 1;
942 NS_LOG_LOGIC("New VR(H) = " << m_vrH);
943 }
944
945 // - if all byte segments of the AMD PDU with SN = VR(MS) are received:
946 // - update VR(MS) to the SN of the first AMD PDU with SN > current VR(MS) for
947 // which not all byte segments have been received;
948
949 auto it = m_rxonBuffer.find(m_vrMs.GetValue());
950 if (it != m_rxonBuffer.end() && it->second.m_pduComplete)
951 {
952 int firstVrMs = m_vrMs.GetValue();
953 while (it != m_rxonBuffer.end() && it->second.m_pduComplete)
954 {
955 m_vrMs++;
956 it = m_rxonBuffer.find(m_vrMs.GetValue());
957 NS_LOG_LOGIC("Incr VR(MS) = " << m_vrMs);
958
959 NS_ASSERT_MSG(firstVrMs != m_vrMs.GetValue(), "Infinite loop in RxonBuffer");
960 }
961 NS_LOG_LOGIC("New VR(MS) = " << m_vrMs);
962 }
963
964 // - if x = VR(R):
965 // - if all byte segments of the AMD PDU with SN = VR(R) are received:
966 // - update VR(R) to the SN of the first AMD PDU with SN > current VR(R) for which
967 // not all byte segments have been received;
968 // - update VR(MR) to the updated VR(R) + AM_Window_Size;
969 // - reassemble RLC SDUs from any byte segments of AMD PDUs with SN that falls outside
970 // of the receiving window and in-sequence byte segments of the AMD PDU with SN = VR(R),
971 // remove RLC headers when doing so and deliver the reassembled RLC SDUs to upper layer
972 // in sequence if not delivered before;
973
974 if (seqNumber == m_vrR)
975 {
976 auto it = m_rxonBuffer.find(seqNumber.GetValue());
977 if (it != m_rxonBuffer.end() && it->second.m_pduComplete)
978 {
979 it = m_rxonBuffer.find(m_vrR.GetValue());
980 int firstVrR = m_vrR.GetValue();
981 while (it != m_rxonBuffer.end() && it->second.m_pduComplete)
982 {
983 NS_LOG_LOGIC("Reassemble and Deliver ( SN = " << m_vrR << " )");
984 NS_ASSERT_MSG(it->second.m_byteSegments.size() == 1,
985 "Too many segments. PDU Reassembly process didn't work");
986 ReassembleAndDeliver(it->second.m_byteSegments.front());
987 m_rxonBuffer.erase(m_vrR.GetValue());
988
989 m_vrR++;
994 it = m_rxonBuffer.find(m_vrR.GetValue());
995
996 NS_ASSERT_MSG(firstVrR != m_vrR.GetValue(), "Infinite loop in RxonBuffer");
997 }
998 NS_LOG_LOGIC("New VR(R) = " << m_vrR);
1000
1001 NS_LOG_LOGIC("New VR(MR) = " << m_vrMr);
1002 }
1003 }
1004
1005 // - if t-Reordering is running:
1006 // - if VR(X) = VR(R); or
1007 // - if VR(X) falls outside of the receiving window and VR(X) is not equal to VR(MR):
1008 // - stop and reset t-Reordering;
1009
1011 {
1012 NS_LOG_LOGIC("Reordering timer is running");
1013 if ((m_vrX == m_vrR) || ((!IsInsideReceivingWindow(m_vrX)) && (m_vrX != m_vrMr)))
1014 {
1015 /// \todo stop and reset the t-Reordering
1016 NS_LOG_LOGIC("Stop reordering timer");
1018 }
1019 }
1020
1021 // - if t-Reordering is not running (includes the case t-Reordering is stopped due to
1022 // actions above):
1023 // - if VR (H) > VR(R):
1024 // - start t-Reordering;
1025 // - set VR(X) to VR(H).
1026
1028 {
1029 NS_LOG_LOGIC("Reordering timer is not running");
1030 if (m_vrH > m_vrR)
1031 {
1032 NS_LOG_LOGIC("Start reordering timer");
1035 this);
1036 m_vrX = m_vrH;
1037 NS_LOG_LOGIC("New VR(X) = " << m_vrX);
1038 }
1039 }
1040 }
1041 else if (rlcAmHeader.IsControlPdu())
1042 {
1043 NS_LOG_INFO("Control AM RLC PDU");
1044
1045 SequenceNumber10 ackSn = rlcAmHeader.GetAckSn();
1047
1048 NS_LOG_INFO("ackSn = " << ackSn);
1049 NS_LOG_INFO("VT(A) = " << m_vtA);
1050 NS_LOG_INFO("VT(S) = " << m_vtS);
1051 NS_LOG_LOGIC("retxBufferSize = " << m_retxBufferSize);
1052 NS_LOG_LOGIC("txedBufferSize = " << m_txedBufferSize);
1053
1057 ackSn.SetModulusBase(m_vtA);
1059
1060 bool incrementVtA = true;
1061
1062 for (sn = m_vtA; sn < ackSn && sn < m_vtS; sn++)
1063 {
1064 NS_LOG_LOGIC("sn = " << sn);
1065
1066 uint16_t seqNumberValue = sn.GetValue();
1067
1068 if (m_pollRetransmitTimer.IsPending() && (seqNumberValue == m_pollSn.GetValue()))
1069 {
1071 }
1072
1073 if (rlcAmHeader.IsNackPresent(sn))
1074 {
1075 NS_LOG_LOGIC("sn " << sn << " is NACKed");
1076
1077 incrementVtA = false;
1078
1079 if (m_txedBuffer.at(seqNumberValue).m_pdu)
1080 {
1081 NS_LOG_INFO("Move SN = " << seqNumberValue << " to retxBuffer");
1082 m_retxBuffer.at(seqNumberValue).m_pdu =
1083 m_txedBuffer.at(seqNumberValue).m_pdu->Copy();
1084 m_retxBuffer.at(seqNumberValue).m_retxCount =
1085 m_txedBuffer.at(seqNumberValue).m_retxCount;
1086 m_retxBuffer.at(seqNumberValue).m_waitingSince =
1087 m_txedBuffer.at(seqNumberValue).m_waitingSince;
1088 m_retxBufferSize += m_retxBuffer.at(seqNumberValue).m_pdu->GetSize();
1089
1090 m_txedBufferSize -= m_txedBuffer.at(seqNumberValue).m_pdu->GetSize();
1091 m_txedBuffer.at(seqNumberValue).m_pdu = nullptr;
1092 m_txedBuffer.at(seqNumberValue).m_retxCount = 0;
1093 m_txedBuffer.at(seqNumberValue).m_waitingSince = MilliSeconds(0);
1094 }
1095
1096 NS_ASSERT(m_retxBuffer.at(seqNumberValue).m_pdu);
1097 }
1098 else
1099 {
1100 NS_LOG_LOGIC("sn " << sn << " is ACKed");
1101
1102 if (m_txedBuffer.at(seqNumberValue).m_pdu)
1103 {
1104 NS_LOG_INFO("ACKed SN = " << seqNumberValue << " from txedBuffer");
1105 // NS_LOG_INFO ("m_txedBuffer( " << m_vtA << " )->GetSize = " <<
1106 // m_txedBuffer.at (m_vtA.GetValue ())->GetSize ());
1107 m_txedBufferSize -= m_txedBuffer.at(seqNumberValue).m_pdu->GetSize();
1108 m_txedBuffer.at(seqNumberValue).m_pdu = nullptr;
1109 m_txedBuffer.at(seqNumberValue).m_waitingSince = MilliSeconds(0);
1110 NS_ASSERT(!m_retxBuffer.at(seqNumberValue).m_pdu);
1111 }
1112
1113 if (m_retxBuffer.at(seqNumberValue).m_pdu)
1114 {
1115 NS_LOG_INFO("ACKed SN = " << seqNumberValue << " from retxBuffer");
1116 m_retxBufferSize -= m_retxBuffer.at(seqNumberValue).m_pdu->GetSize();
1117 m_retxBuffer.at(seqNumberValue).m_pdu = nullptr;
1118 m_retxBuffer.at(seqNumberValue).m_retxCount = 0;
1119 m_retxBuffer.at(seqNumberValue).m_waitingSince = MilliSeconds(0);
1120 }
1121 }
1122
1123 NS_LOG_LOGIC("retxBufferSize = " << m_retxBufferSize);
1124 NS_LOG_LOGIC("txedBufferSize = " << m_txedBufferSize);
1125
1126 if (incrementVtA)
1127 {
1128 m_vtA++;
1130 NS_LOG_INFO("New VT(A) = " << m_vtA);
1134 ackSn.SetModulusBase(m_vtA);
1136 }
1137
1138 } // loop over SN : VT(A) <= SN < ACK SN
1139
1140 return;
1141 }
1142 else
1143 {
1144 NS_LOG_WARN("Wrong AM RLC PDU type");
1145 return;
1146 }
1147}
1148
1149bool
1151{
1152 NS_LOG_FUNCTION(this << seqNumber);
1153 NS_LOG_LOGIC("Receiving Window: " << m_vrR << " <= " << seqNumber << " <= " << m_vrMr);
1154
1157 seqNumber.SetModulusBase(m_vrR);
1158
1159 if ((m_vrR <= seqNumber) && (seqNumber < m_vrMr))
1160 {
1161 NS_LOG_LOGIC(seqNumber << " is INSIDE the receiving window");
1162 return true;
1163 }
1164 else
1165 {
1166 NS_LOG_LOGIC(seqNumber << " is OUTSIDE the receiving window");
1167 return false;
1168 }
1169}
1170
1171void
1173{
1174 LteRlcAmHeader rlcAmHeader;
1175 RlcTag rlcTag;
1176 bool ret = packet->FindFirstMatchingByteTag(rlcTag);
1177 NS_ASSERT(ret);
1178 packet->RemoveHeader(rlcAmHeader);
1179 ret = packet->FindFirstMatchingByteTag(rlcTag);
1180 NS_ASSERT(!ret);
1181 uint8_t framingInfo = rlcAmHeader.GetFramingInfo();
1182 SequenceNumber10 currSeqNumber = rlcAmHeader.GetSequenceNumber();
1183 bool expectedSnLost;
1184
1185 if (currSeqNumber != m_expectedSeqNumber)
1186 {
1187 expectedSnLost = true;
1188 NS_LOG_LOGIC("There are losses. Expected SN = " << m_expectedSeqNumber
1189 << ". Current SN = " << currSeqNumber);
1190 m_expectedSeqNumber = currSeqNumber + 1;
1191 }
1192 else
1193 {
1194 expectedSnLost = false;
1195 NS_LOG_LOGIC("No losses. Expected SN = " << m_expectedSeqNumber
1196 << ". Current SN = " << currSeqNumber);
1198 }
1199
1200 // Build list of SDUs
1201 uint8_t extensionBit;
1202 uint16_t lengthIndicator;
1203 do
1204 {
1205 extensionBit = rlcAmHeader.PopExtensionBit();
1206 NS_LOG_LOGIC("E = " << (uint16_t)extensionBit);
1207
1208 if (extensionBit == 0)
1209 {
1210 m_sdusBuffer.push_back(packet);
1211 }
1212 else // extensionBit == 1
1213 {
1214 lengthIndicator = rlcAmHeader.PopLengthIndicator();
1215 NS_LOG_LOGIC("LI = " << lengthIndicator);
1216
1217 // Check if there is enough data in the packet
1218 if (lengthIndicator >= packet->GetSize())
1219 {
1220 NS_LOG_LOGIC("INTERNAL ERROR: Not enough data in the packet ("
1221 << packet->GetSize() << "). Needed LI=" << lengthIndicator);
1222 /// \todo What to do in this case? Discard packet and continue? Or Assert?
1223 }
1224
1225 // Split packet in two fragments
1226 Ptr<Packet> data_field = packet->CreateFragment(0, lengthIndicator);
1227 packet->RemoveAtStart(lengthIndicator);
1228
1229 m_sdusBuffer.push_back(data_field);
1230 }
1231 } while (extensionBit == 1);
1232
1233 // Current reassembling state
1235 {
1236 NS_LOG_LOGIC("Reassembling State = 'WAITING_S0_FULL'");
1237 }
1239 {
1240 NS_LOG_LOGIC("Reassembling State = 'WAITING_SI_SF'");
1241 }
1242 else
1243 {
1244 NS_LOG_LOGIC("Reassembling State = Unknown state");
1245 }
1246
1247 // Received framing Info
1248 NS_LOG_LOGIC("Framing Info = " << (uint16_t)framingInfo);
1249 NS_LOG_LOGIC("m_sdusBuffer = " << m_sdusBuffer.size());
1250
1251 // Reassemble the list of SDUs (when there is no losses)
1252 if (!expectedSnLost)
1253 {
1254 switch (m_reassemblingState)
1255 {
1256 case WAITING_S0_FULL:
1257 switch (framingInfo)
1258 {
1261
1262 /**
1263 * Deliver one or multiple PDUs
1264 */
1265 for (auto it = m_sdusBuffer.begin(); it != m_sdusBuffer.end(); it++)
1266 {
1268 }
1269 m_sdusBuffer.clear();
1270 break;
1271
1274
1275 /**
1276 * Deliver full PDUs
1277 */
1278 while (m_sdusBuffer.size() > 1)
1279 {
1281 m_sdusBuffer.pop_front();
1282 }
1283
1284 /**
1285 * Keep S0
1286 */
1287 m_keepS0 = m_sdusBuffer.front();
1288 m_sdusBuffer.pop_front();
1289 break;
1290
1293 default:
1294 /**
1295 * ERROR: Transition not possible
1296 */
1298 "INTERNAL ERROR: Transition not possible. FI = " << (uint32_t)framingInfo);
1299 break;
1300 }
1301 break;
1302
1303 case WAITING_SI_SF:
1304 switch (framingInfo)
1305 {
1308
1309 /**
1310 * Deliver (Kept)S0 + SN
1311 */
1312 m_keepS0->AddAtEnd(m_sdusBuffer.front());
1313 m_sdusBuffer.pop_front();
1315
1316 /**
1317 * Deliver zero, one or multiple PDUs
1318 */
1319 while (!m_sdusBuffer.empty())
1320 {
1322 m_sdusBuffer.pop_front();
1323 }
1324 break;
1325
1328
1329 /**
1330 * Keep SI
1331 */
1332 if (m_sdusBuffer.size() == 1)
1333 {
1334 m_keepS0->AddAtEnd(m_sdusBuffer.front());
1335 m_sdusBuffer.pop_front();
1336 }
1337 else // m_sdusBuffer.size () > 1
1338 {
1339 /**
1340 * Deliver (Kept)S0 + SN
1341 */
1342 m_keepS0->AddAtEnd(m_sdusBuffer.front());
1343 m_sdusBuffer.pop_front();
1345
1346 /**
1347 * Deliver zero, one or multiple PDUs
1348 */
1349 while (m_sdusBuffer.size() > 1)
1350 {
1352 m_sdusBuffer.pop_front();
1353 }
1354
1355 /**
1356 * Keep S0
1357 */
1358 m_keepS0 = m_sdusBuffer.front();
1359 m_sdusBuffer.pop_front();
1360 }
1361 break;
1362
1365 default:
1366 /**
1367 * ERROR: Transition not possible
1368 */
1370 "INTERNAL ERROR: Transition not possible. FI = " << (uint32_t)framingInfo);
1371 break;
1372 }
1373 break;
1374
1375 default:
1377 "INTERNAL ERROR: Wrong reassembling state = " << (uint32_t)m_reassemblingState);
1378 break;
1379 }
1380 }
1381 else // Reassemble the list of SDUs (when there are losses, i.e. the received SN is not the
1382 // expected one)
1383 {
1384 switch (m_reassemblingState)
1385 {
1386 case WAITING_S0_FULL:
1387 switch (framingInfo)
1388 {
1391
1392 /**
1393 * Deliver one or multiple PDUs
1394 */
1395 for (auto it = m_sdusBuffer.begin(); it != m_sdusBuffer.end(); it++)
1396 {
1398 }
1399 m_sdusBuffer.clear();
1400 break;
1401
1404
1405 /**
1406 * Deliver full PDUs
1407 */
1408 while (m_sdusBuffer.size() > 1)
1409 {
1411 m_sdusBuffer.pop_front();
1412 }
1413
1414 /**
1415 * Keep S0
1416 */
1417 m_keepS0 = m_sdusBuffer.front();
1418 m_sdusBuffer.pop_front();
1419 break;
1420
1423
1424 /**
1425 * Discard SN
1426 */
1427 m_sdusBuffer.pop_front();
1428
1429 /**
1430 * Deliver zero, one or multiple PDUs
1431 */
1432 while (!m_sdusBuffer.empty())
1433 {
1435 m_sdusBuffer.pop_front();
1436 }
1437 break;
1438
1440 if (m_sdusBuffer.size() == 1)
1441 {
1443 }
1444 else
1445 {
1447 }
1448
1449 /**
1450 * Discard SI or SN
1451 */
1452 m_sdusBuffer.pop_front();
1453
1454 if (!m_sdusBuffer.empty())
1455 {
1456 /**
1457 * Deliver zero, one or multiple PDUs
1458 */
1459 while (m_sdusBuffer.size() > 1)
1460 {
1462 m_sdusBuffer.pop_front();
1463 }
1464
1465 /**
1466 * Keep S0
1467 */
1468 m_keepS0 = m_sdusBuffer.front();
1469 m_sdusBuffer.pop_front();
1470 }
1471 break;
1472
1473 default:
1474 /**
1475 * ERROR: Transition not possible
1476 */
1478 "INTERNAL ERROR: Transition not possible. FI = " << (uint32_t)framingInfo);
1479 break;
1480 }
1481 break;
1482
1483 case WAITING_SI_SF:
1484 switch (framingInfo)
1485 {
1488
1489 /**
1490 * Discard S0
1491 */
1492 m_keepS0 = nullptr;
1493
1494 /**
1495 * Deliver one or multiple PDUs
1496 */
1497 while (!m_sdusBuffer.empty())
1498 {
1500 m_sdusBuffer.pop_front();
1501 }
1502 break;
1503
1506
1507 /**
1508 * Discard S0
1509 */
1510 m_keepS0 = nullptr;
1511
1512 /**
1513 * Deliver zero, one or multiple PDUs
1514 */
1515 while (m_sdusBuffer.size() > 1)
1516 {
1518 m_sdusBuffer.pop_front();
1519 }
1520
1521 /**
1522 * Keep S0
1523 */
1524 m_keepS0 = m_sdusBuffer.front();
1525 m_sdusBuffer.pop_front();
1526
1527 break;
1528
1531
1532 /**
1533 * Discard S0
1534 */
1535 m_keepS0 = nullptr;
1536
1537 /**
1538 * Discard SI or SN
1539 */
1540 m_sdusBuffer.pop_front();
1541
1542 /**
1543 * Deliver zero, one or multiple PDUs
1544 */
1545 while (!m_sdusBuffer.empty())
1546 {
1548 m_sdusBuffer.pop_front();
1549 }
1550 break;
1551
1553 if (m_sdusBuffer.size() == 1)
1554 {
1556 }
1557 else
1558 {
1560 }
1561
1562 /**
1563 * Discard S0
1564 */
1565 m_keepS0 = nullptr;
1566
1567 /**
1568 * Discard SI or SN
1569 */
1570 m_sdusBuffer.pop_front();
1571
1572 if (!m_sdusBuffer.empty())
1573 {
1574 /**
1575 * Deliver zero, one or multiple PDUs
1576 */
1577 while (m_sdusBuffer.size() > 1)
1578 {
1580 m_sdusBuffer.pop_front();
1581 }
1582
1583 /**
1584 * Keep S0
1585 */
1586 m_keepS0 = m_sdusBuffer.front();
1587 m_sdusBuffer.pop_front();
1588 }
1589 break;
1590
1591 default:
1592 /**
1593 * ERROR: Transition not possible
1594 */
1596 "INTERNAL ERROR: Transition not possible. FI = " << (uint32_t)framingInfo);
1597 break;
1598 }
1599 break;
1600
1601 default:
1603 "INTERNAL ERROR: Wrong reassembling state = " << (uint32_t)m_reassemblingState);
1604 break;
1605 }
1606 }
1607}
1608
1609void
1611{
1612 NS_LOG_FUNCTION(this);
1613
1614 Time now = Simulator::Now();
1615
1616 NS_LOG_LOGIC("txonBufferSize = " << m_txonBufferSize);
1617 NS_LOG_LOGIC("retxBufferSize = " << m_retxBufferSize);
1618 NS_LOG_LOGIC("txedBufferSize = " << m_txedBufferSize);
1619 NS_LOG_LOGIC("VT(A) = " << m_vtA);
1620 NS_LOG_LOGIC("VT(S) = " << m_vtS);
1621
1622 // Transmission Queue HOL time
1623 Time txonQueueHolDelay(0);
1624 if (m_txonBufferSize > 0)
1625 {
1626 txonQueueHolDelay = now - m_txonBuffer.front().m_waitingSince;
1627 }
1628
1629 // Retransmission Queue HOL time
1630 Time retxQueueHolDelay;
1631 if (m_retxBufferSize > 0)
1632 {
1633 Time senderTimestamp;
1634 if (m_retxBuffer.at(m_vtA.GetValue()).m_pdu)
1635 {
1636 senderTimestamp = m_retxBuffer.at(m_vtA.GetValue()).m_waitingSince;
1637 }
1638 else
1639 {
1640 senderTimestamp = m_txedBuffer.at(m_vtA.GetValue()).m_waitingSince;
1641 }
1642 retxQueueHolDelay = now - senderTimestamp;
1643 }
1644 else
1645 {
1646 retxQueueHolDelay = Seconds(0);
1647 }
1648
1650 r.rnti = m_rnti;
1651 r.lcid = m_lcid;
1653 r.txQueueHolDelay = txonQueueHolDelay.GetMilliSeconds();
1655 r.retxQueueHolDelay = retxQueueHolDelay.GetMilliSeconds();
1656
1658 {
1660 }
1661 else
1662 {
1663 r.statusPduSize = 0;
1664 }
1665
1666 if (r.txQueueSize != 0 || r.retxQueueSize != 0 || r.statusPduSize != 0)
1667 {
1668 NS_LOG_INFO("Send ReportBufferStatus: " << r.txQueueSize << ", " << r.txQueueHolDelay
1669 << ", " << r.retxQueueSize << ", "
1670 << r.retxQueueHolDelay << ", " << r.statusPduSize);
1672 }
1673 else
1674 {
1675 NS_LOG_INFO("ReportBufferStatus don't needed");
1676 }
1677}
1678
1679void
1681{
1682 NS_LOG_FUNCTION(this);
1683 NS_LOG_LOGIC("Reordering Timer has expired");
1684
1685 // 5.1.3.2.4 Actions when t-Reordering expires
1686 // When t-Reordering expires, the receiving side of an AM RLC entity shall:
1687 // - update VR(MS) to the SN of the first AMD PDU with SN >= VR(X) for which not all byte
1688 // segments
1689 // have been received;
1690 // - if VR(H) > VR(MS):
1691 // - start t-Reordering;
1692 // - set VR(X) to VR(H).
1693
1694 m_vrMs = m_vrX;
1695 int firstVrMs = m_vrMs.GetValue();
1696 auto it = m_rxonBuffer.find(m_vrMs.GetValue());
1697 while (it != m_rxonBuffer.end() && it->second.m_pduComplete)
1698 {
1699 m_vrMs++;
1700 it = m_rxonBuffer.find(m_vrMs.GetValue());
1701
1702 NS_ASSERT_MSG(firstVrMs != m_vrMs.GetValue(), "Infinite loop in ExpireReorderingTimer");
1703 }
1704 NS_LOG_LOGIC("New VR(MS) = " << m_vrMs);
1705
1706 if (m_vrH > m_vrMs)
1707 {
1708 NS_LOG_LOGIC("Start reordering timer");
1711 m_vrX = m_vrH;
1712 NS_LOG_LOGIC("New VR(MS) = " << m_vrMs);
1713 }
1714
1715 // Section 5.2.3 Status Reporting:
1716 // - The receiving side of an AM RLC entity shall trigger a
1717 // STATUS report when T_reordering expires.
1718 m_statusPduRequested = true;
1719}
1720
1721void
1723{
1724 NS_LOG_FUNCTION(this);
1725 NS_LOG_LOGIC("PollRetransmit Timer has expired");
1726
1727 NS_LOG_LOGIC("txonBufferSize = " << m_txonBufferSize);
1728 NS_LOG_LOGIC("retxBufferSize = " << m_retxBufferSize);
1729 NS_LOG_LOGIC("txedBufferSize = " << m_txedBufferSize);
1730 NS_LOG_LOGIC("statusPduRequested = " << m_statusPduRequested);
1731
1733
1734 // see section 5.2.2.3
1735 // note the difference between Rel 8 and Rel 11 specs; we follow Rel 11 here
1737 if ((m_txonBufferSize == 0 && m_retxBufferSize == 0) || (m_vtS == m_vtMs))
1738 {
1739 NS_LOG_INFO("txonBuffer and retxBuffer empty. Move PDUs up to = " << m_vtS.GetValue() - 1
1740 << " to retxBuffer");
1741 for (SequenceNumber10 sn = m_vtA; sn < m_vtS; sn++)
1742 {
1743 bool pduAvailable = (bool)m_txedBuffer.at(sn.GetValue()).m_pdu;
1744
1745 if (pduAvailable)
1746 {
1747 uint16_t snValue = sn.GetValue();
1748 NS_LOG_INFO("Move PDU " << sn << " from txedBuffer to retxBuffer");
1749 m_retxBuffer.at(snValue).m_pdu = m_txedBuffer.at(snValue).m_pdu->Copy();
1750 m_retxBuffer.at(snValue).m_retxCount = m_txedBuffer.at(snValue).m_retxCount;
1751 m_retxBuffer.at(snValue).m_waitingSince = m_txedBuffer.at(snValue).m_waitingSince;
1752 m_retxBufferSize += m_retxBuffer.at(snValue).m_pdu->GetSize();
1753
1754 m_txedBufferSize -= m_txedBuffer.at(snValue).m_pdu->GetSize();
1755 m_txedBuffer.at(snValue).m_pdu = nullptr;
1756 m_txedBuffer.at(snValue).m_retxCount = 0;
1757 m_txedBuffer.at(snValue).m_waitingSince = MilliSeconds(0);
1758 }
1759 }
1760 }
1761
1763}
1764
1765void
1770
1771void
1782
1783} // namespace ns3
AttributeValue implementation for Boolean.
Definition boolean.h:26
void Cancel()
This method is syntactic sugar for the ns3::Simulator::Cancel method.
Definition event-id.cc:44
bool IsPending() const
This method is syntactic sugar for !IsExpired().
Definition event-id.cc:65
virtual void TransmitPdu(TransmitPduParameters params)=0
send an RLC PDU to the MAC for transmission.
virtual void ReportBufferStatus(ReportBufferStatusParameters params)=0
Report the RLC buffer status to the MAC.
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.
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
void SetLastSegmentFlag(uint8_t lsf)
Set last segment flag function.
void PushNack(int nack)
Add one more NACK to the CONTROL PDU.
void SetFramingInfo(uint8_t framingInfo)
Set sequence number.
static constexpr uint8_t STATUS_PDU
Control PDU type status.
uint16_t PopLengthIndicator()
Pop length indicator function.
void SetAckSn(SequenceNumber10 ackSn)
Set ack sn function.
bool IsControlPdu() const
Is control PDU function.
void SetDataPdu()
Set data PDU function.
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.
bool IsNackPresent(SequenceNumber10 nack)
uint8_t GetFramingInfo() const
Get framing info.
SequenceNumber10 GetSequenceNumber() const
Get sequence number.
void SetControlPdu(uint8_t controlPduType)
Set control PDU function.
void SetSequenceNumber(SequenceNumber10 sequenceNumber)
Set sequence number.
LTE RLC Acknowledged Mode (AM), see 3GPP TS 36.322.
Definition lte-rlc-am.h:27
ReassemblingState_t m_reassemblingState
reassembling state
Definition lte-rlc-am.h:222
void ExpireStatusProhibitTimer()
method called when the T_status_prohibit timer expires
SequenceNumber10 m_vrMr
VR(MR)
Definition lte-rlc-am.h:174
Time m_statusProhibitTimerValue
status prohibit timer value
Definition lte-rlc-am.h:198
bool IsInsideReceivingWindow(SequenceNumber10 seqNumber)
method called when the T_status_prohibit timer expires
uint16_t m_windowSize
Constants.
Definition lte-rlc-am.h:188
Ptr< Packet > m_keepS0
keep S0
Definition lte-rlc-am.h:223
void DoNotifyHarqDeliveryFailure() override
Notify HARQ delivery failure.
SequenceNumber10 m_vrH
VR(H)
Definition lte-rlc-am.h:177
uint32_t m_txonBufferSize
transmit on buffer size
Definition lte-rlc-am.h:138
std::vector< TxPdu > m_txonBuffer
Transmission buffer.
Definition lte-rlc-am.h:122
SequenceNumber10 m_vrMs
VR(MS)
Definition lte-rlc-am.h:176
uint16_t m_pollByte
poll byte
Definition lte-rlc-am.h:207
SequenceNumber10 m_vtS
VT(S)
Definition lte-rlc-am.h:169
void DoDispose() override
Destructor implementation.
SequenceNumber10 m_pollSn
POLL_SN.
Definition lte-rlc-am.h:170
SequenceNumber10 m_vtA
State variables.
Definition lte-rlc-am.h:167
void ExpireReorderingTimer()
This method will schedule a timeout at WaitReplyTimeout interval in the future, unless a timer is alr...
SequenceNumber10 m_vtMs
VT(MS)
Definition lte-rlc-am.h:168
EventId m_rbsTimer
RBS timer.
Definition lte-rlc-am.h:199
~LteRlcAm() override
Definition lte-rlc-am.cc:70
uint32_t m_statusPduBufferSize
status PDU buffer size
Definition lte-rlc-am.h:143
Ptr< Packet > m_controlPduBuffer
Control PDU buffer (just one PDU)
Definition lte-rlc-am.h:156
bool m_txOpportunityForRetxAlwaysBigEnough
transmit opportunity for retransmit?
Definition lte-rlc-am.h:209
bool m_pollRetransmitTimerJustExpired
poll retransmit timer just expired?
Definition lte-rlc-am.h:210
void DoTransmitPdcpPdu(Ptr< Packet > p) override
RLC SAP.
Time m_reorderingTimerValue
reordering timer value
Definition lte-rlc-am.h:196
uint32_t m_maxTxBufferSize
maximum transmission buffer size
Definition lte-rlc-am.h:137
void DoReceivePdu(LteMacSapUser::ReceivePduParameters rxPduParams) override
Receive PDU function.
std::list< Ptr< Packet > > m_sdusBuffer
List of SDUs in a packet (PDU)
Definition lte-rlc-am.h:161
EventId m_pollRetransmitTimer
Timers.
Definition lte-rlc-am.h:193
uint16_t m_maxRetxThreshold
Configurable parameters.
Definition lte-rlc-am.h:205
SequenceNumber10 m_vrX
VR(X)
Definition lte-rlc-am.h:175
std::vector< RetxPdu > m_retxBuffer
Buffer for PDUs considered for retransmission.
Definition lte-rlc-am.h:135
uint32_t m_byteWithoutPoll
byte without poll
Definition lte-rlc-am.h:183
void ExpireRbsTimer()
Expire RBS timer.
uint32_t m_pduWithoutPoll
Counters.
Definition lte-rlc-am.h:182
static TypeId GetTypeId()
Get the type ID.
Definition lte-rlc-am.cc:76
void DoNotifyTxOpportunity(LteMacSapUser::TxOpportunityParameters txOpParams) override
MAC SAP.
Time m_pollRetransmitTimerValue
poll retransmit time value
Definition lte-rlc-am.h:194
void DoReportBufferStatus()
Report buffer status.
void ReassembleAndDeliver(Ptr< Packet > packet)
Reassemble and deliver.
std::map< uint16_t, PduBuffer > m_rxonBuffer
Reception buffer.
Definition lte-rlc-am.h:154
uint32_t m_txedBufferSize
transmit ed buffer size
Definition lte-rlc-am.h:140
uint16_t m_pollPdu
poll PDU
Definition lte-rlc-am.h:206
EventId m_reorderingTimer
reordering timer
Definition lte-rlc-am.h:195
void ExpirePollRetransmitTimer()
Expire poll retransmitter.
SequenceNumber10 m_vrR
VR(R)
Definition lte-rlc-am.h:173
SequenceNumber10 m_expectedSeqNumber
Expected Sequence Number.
Definition lte-rlc-am.h:228
uint32_t m_retxBufferSize
retransmit buffer size
Definition lte-rlc-am.h:139
EventId m_statusProhibitTimer
status prohibit timer
Definition lte-rlc-am.h:197
std::vector< RetxPdu > m_txedBuffer
Buffer for transmitted and retransmitted PDUs that have not been acked but are not considered for ret...
Definition lte-rlc-am.h:132
bool m_statusPduRequested
status PDU requested
Definition lte-rlc-am.h:142
Time m_rbsTimerValue
RBS timer value.
Definition lte-rlc-am.h:200
This abstract base class defines the API to interact with the Radio Link Control (LTE_RLC) in LTE,...
Definition lte-rlc.h:38
LteRlcSapUser * m_rlcSapUser
RLC SAP user.
Definition lte-rlc.h:137
uint8_t m_lcid
LCID.
Definition lte-rlc.h:162
TracedCallback< Ptr< const Packet > > m_txDropTrace
The trace source fired when the RLC drops a packet before transmission.
Definition lte-rlc.h:178
uint16_t m_rnti
RNTI.
Definition lte-rlc.h:161
TracedCallback< uint16_t, uint8_t, uint32_t, uint64_t > m_rxPdu
Used to inform of a PDU reception from the MAC SAP user.
Definition lte-rlc.h:173
void DoDispose() override
Destructor implementation.
Definition lte-rlc.cc:115
LteMacSapProvider * m_macSapProvider
MAC SAP provider.
Definition lte-rlc.h:159
TracedCallback< uint16_t, uint8_t, uint32_t > m_txPdu
Used to inform of a PDU delivery to the MAC SAP provider.
Definition lte-rlc.h:169
virtual void ReceivePdcpPdu(Ptr< Packet > p)=0
Called by the RLC entity to notify the PDCP entity of the reception of a new PDCP PDU.
This class implements a tag that carries the status of a RLC SDU for the fragmentation process Status...
uint8_t GetStatus() const
Get status function.
void SetStatus(uint8_t status)
Set status function.
void AddAtEnd(Ptr< const Packet > packet)
Concatenate the input packet at the end of the current packet.
Definition packet.cc:343
uint32_t GetSize() const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition packet.h:850
bool FindFirstMatchingByteTag(Tag &tag) const
Finds the first tag matching the parameter Tag type.
Definition packet.cc:932
uint32_t PeekHeader(Header &header) const
Deserialize but does not remove the header from the internal buffer.
Definition packet.cc:294
Smart pointer class similar to boost::intrusive_ptr.
Tag to calculate the per-PDU delay from eNb RLC to UE RLC.
Definition lte-rlc-tag.h:25
Time GetSenderTimestamp() const
Get the instant when the RLC delivers the PDU to the MAC SAP provider.
Definition lte-rlc-tag.h:53
void SetSenderTimestamp(Time senderTimestamp)
Set the sender timestamp.
Definition lte-rlc-tag.h:63
SequenceNumber10 class.
uint16_t GetValue() const
Extracts the numeric value of the sequence number.
void SetModulusBase(SequenceNumber10 modulusBase)
Set modulus base.
static EventId Schedule(const Time &delay, FUNC f, Ts &&... args)
Schedule an event to expire after delay.
Definition simulator.h:560
static Time Now()
Return the current simulation virtual time.
Definition simulator.cc:197
Simulation virtual time values and global simulation resolution.
Definition nstime.h:94
int64_t GetNanoSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition nstime.h:407
int64_t GetMilliSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition nstime.h:397
AttributeValue implementation for Time.
Definition nstime.h:1395
a unique identifier for an interface.
Definition type-id.h:48
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
Hold an unsigned integer type.
Definition uinteger.h:34
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
#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:75
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition boolean.cc:113
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition boolean.h:70
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition nstime.h:1396
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition nstime.h:1416
Ptr< const AttributeChecker > MakeUintegerChecker()
Definition uinteger.h:85
Ptr< const AttributeAccessor > MakeUintegerAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method.
Definition uinteger.h:35
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:191
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition log.h:271
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_LOG_WARN(msg)
Use NS_LOG to output a message of level LOG_WARN.
Definition log.h:250
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition log.h:264
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition object-base.h:35
Ptr< T > Create(Ts &&... args)
Create class instances by constructors with varying numbers of arguments and return them by Ptr.
Definition ptr.h:436
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition nstime.h:1308
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition nstime.h:1320
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Parameters for LteMacSapProvider::ReportBufferStatus.
Definition lte-mac-sap.h:58
uint32_t txQueueSize
the current size of the RLC transmission queue
Definition lte-mac-sap.h:61
uint16_t retxQueueHolDelay
the Head Of Line delay of the retransmission queue
Definition lte-mac-sap.h:64
uint16_t txQueueHolDelay
the Head Of Line delay of the transmission queue
Definition lte-mac-sap.h:62
uint32_t retxQueueSize
the current size of the RLC retransmission queue in bytes
Definition lte-mac-sap.h:63
uint8_t lcid
the logical channel id corresponding to the sending RLC instance
Definition lte-mac-sap.h:60
uint16_t rnti
the C-RNTI identifying the UE
Definition lte-mac-sap.h:59
uint16_t statusPduSize
the current size of the pending STATUS RLC PDU message in bytes
Definition lte-mac-sap.h:66
Parameters for LteMacSapProvider::TransmitPdu.
Definition lte-mac-sap.h:34
Parameters for LteMacSapUser::ReceivePdu.
Ptr< Packet > p
the RLC PDU to be received
Parameters for LteMacSapUser::NotifyTxOpportunity.
Definition lte-mac-sap.h:94
uint32_t bytes
the number of bytes to transmit
uint8_t componentCarrierId
the component carrier id
uint8_t layer
the layer of transmission (MIMO)
Store an incoming (from layer above us) PDU, waiting to transmit it.
Definition lte-rlc-am.h:104