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 * 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 "lte-rlc-am.h"
22
23#include "lte-rlc-am-header.h"
25#include "lte-rlc-tag.h"
26
27#include "ns3/log.h"
28#include "ns3/simulator.h"
29
30namespace ns3
31{
32
33NS_LOG_COMPONENT_DEFINE("LteRlcAm");
34
36
38{
39 NS_LOG_FUNCTION(this);
40
41 // Buffers
43 m_retxBuffer.resize(1024);
45 m_txedBuffer.resize(1024);
47
50
51 // State variables: transmitting side
52 m_windowSize = 512;
53 m_vtA = 0;
55 m_vtS = 0;
56 m_pollSn = 0;
57
58 // State variables: receiving side
59 m_vrR = 0;
61 m_vrX = 0;
62 m_vrMs = 0;
63 m_vrH = 0;
64
65 // Counters
68
69 // Configurable parameters
71 m_pollPdu = 1;
72 m_pollByte = 50;
73
74 // SDU reassembling process
77
79}
80
82{
83 NS_LOG_FUNCTION(this);
84}
85
88{
89 static TypeId tid =
90 TypeId("ns3::LteRlcAm")
92 .SetGroupName("Lte")
93 .AddConstructor<LteRlcAm>()
94 .AddAttribute("PollRetransmitTimer",
95 "Value of the t-PollRetransmit timer (See section 7.3 of 3GPP TS 36.322)",
99 .AddAttribute("ReorderingTimer",
100 "Value of the t-Reordering timer (See section 7.3 of 3GPP TS 36.322)",
104 .AddAttribute("StatusProhibitTimer",
105 "Value of the t-StatusProhibit timer (See section 7.3 of 3GPP TS 36.322)",
109 .AddAttribute(
110 "ReportBufferStatusTimer",
111 "How much to wait to issue a new Report Buffer Status since the last time "
112 "a new SDU was received",
116 .AddAttribute("TxOpportunityForRetxAlwaysBigEnough",
117 "If true, always pretend that the size of a TxOpportunity is big enough "
118 "for retransmission. If false (default and realistic behavior), no retx "
119 "is performed unless the corresponding TxOpportunity is big enough.",
120 BooleanValue(false),
123 .AddAttribute("MaxTxBufferSize",
124 "Maximum Size of the Transmission Buffer (in Bytes). If zero is "
125 "configured, the buffer is unlimited.",
126 UintegerValue(10 * 1024),
128 MakeUintegerChecker<uint32_t>());
129 return tid;
130}
131
132void
134{
135 NS_LOG_FUNCTION(this);
140
142 m_txonBuffer.clear();
144 m_txedBuffer.clear();
146 m_retxBuffer.clear();
148 m_rxonBuffer.clear();
149 m_sdusBuffer.clear();
150 m_keepS0 = nullptr;
151 m_controlPduBuffer = nullptr;
152
154}
155
156/**
157 * RLC SAP
158 */
159
160void
162{
163 NS_LOG_FUNCTION(this << m_rnti << (uint32_t)m_lcid << p->GetSize());
164
165 if (m_txonBufferSize + p->GetSize() <= m_maxTxBufferSize || (m_maxTxBufferSize == 0))
166 {
167 /** Store PDCP PDU */
170 p->AddPacketTag(tag);
171
172 NS_LOG_LOGIC("Txon Buffer: New packet added");
173 m_txonBuffer.emplace_back(p, Simulator::Now());
174 m_txonBufferSize += p->GetSize();
175 NS_LOG_LOGIC("NumOfBuffers = " << m_txonBuffer.size());
176 NS_LOG_LOGIC("txonBufferSize = " << m_txonBufferSize);
177 }
178 else
179 {
180 // Discard full RLC SDU
181 NS_LOG_LOGIC("TxonBuffer is full. RLC SDU discarded");
182 NS_LOG_LOGIC("MaxTxBufferSize = " << m_maxTxBufferSize);
183 NS_LOG_LOGIC("txonBufferSize = " << m_txonBufferSize);
184 NS_LOG_LOGIC("packet size = " << p->GetSize());
185 m_txDropTrace(p);
186 }
187
188 /** Report Buffer Status */
192}
193
194/**
195 * MAC SAP
196 */
197
198void
200{
201 NS_LOG_FUNCTION(this << m_rnti << (uint32_t)m_lcid << txOpParams.bytes);
202
203 if (txOpParams.bytes < 4)
204 {
205 // Stingy MAC: In general, we need more bytes.
206 // There are a more restrictive test for each particular case
207 NS_LOG_LOGIC("TxOpportunity (size = " << txOpParams.bytes << ") too small");
208 NS_ASSERT_MSG(false,
209 "TxOpportunity (size = "
210 << txOpParams.bytes << ") too small.\n"
211 << "Your MAC scheduler is assigned too few resource blocks.");
212 return;
213 }
214
216 {
217 if (txOpParams.bytes < m_statusPduBufferSize)
218 {
219 // Stingy MAC: We need more bytes for the STATUS PDU
220 NS_LOG_LOGIC("TxOpportunity (size = " << txOpParams.bytes
221 << ") too small for the STATUS PDU (size = "
222 << m_statusPduBufferSize << ")");
223 NS_ASSERT_MSG(false,
224 "TxOpportunity (size = "
225 << txOpParams.bytes << ") too small for the STATUS PDU (size = "
226 << m_statusPduBufferSize << ")\n"
227 << "Your MAC scheduler is assigned too few resource blocks.");
228 return;
229 }
230
231 NS_LOG_LOGIC("Sending STATUS PDU");
232
233 Ptr<Packet> packet = Create<Packet>();
234 LteRlcAmHeader rlcAmHeader;
236
237 NS_LOG_LOGIC("Check for SNs to NACK from " << m_vrR.GetValue() << " to "
238 << m_vrMs.GetValue());
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 auto 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 auto 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 auto it = dataField.begin();
663
664 // FIRST SEGMENT
666 NS_ASSERT_MSG((*it)->PeekPacketTag(tag), "LteRlcSduStatusTag is missing");
667 (*it)->PeekPacketTag(tag);
670 {
671 framingInfo |= LteRlcAmHeader::FIRST_BYTE;
672 }
673 else
674 {
675 framingInfo |= LteRlcAmHeader::NO_FIRST_BYTE;
676 }
677
678 // Add all SDUs (in DataField) to the Packet
679 while (it < dataField.end())
680 {
681 NS_LOG_LOGIC("Adding SDU/segment to packet, length = " << (*it)->GetSize());
682
683 NS_ASSERT_MSG((*it)->PeekPacketTag(tag), "LteRlcSduStatusTag is missing");
684 (*it)->RemovePacketTag(tag);
685 if (packet->GetSize() > 0)
686 {
687 packet->AddAtEnd(*it);
688 }
689 else
690 {
691 packet = (*it);
692 }
693 it++;
694 }
695
696 // LAST SEGMENT (Note: There could be only one and be the first one)
697 it--;
700 {
701 framingInfo |= LteRlcAmHeader::LAST_BYTE;
702 }
703 else
704 {
705 framingInfo |= LteRlcAmHeader::NO_LAST_BYTE;
706 }
707
708 // Set the FramingInfo flag after the calculation
709 rlcAmHeader.SetFramingInfo(framingInfo);
710
711 // Calculate the Polling Bit (5.2.2.1)
713
715 NS_LOG_LOGIC("PDU_WITHOUT_POLL = " << m_pduWithoutPoll);
716 m_byteWithoutPoll += packet->GetSize();
717 NS_LOG_LOGIC("BYTE_WITHOUT_POLL = " << m_byteWithoutPoll);
718
720 ((m_txonBuffer.empty()) && (m_retxBufferSize == 0)) || (m_vtS >= m_vtMs) ||
722 {
727
728 m_pollSn = m_vtS - 1;
729 NS_LOG_LOGIC("New POLL_SN = " << m_pollSn);
730
732 {
733 NS_LOG_LOGIC("Start PollRetransmit timer");
734
737 this);
738 }
739 else
740 {
741 NS_LOG_LOGIC("Restart PollRetransmit timer");
742
746 this);
747 }
748 }
749
750 // Build RLC PDU with DataField and Header
751 NS_LOG_LOGIC("AM RLC header: " << rlcAmHeader);
752
753 RlcTag rlcTag;
755
756 packet->AddHeader(rlcAmHeader);
757 packet->AddByteTag(rlcTag, 1, rlcAmHeader.GetSerializedSize());
758
759 // Store new PDU into the Transmitted PDU Buffer
760 NS_LOG_LOGIC("Put transmitted PDU in the txedBuffer");
761 m_txedBufferSize += packet->GetSize();
762 m_txedBuffer.at(rlcAmHeader.GetSequenceNumber().GetValue()).m_pdu = packet->Copy();
763 m_txedBuffer.at(rlcAmHeader.GetSequenceNumber().GetValue()).m_retxCount = 0;
764 m_txedBuffer.at(rlcAmHeader.GetSequenceNumber().GetValue()).m_waitingSince = Simulator::Now();
765
766 m_txPdu(m_rnti, m_lcid, packet->GetSize());
767
768 // Send RLC PDU to MAC layer
770 params.pdu = packet;
771 params.rnti = m_rnti;
772 params.lcid = m_lcid;
773 params.layer = txOpParams.layer;
774 params.harqProcessId = txOpParams.harqId;
775 params.componentCarrierId = txOpParams.componentCarrierId;
776
778}
779
780void
782{
783 NS_LOG_FUNCTION(this);
784}
785
786void
788{
789 NS_LOG_FUNCTION(this << m_rnti << (uint32_t)m_lcid << rxPduParams.p->GetSize());
790
791 // Get RLC header parameters
792 LteRlcAmHeader rlcAmHeader;
793 rxPduParams.p->PeekHeader(rlcAmHeader);
794 NS_LOG_LOGIC("RLC header: " << rlcAmHeader);
795
796 // Receiver timestamp
797 Time delay;
798 RlcTag rlcTag;
799
800 bool ret = rxPduParams.p->FindFirstMatchingByteTag(rlcTag);
801 NS_ASSERT_MSG(ret, "RlcTag not found in RLC Header. The packet went into a real network?");
802
803 delay = Simulator::Now() - rlcTag.GetSenderTimestamp();
804
805 m_rxPdu(m_rnti, m_lcid, rxPduParams.p->GetSize(), delay.GetNanoSeconds());
806
807 if (rlcAmHeader.IsDataPdu())
808 {
809 // 5.1.3.1 Transmit operations
810
811 // 5.1.3.1.1 General
812 //
813 // The transmitting side of an AM RLC entity shall prioritize transmission of RLC control
814 // PDUs over RLC data PDUs. The transmitting side of an AM RLC entity shall prioritize
815 // retransmission of RLC data PDUs over transmission of new AMD PDUs.
816 //
817 // The transmitting side of an AM RLC entity shall maintain a transmitting window according
818 // to state variables VT(A) and VT(MS) as follows:
819 // - a SN falls within the transmitting window if VT(A) <= SN < VT(MS);
820 // - a SN falls outside of the transmitting window otherwise.
821 //
822 // The transmitting side of an AM RLC entity shall not deliver to lower layer any RLC data
823 // PDU whose SN falls outside of the transmitting window.
824 //
825 // When delivering a new AMD PDU to lower layer, the transmitting side of an AM RLC entity
826 // shall:
827 // - set the SN of the AMD PDU to VT(S), and then increment VT(S) by one.
828 //
829 // The transmitting side of an AM RLC entity can receive a positive acknowledgement
830 // (confirmation of successful reception by its peer AM RLC entity) for a RLC data PDU by
831 // the following:
832 // - STATUS PDU from its peer AM RLC entity.
833 //
834 // When receiving a positive acknowledgement for an AMD PDU with SN = VT(A), the
835 // transmitting side of an AM RLC entity shall:
836 // - set VT(A) equal to the SN of the AMD PDU with the smallest SN, whose SN falls within
837 // the
838 // range VT(A) <= SN <= VT(S) and for which a positive acknowledgment has not been
839 // received yet.
840 // - if positive acknowledgements have been received for all AMD PDUs associated with
841 // a transmitted RLC SDU:
842 // - send an indication to the upper layers of successful delivery of the RLC SDU.
843
844 // 5.1.3.2 Receive operations
845 //
846 // 5.1.3.2.1 General
847 //
848 // The receiving side of an AM RLC entity shall maintain a receiving window according to
849 // state variables VR(R) and VR(MR) as follows:
850 // - a SN falls within the receiving window if VR(R) <= SN < VR(MR);
851 // - a SN falls outside of the receiving window otherwise.
852 //
853 // When receiving a RLC data PDU from lower layer, the receiving side of an AM RLC entity
854 // shall:
855 // - either discard the received RLC data PDU or place it in the reception buffer (see sub
856 // clause 5.1.3.2.2);
857 // - if the received RLC data PDU was placed in the reception buffer:
858 // - update state variables, reassemble and deliver RLC SDUs to upper layer and start/stop
859 // t-Reordering as needed (see sub clause 5.1.3.2.3).
860 //
861 // When t-Reordering expires, the receiving side of an AM RLC entity shall:
862 // - update state variables and start t-Reordering as needed (see sub clause 5.1.3.2.4).
863
864 SequenceNumber10 seqNumber = rlcAmHeader.GetSequenceNumber();
865 seqNumber.SetModulusBase(m_vrR);
866
868 {
869 NS_LOG_LOGIC("PDU segment received ( SN = " << seqNumber << " )");
870 }
871 else if (rlcAmHeader.GetResegmentationFlag() == LteRlcAmHeader::PDU)
872 {
873 NS_LOG_LOGIC("PDU received ( SN = " << seqNumber << " )");
874 }
875 else
876 {
877 NS_ASSERT_MSG(false, "Neither a PDU segment nor a PDU received");
878 return;
879 }
880
881 // STATUS PDU is requested
883 {
886
888 {
890 }
891 }
892
893 // 5.1.3.2.2 Actions when a RLC data PDU is received from lower layer
894 //
895 // When a RLC data PDU is received from lower layer, where the RLC data PDU contains
896 // byte segment numbers y to z of an AMD PDU with SN = x, the receiving side of an AM RLC
897 // entity shall:
898 // - if x falls outside of the receiving window; or
899 // - if byte segment numbers y to z of the AMD PDU with SN = x have been received before:
900 // - discard the received RLC data PDU;
901 // - else:
902 // - place the received RLC data PDU in the reception buffer;
903 // - if some byte segments of the AMD PDU contained in the RLC data PDU have been
904 // received before:
905 // - discard the duplicate byte segments.
906
907 NS_LOG_LOGIC("VR(R) = " << m_vrR);
908 NS_LOG_LOGIC("VR(MR) = " << m_vrMr);
909 NS_LOG_LOGIC("VR(X) = " << m_vrX);
910 NS_LOG_LOGIC("VR(MS) = " << m_vrMs);
911 NS_LOG_LOGIC("VR(H) = " << m_vrH);
912
913 // - if x falls outside of the receiving window; or
914 // - if byte segment numbers y to z of the AMD PDU with SN = x have been received before:
915 if (!IsInsideReceivingWindow(seqNumber))
916 {
917 NS_LOG_LOGIC("PDU discarded");
918 return;
919 }
920 else
921 {
922 // - if some byte segments of the AMD PDU contained in the RLC data PDU have been
923 // received before:
924 // - discard the duplicate byte segments.
925 // note: re-segmentation of AMD PDU is currently not supported,
926 // so we just check that the segment was not received before
927 auto it = m_rxonBuffer.find(seqNumber.GetValue());
928 if (it != m_rxonBuffer.end())
929 {
930 NS_ASSERT(!it->second.m_byteSegments.empty());
931 NS_ASSERT_MSG(it->second.m_byteSegments.size() == 1,
932 "re-segmentation not supported");
933 NS_LOG_LOGIC("PDU segment already received, discarded");
934 }
935 else
936 {
937 NS_LOG_LOGIC("Place PDU in the reception buffer ( SN = " << seqNumber << " )");
938 m_rxonBuffer[seqNumber.GetValue()].m_byteSegments.push_back(rxPduParams.p);
939 m_rxonBuffer[seqNumber.GetValue()].m_pduComplete = true;
940 }
941 }
942
943 // 5.1.3.2.3 Actions when a RLC data PDU is placed in the reception buffer
944 // When a RLC data PDU with SN = x is placed in the reception buffer,
945 // the receiving side of an AM RLC entity shall:
946
947 // - if x >= VR(H)
948 // - update VR(H) to x+ 1;
949
950 if (seqNumber >= m_vrH)
951 {
952 m_vrH = seqNumber + 1;
953 NS_LOG_LOGIC("New VR(H) = " << m_vrH);
954 }
955
956 // - if all byte segments of the AMD PDU with SN = VR(MS) are received:
957 // - update VR(MS) to the SN of the first AMD PDU with SN > current VR(MS) for
958 // which not all byte segments have been received;
959
960 auto it = m_rxonBuffer.find(m_vrMs.GetValue());
961 if (it != m_rxonBuffer.end() && it->second.m_pduComplete)
962 {
963 int firstVrMs = m_vrMs.GetValue();
964 while (it != m_rxonBuffer.end() && it->second.m_pduComplete)
965 {
966 m_vrMs++;
967 it = m_rxonBuffer.find(m_vrMs.GetValue());
968 NS_LOG_LOGIC("Incr VR(MS) = " << m_vrMs);
969
970 NS_ASSERT_MSG(firstVrMs != m_vrMs.GetValue(), "Infinite loop in RxonBuffer");
971 }
972 NS_LOG_LOGIC("New VR(MS) = " << m_vrMs);
973 }
974
975 // - if x = VR(R):
976 // - if all byte segments of the AMD PDU with SN = VR(R) are received:
977 // - update VR(R) to the SN of the first AMD PDU with SN > current VR(R) for which
978 // not all byte segments have been received;
979 // - update VR(MR) to the updated VR(R) + AM_Window_Size;
980 // - reassemble RLC SDUs from any byte segments of AMD PDUs with SN that falls outside
981 // of the receiving window and in-sequence byte segments of the AMD PDU with SN = VR(R),
982 // remove RLC headers when doing so and deliver the reassembled RLC SDUs to upper layer
983 // in sequence if not delivered before;
984
985 if (seqNumber == m_vrR)
986 {
987 auto it = m_rxonBuffer.find(seqNumber.GetValue());
988 if (it != m_rxonBuffer.end() && it->second.m_pduComplete)
989 {
990 it = m_rxonBuffer.find(m_vrR.GetValue());
991 int firstVrR = m_vrR.GetValue();
992 while (it != m_rxonBuffer.end() && it->second.m_pduComplete)
993 {
994 NS_LOG_LOGIC("Reassemble and Deliver ( SN = " << m_vrR << " )");
995 NS_ASSERT_MSG(it->second.m_byteSegments.size() == 1,
996 "Too many segments. PDU Reassembly process didn't work");
997 ReassembleAndDeliver(it->second.m_byteSegments.front());
998 m_rxonBuffer.erase(m_vrR.GetValue());
999
1000 m_vrR++;
1005 it = m_rxonBuffer.find(m_vrR.GetValue());
1006
1007 NS_ASSERT_MSG(firstVrR != m_vrR.GetValue(), "Infinite loop in RxonBuffer");
1008 }
1009 NS_LOG_LOGIC("New VR(R) = " << m_vrR);
1011
1012 NS_LOG_LOGIC("New VR(MR) = " << m_vrMr);
1013 }
1014 }
1015
1016 // - if t-Reordering is running:
1017 // - if VR(X) = VR(R); or
1018 // - if VR(X) falls outside of the receiving window and VR(X) is not equal to VR(MR):
1019 // - stop and reset t-Reordering;
1020
1022 {
1023 NS_LOG_LOGIC("Reordering timer is running");
1024 if ((m_vrX == m_vrR) || ((!IsInsideReceivingWindow(m_vrX)) && (m_vrX != m_vrMr)))
1025 {
1026 /// \todo stop and reset the t-Reordering
1027 NS_LOG_LOGIC("Stop reordering timer");
1029 }
1030 }
1031
1032 // - if t-Reordering is not running (includes the case t-Reordering is stopped due to
1033 // actions above):
1034 // - if VR (H) > VR(R):
1035 // - start t-Reordering;
1036 // - set VR(X) to VR(H).
1037
1039 {
1040 NS_LOG_LOGIC("Reordering timer is not running");
1041 if (m_vrH > m_vrR)
1042 {
1043 NS_LOG_LOGIC("Start reordering timer");
1046 this);
1047 m_vrX = m_vrH;
1048 NS_LOG_LOGIC("New VR(X) = " << m_vrX);
1049 }
1050 }
1051 }
1052 else if (rlcAmHeader.IsControlPdu())
1053 {
1054 NS_LOG_INFO("Control AM RLC PDU");
1055
1056 SequenceNumber10 ackSn = rlcAmHeader.GetAckSn();
1058
1059 NS_LOG_INFO("ackSn = " << ackSn);
1060 NS_LOG_INFO("VT(A) = " << m_vtA);
1061 NS_LOG_INFO("VT(S) = " << m_vtS);
1062 NS_LOG_LOGIC("retxBufferSize = " << m_retxBufferSize);
1063 NS_LOG_LOGIC("txedBufferSize = " << m_txedBufferSize);
1064
1068 ackSn.SetModulusBase(m_vtA);
1070
1071 bool incrementVtA = true;
1072
1073 for (sn = m_vtA; sn < ackSn && sn < m_vtS; sn++)
1074 {
1075 NS_LOG_LOGIC("sn = " << sn);
1076
1077 uint16_t seqNumberValue = sn.GetValue();
1078
1079 if (m_pollRetransmitTimer.IsRunning() && (seqNumberValue == m_pollSn.GetValue()))
1080 {
1082 }
1083
1084 if (rlcAmHeader.IsNackPresent(sn))
1085 {
1086 NS_LOG_LOGIC("sn " << sn << " is NACKed");
1087
1088 incrementVtA = false;
1089
1090 if (m_txedBuffer.at(seqNumberValue).m_pdu)
1091 {
1092 NS_LOG_INFO("Move SN = " << seqNumberValue << " to retxBuffer");
1093 m_retxBuffer.at(seqNumberValue).m_pdu =
1094 m_txedBuffer.at(seqNumberValue).m_pdu->Copy();
1095 m_retxBuffer.at(seqNumberValue).m_retxCount =
1096 m_txedBuffer.at(seqNumberValue).m_retxCount;
1097 m_retxBuffer.at(seqNumberValue).m_waitingSince =
1098 m_txedBuffer.at(seqNumberValue).m_waitingSince;
1099 m_retxBufferSize += m_retxBuffer.at(seqNumberValue).m_pdu->GetSize();
1100
1101 m_txedBufferSize -= m_txedBuffer.at(seqNumberValue).m_pdu->GetSize();
1102 m_txedBuffer.at(seqNumberValue).m_pdu = nullptr;
1103 m_txedBuffer.at(seqNumberValue).m_retxCount = 0;
1104 m_txedBuffer.at(seqNumberValue).m_waitingSince = MilliSeconds(0);
1105 }
1106
1107 NS_ASSERT(m_retxBuffer.at(seqNumberValue).m_pdu);
1108 }
1109 else
1110 {
1111 NS_LOG_LOGIC("sn " << sn << " is ACKed");
1112
1113 if (m_txedBuffer.at(seqNumberValue).m_pdu)
1114 {
1115 NS_LOG_INFO("ACKed SN = " << seqNumberValue << " from txedBuffer");
1116 // NS_LOG_INFO ("m_txedBuffer( " << m_vtA << " )->GetSize = " <<
1117 // m_txedBuffer.at (m_vtA.GetValue ())->GetSize ());
1118 m_txedBufferSize -= m_txedBuffer.at(seqNumberValue).m_pdu->GetSize();
1119 m_txedBuffer.at(seqNumberValue).m_pdu = nullptr;
1120 m_txedBuffer.at(seqNumberValue).m_waitingSince = MilliSeconds(0);
1121 NS_ASSERT(!m_retxBuffer.at(seqNumberValue).m_pdu);
1122 }
1123
1124 if (m_retxBuffer.at(seqNumberValue).m_pdu)
1125 {
1126 NS_LOG_INFO("ACKed SN = " << seqNumberValue << " from retxBuffer");
1127 m_retxBufferSize -= m_retxBuffer.at(seqNumberValue).m_pdu->GetSize();
1128 m_retxBuffer.at(seqNumberValue).m_pdu = nullptr;
1129 m_retxBuffer.at(seqNumberValue).m_retxCount = 0;
1130 m_retxBuffer.at(seqNumberValue).m_waitingSince = MilliSeconds(0);
1131 }
1132 }
1133
1134 NS_LOG_LOGIC("retxBufferSize = " << m_retxBufferSize);
1135 NS_LOG_LOGIC("txedBufferSize = " << m_txedBufferSize);
1136
1137 if (incrementVtA)
1138 {
1139 m_vtA++;
1141 NS_LOG_INFO("New VT(A) = " << m_vtA);
1145 ackSn.SetModulusBase(m_vtA);
1147 }
1148
1149 } // loop over SN : VT(A) <= SN < ACK SN
1150
1151 return;
1152 }
1153 else
1154 {
1155 NS_LOG_WARN("Wrong AM RLC PDU type");
1156 return;
1157 }
1158}
1159
1160bool
1162{
1163 NS_LOG_FUNCTION(this << seqNumber);
1164 NS_LOG_LOGIC("Receiving Window: " << m_vrR << " <= " << seqNumber << " <= " << m_vrMr);
1165
1168 seqNumber.SetModulusBase(m_vrR);
1169
1170 if ((m_vrR <= seqNumber) && (seqNumber < m_vrMr))
1171 {
1172 NS_LOG_LOGIC(seqNumber << " is INSIDE the receiving window");
1173 return true;
1174 }
1175 else
1176 {
1177 NS_LOG_LOGIC(seqNumber << " is OUTSIDE the receiving window");
1178 return false;
1179 }
1180}
1181
1182void
1184{
1185 LteRlcAmHeader rlcAmHeader;
1186 RlcTag rlcTag;
1187 bool ret = packet->FindFirstMatchingByteTag(rlcTag);
1188 NS_ASSERT(ret);
1189 packet->RemoveHeader(rlcAmHeader);
1190 ret = packet->FindFirstMatchingByteTag(rlcTag);
1191 NS_ASSERT(!ret);
1192 uint8_t framingInfo = rlcAmHeader.GetFramingInfo();
1193 SequenceNumber10 currSeqNumber = rlcAmHeader.GetSequenceNumber();
1194 bool expectedSnLost;
1195
1196 if (currSeqNumber != m_expectedSeqNumber)
1197 {
1198 expectedSnLost = true;
1199 NS_LOG_LOGIC("There are losses. Expected SN = " << m_expectedSeqNumber
1200 << ". Current SN = " << currSeqNumber);
1201 m_expectedSeqNumber = currSeqNumber + 1;
1202 }
1203 else
1204 {
1205 expectedSnLost = false;
1206 NS_LOG_LOGIC("No losses. Expected SN = " << m_expectedSeqNumber
1207 << ". Current SN = " << currSeqNumber);
1209 }
1210
1211 // Build list of SDUs
1212 uint8_t extensionBit;
1213 uint16_t lengthIndicator;
1214 do
1215 {
1216 extensionBit = rlcAmHeader.PopExtensionBit();
1217 NS_LOG_LOGIC("E = " << (uint16_t)extensionBit);
1218
1219 if (extensionBit == 0)
1220 {
1221 m_sdusBuffer.push_back(packet);
1222 }
1223 else // extensionBit == 1
1224 {
1225 lengthIndicator = rlcAmHeader.PopLengthIndicator();
1226 NS_LOG_LOGIC("LI = " << lengthIndicator);
1227
1228 // Check if there is enough data in the packet
1229 if (lengthIndicator >= packet->GetSize())
1230 {
1231 NS_LOG_LOGIC("INTERNAL ERROR: Not enough data in the packet ("
1232 << packet->GetSize() << "). Needed LI=" << lengthIndicator);
1233 /// \todo What to do in this case? Discard packet and continue? Or Assert?
1234 }
1235
1236 // Split packet in two fragments
1237 Ptr<Packet> data_field = packet->CreateFragment(0, lengthIndicator);
1238 packet->RemoveAtStart(lengthIndicator);
1239
1240 m_sdusBuffer.push_back(data_field);
1241 }
1242 } while (extensionBit == 1);
1243
1244 // Current reassembling state
1246 {
1247 NS_LOG_LOGIC("Reassembling State = 'WAITING_S0_FULL'");
1248 }
1250 {
1251 NS_LOG_LOGIC("Reassembling State = 'WAITING_SI_SF'");
1252 }
1253 else
1254 {
1255 NS_LOG_LOGIC("Reassembling State = Unknown state");
1256 }
1257
1258 // Received framing Info
1259 NS_LOG_LOGIC("Framing Info = " << (uint16_t)framingInfo);
1260 NS_LOG_LOGIC("m_sdusBuffer = " << m_sdusBuffer.size());
1261
1262 // Reassemble the list of SDUs (when there is no losses)
1263 if (!expectedSnLost)
1264 {
1265 switch (m_reassemblingState)
1266 {
1267 case WAITING_S0_FULL:
1268 switch (framingInfo)
1269 {
1272
1273 /**
1274 * Deliver one or multiple PDUs
1275 */
1276 for (auto it = m_sdusBuffer.begin(); it != m_sdusBuffer.end(); it++)
1277 {
1279 }
1280 m_sdusBuffer.clear();
1281 break;
1282
1285
1286 /**
1287 * Deliver full PDUs
1288 */
1289 while (m_sdusBuffer.size() > 1)
1290 {
1292 m_sdusBuffer.pop_front();
1293 }
1294
1295 /**
1296 * Keep S0
1297 */
1298 m_keepS0 = m_sdusBuffer.front();
1299 m_sdusBuffer.pop_front();
1300 break;
1301
1304 default:
1305 /**
1306 * ERROR: Transition not possible
1307 */
1309 "INTERNAL ERROR: Transition not possible. FI = " << (uint32_t)framingInfo);
1310 break;
1311 }
1312 break;
1313
1314 case WAITING_SI_SF:
1315 switch (framingInfo)
1316 {
1319
1320 /**
1321 * Deliver (Kept)S0 + SN
1322 */
1323 m_keepS0->AddAtEnd(m_sdusBuffer.front());
1324 m_sdusBuffer.pop_front();
1326
1327 /**
1328 * Deliver zero, one or multiple PDUs
1329 */
1330 while (!m_sdusBuffer.empty())
1331 {
1333 m_sdusBuffer.pop_front();
1334 }
1335 break;
1336
1339
1340 /**
1341 * Keep SI
1342 */
1343 if (m_sdusBuffer.size() == 1)
1344 {
1345 m_keepS0->AddAtEnd(m_sdusBuffer.front());
1346 m_sdusBuffer.pop_front();
1347 }
1348 else // m_sdusBuffer.size () > 1
1349 {
1350 /**
1351 * Deliver (Kept)S0 + SN
1352 */
1353 m_keepS0->AddAtEnd(m_sdusBuffer.front());
1354 m_sdusBuffer.pop_front();
1356
1357 /**
1358 * Deliver zero, one or multiple PDUs
1359 */
1360 while (m_sdusBuffer.size() > 1)
1361 {
1363 m_sdusBuffer.pop_front();
1364 }
1365
1366 /**
1367 * Keep S0
1368 */
1369 m_keepS0 = m_sdusBuffer.front();
1370 m_sdusBuffer.pop_front();
1371 }
1372 break;
1373
1376 default:
1377 /**
1378 * ERROR: Transition not possible
1379 */
1381 "INTERNAL ERROR: Transition not possible. FI = " << (uint32_t)framingInfo);
1382 break;
1383 }
1384 break;
1385
1386 default:
1388 "INTERNAL ERROR: Wrong reassembling state = " << (uint32_t)m_reassemblingState);
1389 break;
1390 }
1391 }
1392 else // Reassemble the list of SDUs (when there are losses, i.e. the received SN is not the
1393 // expected one)
1394 {
1395 switch (m_reassemblingState)
1396 {
1397 case WAITING_S0_FULL:
1398 switch (framingInfo)
1399 {
1402
1403 /**
1404 * Deliver one or multiple PDUs
1405 */
1406 for (auto it = m_sdusBuffer.begin(); it != m_sdusBuffer.end(); it++)
1407 {
1409 }
1410 m_sdusBuffer.clear();
1411 break;
1412
1415
1416 /**
1417 * Deliver full PDUs
1418 */
1419 while (m_sdusBuffer.size() > 1)
1420 {
1422 m_sdusBuffer.pop_front();
1423 }
1424
1425 /**
1426 * Keep S0
1427 */
1428 m_keepS0 = m_sdusBuffer.front();
1429 m_sdusBuffer.pop_front();
1430 break;
1431
1434
1435 /**
1436 * Discard SN
1437 */
1438 m_sdusBuffer.pop_front();
1439
1440 /**
1441 * Deliver zero, one or multiple PDUs
1442 */
1443 while (!m_sdusBuffer.empty())
1444 {
1446 m_sdusBuffer.pop_front();
1447 }
1448 break;
1449
1451 if (m_sdusBuffer.size() == 1)
1452 {
1454 }
1455 else
1456 {
1458 }
1459
1460 /**
1461 * Discard SI or SN
1462 */
1463 m_sdusBuffer.pop_front();
1464
1465 if (!m_sdusBuffer.empty())
1466 {
1467 /**
1468 * Deliver zero, one or multiple PDUs
1469 */
1470 while (m_sdusBuffer.size() > 1)
1471 {
1473 m_sdusBuffer.pop_front();
1474 }
1475
1476 /**
1477 * Keep S0
1478 */
1479 m_keepS0 = m_sdusBuffer.front();
1480 m_sdusBuffer.pop_front();
1481 }
1482 break;
1483
1484 default:
1485 /**
1486 * ERROR: Transition not possible
1487 */
1489 "INTERNAL ERROR: Transition not possible. FI = " << (uint32_t)framingInfo);
1490 break;
1491 }
1492 break;
1493
1494 case WAITING_SI_SF:
1495 switch (framingInfo)
1496 {
1499
1500 /**
1501 * Discard S0
1502 */
1503 m_keepS0 = nullptr;
1504
1505 /**
1506 * Deliver one or multiple PDUs
1507 */
1508 while (!m_sdusBuffer.empty())
1509 {
1511 m_sdusBuffer.pop_front();
1512 }
1513 break;
1514
1517
1518 /**
1519 * Discard S0
1520 */
1521 m_keepS0 = nullptr;
1522
1523 /**
1524 * Deliver zero, one or multiple PDUs
1525 */
1526 while (m_sdusBuffer.size() > 1)
1527 {
1529 m_sdusBuffer.pop_front();
1530 }
1531
1532 /**
1533 * Keep S0
1534 */
1535 m_keepS0 = m_sdusBuffer.front();
1536 m_sdusBuffer.pop_front();
1537
1538 break;
1539
1542
1543 /**
1544 * Discard S0
1545 */
1546 m_keepS0 = nullptr;
1547
1548 /**
1549 * Discard SI or SN
1550 */
1551 m_sdusBuffer.pop_front();
1552
1553 /**
1554 * Deliver zero, one or multiple PDUs
1555 */
1556 while (!m_sdusBuffer.empty())
1557 {
1559 m_sdusBuffer.pop_front();
1560 }
1561 break;
1562
1564 if (m_sdusBuffer.size() == 1)
1565 {
1567 }
1568 else
1569 {
1571 }
1572
1573 /**
1574 * Discard S0
1575 */
1576 m_keepS0 = nullptr;
1577
1578 /**
1579 * Discard SI or SN
1580 */
1581 m_sdusBuffer.pop_front();
1582
1583 if (!m_sdusBuffer.empty())
1584 {
1585 /**
1586 * Deliver zero, one or multiple PDUs
1587 */
1588 while (m_sdusBuffer.size() > 1)
1589 {
1591 m_sdusBuffer.pop_front();
1592 }
1593
1594 /**
1595 * Keep S0
1596 */
1597 m_keepS0 = m_sdusBuffer.front();
1598 m_sdusBuffer.pop_front();
1599 }
1600 break;
1601
1602 default:
1603 /**
1604 * ERROR: Transition not possible
1605 */
1607 "INTERNAL ERROR: Transition not possible. FI = " << (uint32_t)framingInfo);
1608 break;
1609 }
1610 break;
1611
1612 default:
1614 "INTERNAL ERROR: Wrong reassembling state = " << (uint32_t)m_reassemblingState);
1615 break;
1616 }
1617 }
1618}
1619
1620void
1622{
1623 NS_LOG_FUNCTION(this);
1624
1625 Time now = Simulator::Now();
1626
1627 NS_LOG_LOGIC("txonBufferSize = " << m_txonBufferSize);
1628 NS_LOG_LOGIC("retxBufferSize = " << m_retxBufferSize);
1629 NS_LOG_LOGIC("txedBufferSize = " << m_txedBufferSize);
1630 NS_LOG_LOGIC("VT(A) = " << m_vtA);
1631 NS_LOG_LOGIC("VT(S) = " << m_vtS);
1632
1633 // Transmission Queue HOL time
1634 Time txonQueueHolDelay(0);
1635 if (m_txonBufferSize > 0)
1636 {
1637 txonQueueHolDelay = now - m_txonBuffer.front().m_waitingSince;
1638 }
1639
1640 // Retransmission Queue HOL time
1641 Time retxQueueHolDelay;
1642 if (m_retxBufferSize > 0)
1643 {
1644 Time senderTimestamp;
1645 if (m_retxBuffer.at(m_vtA.GetValue()).m_pdu)
1646 {
1647 senderTimestamp = m_retxBuffer.at(m_vtA.GetValue()).m_waitingSince;
1648 }
1649 else
1650 {
1651 senderTimestamp = m_txedBuffer.at(m_vtA.GetValue()).m_waitingSince;
1652 }
1653 retxQueueHolDelay = now - senderTimestamp;
1654 }
1655 else
1656 {
1657 retxQueueHolDelay = Seconds(0);
1658 }
1659
1661 r.rnti = m_rnti;
1662 r.lcid = m_lcid;
1664 r.txQueueHolDelay = txonQueueHolDelay.GetMilliSeconds();
1666 r.retxQueueHolDelay = retxQueueHolDelay.GetMilliSeconds();
1667
1669 {
1671 }
1672 else
1673 {
1674 r.statusPduSize = 0;
1675 }
1676
1677 if (r.txQueueSize != 0 || r.retxQueueSize != 0 || r.statusPduSize != 0)
1678 {
1679 NS_LOG_INFO("Send ReportBufferStatus: " << r.txQueueSize << ", " << r.txQueueHolDelay
1680 << ", " << r.retxQueueSize << ", "
1681 << r.retxQueueHolDelay << ", " << r.statusPduSize);
1683 }
1684 else
1685 {
1686 NS_LOG_INFO("ReportBufferStatus don't needed");
1687 }
1688}
1689
1690void
1692{
1693 NS_LOG_FUNCTION(this);
1694 NS_LOG_LOGIC("Reordering Timer has expired");
1695
1696 // 5.1.3.2.4 Actions when t-Reordering expires
1697 // When t-Reordering expires, the receiving side of an AM RLC entity shall:
1698 // - update VR(MS) to the SN of the first AMD PDU with SN >= VR(X) for which not all byte
1699 // segments
1700 // have been received;
1701 // - if VR(H) > VR(MS):
1702 // - start t-Reordering;
1703 // - set VR(X) to VR(H).
1704
1705 m_vrMs = m_vrX;
1706 int firstVrMs = m_vrMs.GetValue();
1707 auto it = m_rxonBuffer.find(m_vrMs.GetValue());
1708 while (it != m_rxonBuffer.end() && it->second.m_pduComplete)
1709 {
1710 m_vrMs++;
1711 it = m_rxonBuffer.find(m_vrMs.GetValue());
1712
1713 NS_ASSERT_MSG(firstVrMs != m_vrMs.GetValue(), "Infinite loop in ExpireReorderingTimer");
1714 }
1715 NS_LOG_LOGIC("New VR(MS) = " << m_vrMs);
1716
1717 if (m_vrH > m_vrMs)
1718 {
1719 NS_LOG_LOGIC("Start reordering timer");
1722 m_vrX = m_vrH;
1723 NS_LOG_LOGIC("New VR(MS) = " << m_vrMs);
1724 }
1725
1726 // Section 5.2.3 Status Reporting:
1727 // - The receiving side of an AM RLC entity shall trigger a
1728 // STATUS report when T_reordering expires.
1729 m_statusPduRequested = true;
1730}
1731
1732void
1734{
1735 NS_LOG_FUNCTION(this);
1736 NS_LOG_LOGIC("PollRetransmit Timer has expired");
1737
1738 NS_LOG_LOGIC("txonBufferSize = " << m_txonBufferSize);
1739 NS_LOG_LOGIC("retxBufferSize = " << m_retxBufferSize);
1740 NS_LOG_LOGIC("txedBufferSize = " << m_txedBufferSize);
1741 NS_LOG_LOGIC("statusPduRequested = " << m_statusPduRequested);
1742
1744
1745 // see section 5.2.2.3
1746 // note the difference between Rel 8 and Rel 11 specs; we follow Rel 11 here
1748 if ((m_txonBufferSize == 0 && m_retxBufferSize == 0) || (m_vtS == m_vtMs))
1749 {
1750 NS_LOG_INFO("txonBuffer and retxBuffer empty. Move PDUs up to = " << m_vtS.GetValue() - 1
1751 << " to retxBuffer");
1752 for (SequenceNumber10 sn = m_vtA; sn < m_vtS; sn++)
1753 {
1754 bool pduAvailable = (bool)m_txedBuffer.at(sn.GetValue()).m_pdu;
1755
1756 if (pduAvailable)
1757 {
1758 uint16_t snValue = sn.GetValue();
1759 NS_LOG_INFO("Move PDU " << sn << " from txedBuffer to retxBuffer");
1760 m_retxBuffer.at(snValue).m_pdu = m_txedBuffer.at(snValue).m_pdu->Copy();
1761 m_retxBuffer.at(snValue).m_retxCount = m_txedBuffer.at(snValue).m_retxCount;
1762 m_retxBuffer.at(snValue).m_waitingSince = m_txedBuffer.at(snValue).m_waitingSince;
1763 m_retxBufferSize += m_retxBuffer.at(snValue).m_pdu->GetSize();
1764
1765 m_txedBufferSize -= m_txedBuffer.at(snValue).m_pdu->GetSize();
1766 m_txedBuffer.at(snValue).m_pdu = nullptr;
1767 m_txedBuffer.at(snValue).m_retxCount = 0;
1768 m_txedBuffer.at(snValue).m_waitingSince = MilliSeconds(0);
1769 }
1770 }
1771 }
1772
1774}
1775
1776void
1778{
1779 NS_LOG_FUNCTION(this);
1780}
1781
1782void
1784{
1785 NS_LOG_LOGIC("RBS Timer expires");
1786
1788 {
1791 }
1792}
1793
1794} // namespace ns3
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.
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:38
ReassemblingState_t m_reassemblingState
reassembling state
Definition: lte-rlc-am.h:233
void ExpireStatusProhibitTimer()
method called when the T_status_prohibit timer expires
Definition: lte-rlc-am.cc:1777
SequenceNumber10 m_vrMr
VR(MR)
Definition: lte-rlc-am.h:185
Time m_statusProhibitTimerValue
status prohibit timer value
Definition: lte-rlc-am.h:209
bool IsInsideReceivingWindow(SequenceNumber10 seqNumber)
method called when the T_status_prohibit timer expires
Definition: lte-rlc-am.cc:1161
uint16_t m_windowSize
Constants.
Definition: lte-rlc-am.h:199
Ptr< Packet > m_keepS0
keep S0
Definition: lte-rlc-am.h:234
void DoNotifyHarqDeliveryFailure() override
Notify HARQ delivery failure.
Definition: lte-rlc-am.cc:781
SequenceNumber10 m_vrH
VR(H)
Definition: lte-rlc-am.h:188
uint32_t m_txonBufferSize
transmit on buffer size
Definition: lte-rlc-am.h:149
std::vector< TxPdu > m_txonBuffer
Transmission buffer.
Definition: lte-rlc-am.h:133
SequenceNumber10 m_vrMs
VR(MS)
Definition: lte-rlc-am.h:187
uint16_t m_pollByte
poll byte
Definition: lte-rlc-am.h:218
SequenceNumber10 m_vtS
VT(S)
Definition: lte-rlc-am.h:180
void DoDispose() override
Destructor implementation.
Definition: lte-rlc-am.cc:133
SequenceNumber10 m_pollSn
POLL_SN.
Definition: lte-rlc-am.h:181
SequenceNumber10 m_vtA
State variables.
Definition: lte-rlc-am.h:178
void ExpireReorderingTimer()
This method will schedule a timeout at WaitReplyTimeout interval in the future, unless a timer is alr...
Definition: lte-rlc-am.cc:1691
SequenceNumber10 m_vtMs
VT(MS)
Definition: lte-rlc-am.h:179
EventId m_rbsTimer
RBS timer.
Definition: lte-rlc-am.h:210
~LteRlcAm() override
Definition: lte-rlc-am.cc:81
uint32_t m_statusPduBufferSize
status PDU buffer size
Definition: lte-rlc-am.h:154
Ptr< Packet > m_controlPduBuffer
Control PDU buffer (just one PDU)
Definition: lte-rlc-am.h:167
bool m_txOpportunityForRetxAlwaysBigEnough
transmit opportunity for retransmit?
Definition: lte-rlc-am.h:220
bool m_pollRetransmitTimerJustExpired
poll retransmit timer just expired?
Definition: lte-rlc-am.h:221
void DoTransmitPdcpPdu(Ptr< Packet > p) override
RLC SAP.
Definition: lte-rlc-am.cc:161
Time m_reorderingTimerValue
reordering timer value
Definition: lte-rlc-am.h:207
uint32_t m_maxTxBufferSize
maximum transmission buffer size
Definition: lte-rlc-am.h:148
void DoReceivePdu(LteMacSapUser::ReceivePduParameters rxPduParams) override
Receive PDU function.
Definition: lte-rlc-am.cc:787
std::list< Ptr< Packet > > m_sdusBuffer
List of SDUs in a packet (PDU)
Definition: lte-rlc-am.h:172
EventId m_pollRetransmitTimer
Timers.
Definition: lte-rlc-am.h:204
uint16_t m_maxRetxThreshold
Configurable parameters.
Definition: lte-rlc-am.h:216
SequenceNumber10 m_vrX
VR(X)
Definition: lte-rlc-am.h:186
std::vector< RetxPdu > m_retxBuffer
Buffer for PDUs considered for retransmission.
Definition: lte-rlc-am.h:146
uint32_t m_byteWithoutPoll
byte without poll
Definition: lte-rlc-am.h:194
void ExpireRbsTimer()
Expire RBS timer.
Definition: lte-rlc-am.cc:1783
uint32_t m_pduWithoutPoll
Counters.
Definition: lte-rlc-am.h:193
static TypeId GetTypeId()
Get the type ID.
Definition: lte-rlc-am.cc:87
void DoNotifyTxOpportunity(LteMacSapUser::TxOpportunityParameters txOpParams) override
MAC SAP.
Definition: lte-rlc-am.cc:199
Time m_pollRetransmitTimerValue
poll retransmit time value
Definition: lte-rlc-am.h:205
void DoReportBufferStatus()
Report buffer status.
Definition: lte-rlc-am.cc:1621
void ReassembleAndDeliver(Ptr< Packet > packet)
Reassemble and deliver.
Definition: lte-rlc-am.cc:1183
std::map< uint16_t, PduBuffer > m_rxonBuffer
Reception buffer.
Definition: lte-rlc-am.h:165
uint32_t m_txedBufferSize
transmit ed buffer size
Definition: lte-rlc-am.h:151
uint16_t m_pollPdu
poll PDU
Definition: lte-rlc-am.h:217
EventId m_reorderingTimer
reordering timer
Definition: lte-rlc-am.h:206
void ExpirePollRetransmitTimer()
Expire poll retransmitter.
Definition: lte-rlc-am.cc:1733
SequenceNumber10 m_vrR
VR(R)
Definition: lte-rlc-am.h:184
SequenceNumber10 m_expectedSeqNumber
Expected Sequence Number.
Definition: lte-rlc-am.h:239
uint32_t m_retxBufferSize
retransmit buffer size
Definition: lte-rlc-am.h:150
EventId m_statusProhibitTimer
status prohibit timer
Definition: lte-rlc-am.h:208
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:143
bool m_statusPduRequested
status PDU requested
Definition: lte-rlc-am.h:153
Time m_rbsTimerValue
RBS timer value.
Definition: lte-rlc-am.h:211
This abstract base class defines the API to interact with the Radio Link Control (LTE_RLC) in LTE,...
Definition: lte-rlc.h:49
LteRlcSapUser * m_rlcSapUser
RLC SAP user.
Definition: lte-rlc.h:148
uint8_t m_lcid
LCID.
Definition: lte-rlc.h:173
TracedCallback< Ptr< const Packet > > m_txDropTrace
The trace source fired when the RLC drops a packet before transmission.
Definition: lte-rlc.h:189
uint16_t m_rnti
RNTI.
Definition: lte-rlc.h:172
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:184
void DoDispose() override
Destructor implementation.
Definition: lte-rlc.cc:126
LteMacSapProvider * m_macSapProvider
MAC SAP provider.
Definition: lte-rlc.h:170
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:180
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:354
uint32_t GetSize() const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:861
bool FindFirstMatchingByteTag(Tag &tag) const
Finds the first tag matching the parameter Tag type.
Definition: packet.cc:943
uint32_t PeekHeader(Header &header) const
Deserialize but does not remove the header from the internal buffer.
Definition: packet.cc:305
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
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:571
static Time Now()
Return the current simulation virtual time.
Definition: simulator.cc:208
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:418
int64_t GetMilliSeconds() const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:408
AttributeValue implementation for Time.
Definition: nstime.h:1406
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:932
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:81
Ptr< const AttributeChecker > MakeBooleanChecker()
Definition: boolean.cc:124
Ptr< const AttributeChecker > MakeTimeChecker()
Helper to make an unbounded Time checker.
Definition: nstime.h:1427
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Definition: nstime.h:1407
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:1319
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1331
Every class exported by the ns3 library is enclosed in the ns3 namespace.
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:115