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