5G-LENA nr-v4.0
The 5G/NR module for the ns-3 simulator
Loading...
Searching...
No Matches
nr-rlc-am.cc
1// Copyright (c) 2011 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
2//
3// SPDX-License-Identifier: GPL-2.0-only
4//
5// Author: Manuel Requena <manuel.requena@cttc.es>
6// Nicola Baldo <nbaldo@cttc.es>
7
8#include "nr-rlc-am.h"
9
10#include "nr-rlc-am-header.h"
11#include "nr-rlc-sdu-status-tag.h"
12#include "nr-rlc-tag.h"
13
14#include "ns3/log.h"
15#include "ns3/simulator.h"
16
17namespace ns3
18{
19
20NS_LOG_COMPONENT_DEFINE("NrRlcAm");
21
22NS_OBJECT_ENSURE_REGISTERED(NrRlcAm);
23
24NrRlcAm::NrRlcAm()
25{
26 NS_LOG_FUNCTION(this);
27
28 // Buffers
29 m_txonBufferSize = 0;
30 m_retxBuffer.resize(1024);
31 m_retxBufferSize = 0;
32 m_txedBuffer.resize(1024);
33 m_txedBufferSize = 0;
34
35 m_statusPduRequested = false;
36 m_statusPduBufferSize = 0;
37
38 // State variables: transmitting side
39 m_windowSize = 512;
40 m_vtA = 0;
41 m_vtMs = m_vtA + m_windowSize;
42 m_vtS = 0;
43 m_pollSn = 0;
44
45 // State variables: receiving side
46 m_vrR = 0;
47 m_vrMr = m_vrR + m_windowSize;
48 m_vrX = 0;
49 m_vrMs = 0;
50 m_vrH = 0;
51
52 // Counters
53 m_pduWithoutPoll = 0;
54 m_byteWithoutPoll = 0;
55
56 // Configurable parameters
57 m_maxRetxThreshold = 5;
58 m_pollPdu = 1;
59 m_pollByte = 50;
60
61 // SDU reassembling process
62 m_reassemblingState = WAITING_S0_FULL;
63 m_expectedSeqNumber = 0;
64
65 m_pollRetransmitTimerJustExpired = false;
66}
67
68NrRlcAm::~NrRlcAm()
69{
70 NS_LOG_FUNCTION(this);
71}
72
73TypeId
75{
76 static TypeId tid =
77 TypeId("ns3::NrRlcAm")
78 .SetParent<NrRlc>()
79 .SetGroupName("Nr")
80 .AddConstructor<NrRlcAm>()
81 .AddAttribute("PollRetransmitTimer",
82 "Value of the t-PollRetransmit timer (See section 7.3 of 3GPP TS 36.322)",
83 TimeValue(MilliSeconds(20)),
84 MakeTimeAccessor(&NrRlcAm::m_pollRetransmitTimerValue),
85 MakeTimeChecker())
86 .AddAttribute("ReorderingTimer",
87 "Value of the t-Reordering timer (See section 7.3 of 3GPP TS 36.322)",
88 TimeValue(MilliSeconds(10)),
89 MakeTimeAccessor(&NrRlcAm::m_reorderingTimerValue),
90 MakeTimeChecker())
91 .AddAttribute("StatusProhibitTimer",
92 "Value of the t-StatusProhibit timer (See section 7.3 of 3GPP TS 36.322)",
93 TimeValue(MilliSeconds(10)),
94 MakeTimeAccessor(&NrRlcAm::m_statusProhibitTimerValue),
95 MakeTimeChecker())
96 .AddAttribute(
97 "BufferStatusReportTimer",
98 "How much to wait to issue a new Buffer Status Report since the last time "
99 "a new SDU was received",
100 TimeValue(MilliSeconds(20)),
101 MakeTimeAccessor(&NrRlcAm::m_bsrTimerValue),
102 MakeTimeChecker())
103 .AddAttribute("TxOpportunityForRetxAlwaysBigEnough",
104 "If true, always pretend that the size of a TxOpportunity is big enough "
105 "for retransmission. If false (default and realistic behavior), no retx "
106 "is performed unless the corresponding TxOpportunity is big enough.",
107 BooleanValue(false),
108 MakeBooleanAccessor(&NrRlcAm::m_txOpportunityForRetxAlwaysBigEnough),
109 MakeBooleanChecker())
110 .AddAttribute("MaxTxBufferSize",
111 "Maximum Size of the Transmission Buffer (in Bytes). If zero is "
112 "configured, the buffer is unlimited.",
113 UintegerValue(10 * 1024),
114 MakeUintegerAccessor(&NrRlcAm::m_maxTxBufferSize),
115 MakeUintegerChecker<uint32_t>());
116 return tid;
117}
118
119void
120NrRlcAm::DoDispose()
121{
122 NS_LOG_FUNCTION(this);
123 m_pollRetransmitTimer.Cancel();
124 m_reorderingTimer.Cancel();
125 m_statusProhibitTimer.Cancel();
126 m_bsrTimer.Cancel();
127
128 m_maxTxBufferSize = 0;
129 m_txonBuffer.clear();
130 m_txonBufferSize = 0;
131 m_txedBuffer.clear();
132 m_txedBufferSize = 0;
133 m_retxBuffer.clear();
134 m_retxBufferSize = 0;
135 m_rxonBuffer.clear();
136 m_sdusBuffer.clear();
137 m_keepS0 = nullptr;
138 m_controlPduBuffer = nullptr;
139
140 NrRlc::DoDispose();
141}
142
147void
149{
150 NS_LOG_FUNCTION(this << m_rnti << (uint32_t)m_lcid << p->GetSize());
151
152 if (m_txonBufferSize + p->GetSize() <= m_maxTxBufferSize || (m_maxTxBufferSize == 0))
153 {
156 tag.SetStatus(NrRlcSduStatusTag::FULL_SDU);
157 p->AddPacketTag(tag);
158
159 NS_LOG_LOGIC("Txon Buffer: New packet added");
160 m_txonBuffer.emplace_back(p, Simulator::Now());
161 m_txonBufferSize += p->GetSize();
162 NS_LOG_LOGIC("NumOfBuffers = " << m_txonBuffer.size());
163 NS_LOG_LOGIC("txonBufferSize = " << m_txonBufferSize);
164 }
165 else
166 {
167 // Discard full RLC SDU
168 NS_LOG_LOGIC("TxonBuffer is full. RLC SDU discarded");
169 NS_LOG_LOGIC("MaxTxBufferSize = " << m_maxTxBufferSize);
170 NS_LOG_LOGIC("txonBufferSize = " << m_txonBufferSize);
171 NS_LOG_LOGIC("packet size = " << p->GetSize());
172 m_txDropTrace(p);
173 }
174
176 DoTransmitBufferStatusReport();
177 m_bsrTimer.Cancel();
178 m_bsrTimer = Simulator::Schedule(m_bsrTimerValue, &NrRlcAm::ExpireBsrTimer, this);
179}
180
185void
187{
188 NS_LOG_FUNCTION(this << m_rnti << (uint32_t)m_lcid << txOpParams.bytes);
189
190 if (txOpParams.bytes < 4)
191 {
192 // Stingy MAC: In general, we need more bytes.
193 // There are a more restrictive test for each particular case
194 NS_LOG_LOGIC("TxOpportunity (size = " << txOpParams.bytes << ") too small");
195 NS_ASSERT_MSG(false,
196 "TxOpportunity (size = "
197 << txOpParams.bytes << ") too small.\n"
198 << "Your MAC scheduler is assigned too few resource blocks.");
199 return;
200 }
201
202 if (m_statusPduRequested && !m_statusProhibitTimer.IsPending())
203 {
204 if (txOpParams.bytes < m_statusPduBufferSize)
205 {
206 // Stingy MAC: We need more bytes for the STATUS PDU
207 NS_LOG_LOGIC("TxOpportunity (size = " << txOpParams.bytes
208 << ") too small for the STATUS PDU (size = "
209 << m_statusPduBufferSize << ")");
210 NS_ASSERT_MSG(false,
211 "TxOpportunity (size = "
212 << txOpParams.bytes << ") too small for the STATUS PDU (size = "
213 << m_statusPduBufferSize << ")\n"
214 << "Your MAC scheduler is assigned too few resource blocks.");
215 return;
216 }
217
218 NS_LOG_LOGIC("Sending STATUS PDU");
219
220 Ptr<Packet> packet = Create<Packet>();
221 NrRlcAmHeader rlcAmHeader;
223
224 NS_LOG_LOGIC("Check for SNs to NACK from " << m_vrR.GetValue() << " to "
225 << m_vrMs.GetValue());
227 sn.SetModulusBase(m_vrR);
228 for (sn = m_vrR; sn < m_vrMs; sn++)
229 {
230 NS_LOG_LOGIC("SN = " << sn);
231 if (!rlcAmHeader.OneMoreNackWouldFitIn(txOpParams.bytes))
232 {
233 NS_LOG_LOGIC("Can't fit more NACKs in STATUS PDU");
234 break;
235 }
236 auto pduIt = m_rxonBuffer.find(sn.GetValue());
237 if (pduIt == m_rxonBuffer.end() || (!(pduIt->second.m_pduComplete)))
238 {
239 NS_LOG_LOGIC("adding NACK_SN " << sn.GetValue());
240 rlcAmHeader.PushNack(sn.GetValue());
241 }
242 }
243 NS_LOG_LOGIC("SN at end of NACK loop = " << sn);
244 // 3GPP TS 36.322 section 6.2.2.1.4 ACK SN
245 // find the SN of the next not received RLC Data PDU
246 // which is not reported as missing in the STATUS PDU.
247 auto pduIt = m_rxonBuffer.find(sn.GetValue());
248 while ((sn < m_vrMs) && (pduIt != m_rxonBuffer.end()) && (pduIt->second.m_pduComplete))
249 {
250 NS_LOG_LOGIC("SN = " << sn << " < " << m_vrMs << " = " << (sn < m_vrMs));
251 sn++;
252 NS_LOG_LOGIC("SN = " << sn);
253 pduIt = m_rxonBuffer.find(sn.GetValue());
254 }
255
256 NS_ASSERT_MSG(sn <= m_vrMs,
257 "first SN not reported as missing = " << sn << ", VR(MS) = " << m_vrMs);
258 rlcAmHeader.SetAckSn(sn);
259
260 NS_LOG_LOGIC("RLC header: " << rlcAmHeader);
261 packet->AddHeader(rlcAmHeader);
262
263 // Sender timestamp
264 NrRlcTag rlcTag(Simulator::Now());
265 packet->AddByteTag(rlcTag, 1, rlcAmHeader.GetSerializedSize());
266 m_txPdu(m_rnti, m_lcid, packet->GetSize());
267
268 // Send RLC PDU to MAC layer
270 params.pdu = packet;
271 params.rnti = m_rnti;
272 params.lcid = m_lcid;
273 params.layer = txOpParams.layer;
274 params.harqProcessId = txOpParams.harqId;
275 params.componentCarrierId = txOpParams.componentCarrierId;
276
278
279 m_statusPduRequested = false;
280 m_statusPduBufferSize = 0;
281 m_statusProhibitTimer = Simulator::Schedule(m_statusProhibitTimerValue,
282 &NrRlcAm::ExpireStatusProhibitTimer,
283 this);
284 return;
285 }
286 else if (m_retxBufferSize > 0)
287 {
288 NS_LOG_LOGIC("retxBufferSize = " << m_retxBufferSize);
289 NS_LOG_LOGIC("Sending data from Retransmission Buffer");
290 NS_ASSERT(m_vtA < m_vtS);
292 sn.SetModulusBase(m_vtA);
293 for (sn = m_vtA; sn < m_vtS; sn++)
294 {
295 uint16_t seqNumberValue = sn.GetValue();
296 NS_LOG_LOGIC("SN = " << seqNumberValue << " m_pdu "
297 << m_retxBuffer.at(seqNumberValue).m_pdu);
298
299 if (m_retxBuffer.at(seqNumberValue).m_pdu)
300 {
301 Ptr<Packet> packet = m_retxBuffer.at(seqNumberValue).m_pdu->Copy();
302
303 if ((packet->GetSize() <= txOpParams.bytes) ||
304 m_txOpportunityForRetxAlwaysBigEnough)
305 {
306 // According to 5.2.1, the data field is left as is, but we rebuild the header
307 NrRlcAmHeader rlcAmHeader;
308 packet->RemoveHeader(rlcAmHeader);
309 NS_LOG_LOGIC("old AM RLC header: " << rlcAmHeader);
310
311 // Calculate the Polling Bit (5.2.2.1)
312 rlcAmHeader.SetPollingBit(NrRlcAmHeader::STATUS_REPORT_NOT_REQUESTED);
313
314 NS_LOG_LOGIC("polling conditions: m_txonBuffer.empty="
315 << m_txonBuffer.empty() << " retxBufferSize=" << m_retxBufferSize
316 << " packet->GetSize ()=" << packet->GetSize());
317 if (((m_txonBuffer.empty()) &&
318 (m_retxBufferSize ==
319 packet->GetSize() + rlcAmHeader.GetSerializedSize())) ||
320 (m_vtS >= m_vtMs) || m_pollRetransmitTimerJustExpired)
321 {
322 m_pollRetransmitTimerJustExpired = false;
323 rlcAmHeader.SetPollingBit(NrRlcAmHeader::STATUS_REPORT_IS_REQUESTED);
324 m_pduWithoutPoll = 0;
325 m_byteWithoutPoll = 0;
326
327 m_pollSn = m_vtS - 1;
328 NS_LOG_LOGIC("New POLL_SN = " << m_pollSn);
329
330 if (!m_pollRetransmitTimer.IsPending())
331 {
332 NS_LOG_LOGIC("Start PollRetransmit timer");
333
334 m_pollRetransmitTimer =
335 Simulator::Schedule(m_pollRetransmitTimerValue,
336 &NrRlcAm::ExpirePollRetransmitTimer,
337 this);
338 }
339 else
340 {
341 NS_LOG_LOGIC("Restart PollRetransmit timer");
342
343 m_pollRetransmitTimer.Cancel();
344 m_pollRetransmitTimer =
345 Simulator::Schedule(m_pollRetransmitTimerValue,
346 &NrRlcAm::ExpirePollRetransmitTimer,
347 this);
348 }
349 }
350
351 packet->AddHeader(rlcAmHeader);
352
353 NrRlcTag rlcTag;
354 rlcTag.SetSenderTimestamp(Simulator::Now());
355
356 packet->AddByteTag(rlcTag, 1, rlcAmHeader.GetSerializedSize());
357
358 NS_LOG_LOGIC("new AM RLC header: " << rlcAmHeader);
359
360 m_txPdu(m_rnti, m_lcid, packet->GetSize());
361
362 // Send RLC PDU to MAC layer
364 params.pdu = packet;
365 params.rnti = m_rnti;
366 params.lcid = m_lcid;
367 params.layer = txOpParams.layer;
368 params.harqProcessId = txOpParams.harqId;
369 params.componentCarrierId = txOpParams.componentCarrierId;
370
372
373 m_retxBuffer.at(seqNumberValue).m_retxCount++;
374 m_retxBuffer.at(seqNumberValue).m_waitingSince = Simulator::Now();
375 NS_LOG_INFO("Incr RETX_COUNT for SN = " << seqNumberValue);
376 if (m_retxBuffer.at(seqNumberValue).m_retxCount >= m_maxRetxThreshold)
377 {
378 NS_LOG_INFO("Max RETX_COUNT for SN = " << seqNumberValue);
379 }
380
381 NS_LOG_INFO("Move SN = " << seqNumberValue << " back to txedBuffer");
382 m_txedBuffer.at(seqNumberValue).m_pdu =
383 m_retxBuffer.at(seqNumberValue).m_pdu->Copy();
384 m_txedBuffer.at(seqNumberValue).m_retxCount =
385 m_retxBuffer.at(seqNumberValue).m_retxCount;
386 m_txedBuffer.at(seqNumberValue).m_waitingSince =
387 m_retxBuffer.at(seqNumberValue).m_waitingSince;
388 m_txedBufferSize += m_txedBuffer.at(seqNumberValue).m_pdu->GetSize();
389
390 m_retxBufferSize -= m_retxBuffer.at(seqNumberValue).m_pdu->GetSize();
391 m_retxBuffer.at(seqNumberValue).m_pdu = nullptr;
392 m_retxBuffer.at(seqNumberValue).m_retxCount = 0;
393 m_retxBuffer.at(seqNumberValue).m_waitingSince = MilliSeconds(0);
394
395 NS_LOG_LOGIC("retxBufferSize = " << m_retxBufferSize);
396
397 return;
398 }
399 else
400 {
401 NS_LOG_LOGIC("TxOpportunity (size = "
402 << txOpParams.bytes
403 << ") too small for retransmission of the packet (size = "
404 << packet->GetSize() << ")");
405 NS_LOG_LOGIC("Waiting for bigger TxOpportunity");
406 return;
407 }
408 }
409 }
410 NS_ASSERT_MSG(false, "m_retxBufferSize > 0, but no PDU considered for retx found");
411 }
412 else if (m_txonBufferSize > 0)
413 {
414 if (txOpParams.bytes < 7)
415 {
416 // Stingy MAC: We need more bytes for new DATA PDUs.
417 NS_LOG_LOGIC("TxOpportunity (size = " << txOpParams.bytes
418 << ") too small for DATA PDU");
419 NS_ASSERT_MSG(false,
420 "TxOpportunity (size = "
421 << txOpParams.bytes << ") too small for DATA PDU\n"
422 << "Your MAC scheduler is assigned too few resource blocks.");
423 return;
424 }
425
426 NS_ASSERT(m_vtS <= m_vtMs);
427 if (m_vtS == m_vtMs)
428 {
429 NS_LOG_INFO("cannot transmit new RLC PDU due to window stalling");
430 return;
431 }
432
433 NS_LOG_LOGIC("Sending data from Transmission Buffer");
434 }
435 else
436 {
437 NS_LOG_LOGIC("No data pending");
438 return;
439 }
440
441 //
442 //
443 // Build new PDU
444 //
445 //
446
447 Ptr<Packet> packet = Create<Packet>();
448 NrRlcAmHeader rlcAmHeader;
449 rlcAmHeader.SetDataPdu();
450
451 // Build Data field
452 uint32_t nextSegmentSize = txOpParams.bytes - 4;
453 uint32_t nextSegmentId = 1;
454 uint32_t dataFieldAddedSize = 0;
455 std::vector<Ptr<Packet>> dataField;
456
457 // Remove the first packet from the transmission buffer.
458 // If only a segment of the packet is taken, then the remaining is given back later
459 if (m_txonBuffer.empty())
460 {
461 NS_LOG_LOGIC("No data pending");
462 return;
463 }
464
465 NS_LOG_LOGIC("SDUs in TxonBuffer = " << m_txonBuffer.size());
466 NS_LOG_LOGIC("First SDU buffer = " << m_txonBuffer.begin()->m_pdu);
467 NS_LOG_LOGIC("First SDU size = " << m_txonBuffer.begin()->m_pdu->GetSize());
468 NS_LOG_LOGIC("Next segment size = " << nextSegmentSize);
469 NS_LOG_LOGIC("Remove SDU from TxBuffer");
470 Time firstSegmentTime = m_txonBuffer.begin()->m_waitingSince;
471 Ptr<Packet> firstSegment = m_txonBuffer.begin()->m_pdu->Copy();
472 m_txonBufferSize -= m_txonBuffer.begin()->m_pdu->GetSize();
473 NS_LOG_LOGIC("txBufferSize = " << m_txonBufferSize);
474 m_txonBuffer.erase(m_txonBuffer.begin());
475
476 while (firstSegment && (firstSegment->GetSize() > 0) && (nextSegmentSize > 0))
477 {
478 NS_LOG_LOGIC("WHILE ( firstSegment && firstSegment->GetSize > 0 && nextSegmentSize > 0 )");
479 NS_LOG_LOGIC(" firstSegment size = " << firstSegment->GetSize());
480 NS_LOG_LOGIC(" nextSegmentSize = " << nextSegmentSize);
481 if ((firstSegment->GetSize() > nextSegmentSize) ||
482 // Segment larger than 2047 octets can only be mapped to the end of the Data field
483 (firstSegment->GetSize() > 2047))
484 {
485 // Take the minimum size, due to the 2047-bytes 3GPP exception
486 // This exception is due to the length of the LI field (just 11 bits)
487 uint32_t currSegmentSize = std::min(firstSegment->GetSize(), nextSegmentSize);
488
489 NS_LOG_LOGIC(" IF ( firstSegment > nextSegmentSize ||");
490 NS_LOG_LOGIC(" firstSegment > 2047 )");
491
492 // Segment txBuffer.FirstBuffer and
493 // Give back the remaining segment to the transmission buffer
494 Ptr<Packet> newSegment = firstSegment->CreateFragment(0, currSegmentSize);
495 NS_LOG_LOGIC(" newSegment size = " << newSegment->GetSize());
496
497 // Status tag of the new and remaining segments
498 // Note: This is the only place where a PDU is segmented and
499 // therefore its status can change
500 NrRlcSduStatusTag oldTag;
501 NrRlcSduStatusTag newTag;
502 firstSegment->RemovePacketTag(oldTag);
503 newSegment->RemovePacketTag(newTag);
504 if (oldTag.GetStatus() == NrRlcSduStatusTag::FULL_SDU)
505 {
506 newTag.SetStatus(NrRlcSduStatusTag::FIRST_SEGMENT);
507 oldTag.SetStatus(NrRlcSduStatusTag::LAST_SEGMENT);
508 }
509 else if (oldTag.GetStatus() == NrRlcSduStatusTag::LAST_SEGMENT)
510 {
511 newTag.SetStatus(NrRlcSduStatusTag::MIDDLE_SEGMENT);
512 // oldTag.SetStatus (NrRlcSduStatusTag::LAST_SEGMENT);
513 }
514
515 // Give back the remaining segment to the transmission buffer
516 firstSegment->RemoveAtStart(currSegmentSize);
517 NS_LOG_LOGIC(
518 " firstSegment size (after RemoveAtStart) = " << firstSegment->GetSize());
519 if (firstSegment->GetSize() > 0)
520 {
521 firstSegment->AddPacketTag(oldTag);
522
523 m_txonBuffer.insert(m_txonBuffer.begin(), TxPdu(firstSegment, firstSegmentTime));
524 m_txonBufferSize += m_txonBuffer.begin()->m_pdu->GetSize();
525
526 NS_LOG_LOGIC(" Txon buffer: Give back the remaining segment");
527 NS_LOG_LOGIC(" Txon buffers = " << m_txonBuffer.size());
528 NS_LOG_LOGIC(" Front buffer size = " << m_txonBuffer.begin()->m_pdu->GetSize());
529 NS_LOG_LOGIC(" txonBufferSize = " << m_txonBufferSize);
530 }
531 else
532 {
533 // Whole segment was taken, so adjust tag
534 if (newTag.GetStatus() == NrRlcSduStatusTag::FIRST_SEGMENT)
535 {
536 newTag.SetStatus(NrRlcSduStatusTag::FULL_SDU);
537 }
538 else if (newTag.GetStatus() == NrRlcSduStatusTag::MIDDLE_SEGMENT)
539 {
540 newTag.SetStatus(NrRlcSduStatusTag::LAST_SEGMENT);
541 }
542 }
543 // Segment is completely taken or
544 // the remaining segment is given back to the transmission buffer
545 firstSegment = nullptr;
546
547 // Put status tag once it has been adjusted
548 newSegment->AddPacketTag(newTag);
549
550 // Add Segment to Data field
551 dataFieldAddedSize = newSegment->GetSize();
552 dataField.push_back(newSegment);
553 newSegment = nullptr;
554
555 // ExtensionBit (Next_Segment - 1) = 0
556 rlcAmHeader.PushExtensionBit(NrRlcAmHeader::DATA_FIELD_FOLLOWS);
557
558 // no LengthIndicator for the last one
559
560 nextSegmentSize -= dataFieldAddedSize;
561 nextSegmentId++;
562
563 // nextSegmentSize MUST be zero (only if segment is smaller or equal to 2047)
564
565 // (NO more segments) ? exit
566 // break;
567 }
568 else if ((nextSegmentSize - firstSegment->GetSize() <= 2) || m_txonBuffer.empty())
569 {
570 NS_LOG_LOGIC(
571 " IF nextSegmentSize - firstSegment->GetSize () <= 2 || txonBuffer.size == 0");
572
573 // Add txBuffer.FirstBuffer to DataField
574 dataFieldAddedSize = firstSegment->GetSize();
575 dataField.push_back(firstSegment);
576 firstSegment = nullptr;
577
578 // ExtensionBit (Next_Segment - 1) = 0
579 rlcAmHeader.PushExtensionBit(NrRlcAmHeader::DATA_FIELD_FOLLOWS);
580
581 // no LengthIndicator for the last one
582
583 nextSegmentSize -= dataFieldAddedSize;
584 nextSegmentId++;
585
586 NS_LOG_LOGIC(" SDUs in TxBuffer = " << m_txonBuffer.size());
587 if (!m_txonBuffer.empty())
588 {
589 NS_LOG_LOGIC(" First SDU buffer = " << m_txonBuffer.begin()->m_pdu);
590 NS_LOG_LOGIC(
591 " First SDU size = " << m_txonBuffer.begin()->m_pdu->GetSize());
592 }
593 NS_LOG_LOGIC(" Next segment size = " << nextSegmentSize);
594
595 // nextSegmentSize <= 2 (only if txBuffer is not empty)
596
597 // (NO more segments) ? exit
598 // break;
599 }
600 else // (firstSegment->GetSize () < m_nextSegmentSize) && (m_txBuffer.size () > 0)
601 {
602 NS_LOG_LOGIC(" IF firstSegment < NextSegmentSize && txonBuffer.size > 0");
603 // Add txBuffer.FirstBuffer to DataField
604 dataFieldAddedSize = firstSegment->GetSize();
605 dataField.push_back(firstSegment);
606
607 // ExtensionBit (Next_Segment - 1) = 1
608 rlcAmHeader.PushExtensionBit(NrRlcAmHeader::E_LI_FIELDS_FOLLOWS);
609
610 // LengthIndicator (Next_Segment) = txBuffer.FirstBuffer.length()
611 rlcAmHeader.PushLengthIndicator(firstSegment->GetSize());
612
613 nextSegmentSize -= ((nextSegmentId % 2) ? (2) : (1)) + dataFieldAddedSize;
614 nextSegmentId++;
615
616 NS_LOG_LOGIC(" SDUs in TxBuffer = " << m_txonBuffer.size());
617 if (!m_txonBuffer.empty())
618 {
619 NS_LOG_LOGIC(" First SDU buffer = " << m_txonBuffer.begin()->m_pdu);
620 NS_LOG_LOGIC(
621 " First SDU size = " << m_txonBuffer.begin()->m_pdu->GetSize());
622 }
623 NS_LOG_LOGIC(" Next segment size = " << nextSegmentSize);
624 NS_LOG_LOGIC(" Remove SDU from TxBuffer");
625
626 // (more segments)
627 firstSegment = m_txonBuffer.begin()->m_pdu->Copy();
628 firstSegmentTime = m_txonBuffer.begin()->m_waitingSince;
629 m_txonBufferSize -= m_txonBuffer.begin()->m_pdu->GetSize();
630 m_txonBuffer.erase(m_txonBuffer.begin());
631 NS_LOG_LOGIC(" txBufferSize = " << m_txonBufferSize);
632 }
633 }
634
635 //
636 // Build RLC header
637 //
638
639 rlcAmHeader.SetSequenceNumber(m_vtS++);
640 rlcAmHeader.SetResegmentationFlag(NrRlcAmHeader::PDU);
641 rlcAmHeader.SetLastSegmentFlag(NrRlcAmHeader::LAST_PDU_SEGMENT);
642 rlcAmHeader.SetSegmentOffset(0);
643
644 NS_ASSERT_MSG(rlcAmHeader.GetSequenceNumber() < m_vtMs, "SN above TX window");
645 NS_ASSERT_MSG(rlcAmHeader.GetSequenceNumber() >= m_vtA, "SN below TX window");
646
647 // Calculate FramingInfo flag according the status of the SDUs in the DataField
648 uint8_t framingInfo = 0;
649 auto it = dataField.begin();
650
651 // FIRST SEGMENT
653 NS_ASSERT_MSG((*it)->PeekPacketTag(tag), "NrRlcSduStatusTag is missing");
654 (*it)->PeekPacketTag(tag);
655 if ((tag.GetStatus() == NrRlcSduStatusTag::FULL_SDU) ||
656 (tag.GetStatus() == NrRlcSduStatusTag::FIRST_SEGMENT))
657 {
658 framingInfo |= NrRlcAmHeader::FIRST_BYTE;
659 }
660 else
661 {
662 framingInfo |= NrRlcAmHeader::NO_FIRST_BYTE;
663 }
664
665 // Add all SDUs (in DataField) to the Packet
666 while (it < dataField.end())
667 {
668 NS_LOG_LOGIC("Adding SDU/segment to packet, length = " << (*it)->GetSize());
669
670 NS_ASSERT_MSG((*it)->PeekPacketTag(tag), "NrRlcSduStatusTag is missing");
671 (*it)->RemovePacketTag(tag);
672 if (packet->GetSize() > 0)
673 {
674 packet->AddAtEnd(*it);
675 }
676 else
677 {
678 packet = (*it);
679 }
680 it++;
681 }
682
683 // LAST SEGMENT (Note: There could be only one and be the first one)
684 it--;
685 if ((tag.GetStatus() == NrRlcSduStatusTag::FULL_SDU) ||
686 (tag.GetStatus() == NrRlcSduStatusTag::LAST_SEGMENT))
687 {
688 framingInfo |= NrRlcAmHeader::LAST_BYTE;
689 }
690 else
691 {
692 framingInfo |= NrRlcAmHeader::NO_LAST_BYTE;
693 }
694
695 // Set the FramingInfo flag after the calculation
696 rlcAmHeader.SetFramingInfo(framingInfo);
697
698 // Calculate the Polling Bit (5.2.2.1)
699 rlcAmHeader.SetPollingBit(NrRlcAmHeader::STATUS_REPORT_NOT_REQUESTED);
700
701 m_pduWithoutPoll++;
702 NS_LOG_LOGIC("PDU_WITHOUT_POLL = " << m_pduWithoutPoll);
703 m_byteWithoutPoll += packet->GetSize();
704 NS_LOG_LOGIC("BYTE_WITHOUT_POLL = " << m_byteWithoutPoll);
705
706 if ((m_pduWithoutPoll >= m_pollPdu) || (m_byteWithoutPoll >= m_pollByte) ||
707 ((m_txonBuffer.empty()) && (m_retxBufferSize == 0)) || (m_vtS >= m_vtMs) ||
708 m_pollRetransmitTimerJustExpired)
709 {
710 m_pollRetransmitTimerJustExpired = false;
711 rlcAmHeader.SetPollingBit(NrRlcAmHeader::STATUS_REPORT_IS_REQUESTED);
712 m_pduWithoutPoll = 0;
713 m_byteWithoutPoll = 0;
714
715 m_pollSn = m_vtS - 1;
716 NS_LOG_LOGIC("New POLL_SN = " << m_pollSn);
717
718 if (!m_pollRetransmitTimer.IsPending())
719 {
720 NS_LOG_LOGIC("Start PollRetransmit timer");
721
722 m_pollRetransmitTimer = Simulator::Schedule(m_pollRetransmitTimerValue,
723 &NrRlcAm::ExpirePollRetransmitTimer,
724 this);
725 }
726 else
727 {
728 NS_LOG_LOGIC("Restart PollRetransmit timer");
729
730 m_pollRetransmitTimer.Cancel();
731 m_pollRetransmitTimer = Simulator::Schedule(m_pollRetransmitTimerValue,
732 &NrRlcAm::ExpirePollRetransmitTimer,
733 this);
734 }
735 }
736
737 // Build RLC PDU with DataField and Header
738 NS_LOG_LOGIC("AM RLC header: " << rlcAmHeader);
739
740 NrRlcTag rlcTag;
741 rlcTag.SetSenderTimestamp(Simulator::Now());
742
743 packet->AddHeader(rlcAmHeader);
744 packet->AddByteTag(rlcTag, 1, rlcAmHeader.GetSerializedSize());
745
746 // Store new PDU into the Transmitted PDU Buffer
747 NS_LOG_LOGIC("Put transmitted PDU in the txedBuffer");
748 m_txedBufferSize += packet->GetSize();
749 m_txedBuffer.at(rlcAmHeader.GetSequenceNumber().GetValue()).m_pdu = packet->Copy();
750 m_txedBuffer.at(rlcAmHeader.GetSequenceNumber().GetValue()).m_retxCount = 0;
751 m_txedBuffer.at(rlcAmHeader.GetSequenceNumber().GetValue()).m_waitingSince = Simulator::Now();
752
753 m_txPdu(m_rnti, m_lcid, packet->GetSize());
754
755 // Send RLC PDU to MAC layer
757 params.pdu = packet;
758 params.rnti = m_rnti;
759 params.lcid = m_lcid;
760 params.layer = txOpParams.layer;
761 params.harqProcessId = txOpParams.harqId;
762 params.componentCarrierId = txOpParams.componentCarrierId;
763
765}
766
767void
769{
770 NS_LOG_FUNCTION(this);
771}
772
773void
775{
776 NS_LOG_FUNCTION(this << m_rnti << (uint32_t)m_lcid << rxPduParams.p->GetSize());
777
778 // Get RLC header parameters
779 NrRlcAmHeader rlcAmHeader;
780 rxPduParams.p->PeekHeader(rlcAmHeader);
781 NS_LOG_LOGIC("RLC header: " << rlcAmHeader);
782
783 // Receiver timestamp
784 Time delay;
785 NrRlcTag rlcTag;
786
787 bool ret = rxPduParams.p->FindFirstMatchingByteTag(rlcTag);
788 NS_ASSERT_MSG(ret, "NrRlcTag not found in RLC Header. The packet went into a real network?");
789
790 delay = Simulator::Now() - rlcTag.GetSenderTimestamp();
791
792 m_rxPdu(m_rnti, m_lcid, rxPduParams.p->GetSize(), delay.GetNanoSeconds());
793
794 if (rlcAmHeader.IsDataPdu())
795 {
796 // 5.1.3.1 Transmit operations
797
798 // 5.1.3.1.1 General
799 //
800 // The transmitting side of an AM RLC entity shall prioritize transmission of RLC control
801 // PDUs over RLC data PDUs. The transmitting side of an AM RLC entity shall prioritize
802 // retransmission of RLC data PDUs over transmission of new AMD PDUs.
803 //
804 // The transmitting side of an AM RLC entity shall maintain a transmitting window according
805 // to state variables VT(A) and VT(MS) as follows:
806 // - a SN falls within the transmitting window if VT(A) <= SN < VT(MS);
807 // - a SN falls outside of the transmitting window otherwise.
808 //
809 // The transmitting side of an AM RLC entity shall not deliver to lower layer any RLC data
810 // PDU whose SN falls outside of the transmitting window.
811 //
812 // When delivering a new AMD PDU to lower layer, the transmitting side of an AM RLC entity
813 // shall:
814 // - set the SN of the AMD PDU to VT(S), and then increment VT(S) by one.
815 //
816 // The transmitting side of an AM RLC entity can receive a positive acknowledgement
817 // (confirmation of successful reception by its peer AM RLC entity) for a RLC data PDU by
818 // the following:
819 // - STATUS PDU from its peer AM RLC entity.
820 //
821 // When receiving a positive acknowledgement for an AMD PDU with SN = VT(A), the
822 // transmitting side of an AM RLC entity shall:
823 // - set VT(A) equal to the SN of the AMD PDU with the smallest SN, whose SN falls within
824 // the
825 // range VT(A) <= SN <= VT(S) and for which a positive acknowledgment has not been
826 // received yet.
827 // - if positive acknowledgements have been received for all AMD PDUs associated with
828 // a transmitted RLC SDU:
829 // - send an indication to the upper layers of successful delivery of the RLC SDU.
830
831 // 5.1.3.2 Receive operations
832 //
833 // 5.1.3.2.1 General
834 //
835 // The receiving side of an AM RLC entity shall maintain a receiving window according to
836 // state variables VR(R) and VR(MR) as follows:
837 // - a SN falls within the receiving window if VR(R) <= SN < VR(MR);
838 // - a SN falls outside of the receiving window otherwise.
839 //
840 // When receiving a RLC data PDU from lower layer, the receiving side of an AM RLC entity
841 // shall:
842 // - either discard the received RLC data PDU or place it in the reception buffer (see sub
843 // clause 5.1.3.2.2);
844 // - if the received RLC data PDU was placed in the reception buffer:
845 // - update state variables, reassemble and deliver RLC SDUs to upper layer and start/stop
846 // t-Reordering as needed (see sub clause 5.1.3.2.3).
847 //
848 // When t-Reordering expires, the receiving side of an AM RLC entity shall:
849 // - update state variables and start t-Reordering as needed (see sub clause 5.1.3.2.4).
850
851 nr::SequenceNumber10 seqNumber = rlcAmHeader.GetSequenceNumber();
852 seqNumber.SetModulusBase(m_vrR);
853
854 if (rlcAmHeader.GetResegmentationFlag() == NrRlcAmHeader::SEGMENT)
855 {
856 NS_LOG_LOGIC("PDU segment received ( SN = " << seqNumber << " )");
857 }
858 else if (rlcAmHeader.GetResegmentationFlag() == NrRlcAmHeader::PDU)
859 {
860 NS_LOG_LOGIC("PDU received ( SN = " << seqNumber << " )");
861 }
862 else
863 {
864 NS_ASSERT_MSG(false, "Neither a PDU segment nor a PDU received");
865 return;
866 }
867
868 // STATUS PDU is requested
869 if (rlcAmHeader.GetPollingBit() == NrRlcAmHeader::STATUS_REPORT_IS_REQUESTED)
870 {
871 m_statusPduRequested = true;
872 m_statusPduBufferSize = 4;
873
874 if (!m_statusProhibitTimer.IsPending())
875 {
876 DoTransmitBufferStatusReport();
877 }
878 }
879
880 // 5.1.3.2.2 Actions when a RLC data PDU is received from lower layer
881 //
882 // When a RLC data PDU is received from lower layer, where the RLC data PDU contains
883 // byte segment numbers y to z of an AMD PDU with SN = x, the receiving side of an AM RLC
884 // entity shall:
885 // - if x falls outside of the receiving window; or
886 // - if byte segment numbers y to z of the AMD PDU with SN = x have been received before:
887 // - discard the received RLC data PDU;
888 // - else:
889 // - place the received RLC data PDU in the reception buffer;
890 // - if some byte segments of the AMD PDU contained in the RLC data PDU have been
891 // received before:
892 // - discard the duplicate byte segments.
893
894 NS_LOG_LOGIC("VR(R) = " << m_vrR);
895 NS_LOG_LOGIC("VR(MR) = " << m_vrMr);
896 NS_LOG_LOGIC("VR(X) = " << m_vrX);
897 NS_LOG_LOGIC("VR(MS) = " << m_vrMs);
898 NS_LOG_LOGIC("VR(H) = " << m_vrH);
899
900 // - if x falls outside of the receiving window; or
901 // - if byte segment numbers y to z of the AMD PDU with SN = x have been received before:
902 if (!IsInsideReceivingWindow(seqNumber))
903 {
904 NS_LOG_LOGIC("PDU discarded");
905 return;
906 }
907 else
908 {
909 // - if some byte segments of the AMD PDU contained in the RLC data PDU have been
910 // received before:
911 // - discard the duplicate byte segments.
912 // note: re-segmentation of AMD PDU is currently not supported,
913 // so we just check that the segment was not received before
914 auto it = m_rxonBuffer.find(seqNumber.GetValue());
915 if (it != m_rxonBuffer.end())
916 {
917 NS_ASSERT(!it->second.m_byteSegments.empty());
918 NS_ASSERT_MSG(it->second.m_byteSegments.size() == 1,
919 "re-segmentation not supported");
920 NS_LOG_LOGIC("PDU segment already received, discarded");
921 }
922 else
923 {
924 NS_LOG_LOGIC("Place PDU in the reception buffer ( SN = " << seqNumber << " )");
925 m_rxonBuffer[seqNumber.GetValue()].m_byteSegments.push_back(rxPduParams.p);
926 m_rxonBuffer[seqNumber.GetValue()].m_pduComplete = true;
927 }
928 }
929
930 // 5.1.3.2.3 Actions when a RLC data PDU is placed in the reception buffer
931 // When a RLC data PDU with SN = x is placed in the reception buffer,
932 // the receiving side of an AM RLC entity shall:
933
934 // - if x >= VR(H)
935 // - update VR(H) to x+ 1;
936
937 if (seqNumber >= m_vrH)
938 {
939 m_vrH = seqNumber + 1;
940 NS_LOG_LOGIC("New VR(H) = " << m_vrH);
941 }
942
943 // - if all byte segments of the AMD PDU with SN = VR(MS) are received:
944 // - update VR(MS) to the SN of the first AMD PDU with SN > current VR(MS) for
945 // which not all byte segments have been received;
946
947 auto it = m_rxonBuffer.find(m_vrMs.GetValue());
948 if (it != m_rxonBuffer.end() && it->second.m_pduComplete)
949 {
950 int firstVrMs = m_vrMs.GetValue();
951 while (it != m_rxonBuffer.end() && it->second.m_pduComplete)
952 {
953 m_vrMs++;
954 it = m_rxonBuffer.find(m_vrMs.GetValue());
955 NS_LOG_LOGIC("Incr VR(MS) = " << m_vrMs);
956
957 NS_ASSERT_MSG(firstVrMs != m_vrMs.GetValue(), "Infinite loop in RxonBuffer");
958 }
959 NS_LOG_LOGIC("New VR(MS) = " << m_vrMs);
960 }
961
962 // - if x = VR(R):
963 // - if all byte segments of the AMD PDU with SN = VR(R) are received:
964 // - update VR(R) to the SN of the first AMD PDU with SN > current VR(R) for which
965 // not all byte segments have been received;
966 // - update VR(MR) to the updated VR(R) + AM_Window_Size;
967 // - reassemble RLC SDUs from any byte segments of AMD PDUs with SN that falls outside
968 // of the receiving window and in-sequence byte segments of the AMD PDU with SN = VR(R),
969 // remove RLC headers when doing so and deliver the reassembled RLC SDUs to upper layer
970 // in sequence if not delivered before;
971
972 if (seqNumber == m_vrR)
973 {
974 auto it = m_rxonBuffer.find(seqNumber.GetValue());
975 if (it != m_rxonBuffer.end() && it->second.m_pduComplete)
976 {
977 it = m_rxonBuffer.find(m_vrR.GetValue());
978 int firstVrR = m_vrR.GetValue();
979 while (it != m_rxonBuffer.end() && it->second.m_pduComplete)
980 {
981 NS_LOG_LOGIC("Reassemble and Deliver ( SN = " << m_vrR << " )");
982 NS_ASSERT_MSG(it->second.m_byteSegments.size() == 1,
983 "Too many segments. PDU Reassembly process didn't work");
984 ReassembleAndDeliver(it->second.m_byteSegments.front());
985 m_rxonBuffer.erase(m_vrR.GetValue());
986
987 m_vrR++;
988 m_vrR.SetModulusBase(m_vrR);
989 m_vrX.SetModulusBase(m_vrR);
990 m_vrMs.SetModulusBase(m_vrR);
991 m_vrH.SetModulusBase(m_vrR);
992 it = m_rxonBuffer.find(m_vrR.GetValue());
993
994 NS_ASSERT_MSG(firstVrR != m_vrR.GetValue(), "Infinite loop in RxonBuffer");
995 }
996 NS_LOG_LOGIC("New VR(R) = " << m_vrR);
997 m_vrMr = m_vrR + m_windowSize;
998
999 NS_LOG_LOGIC("New VR(MR) = " << m_vrMr);
1000 }
1001 }
1002
1003 // - if t-Reordering is running:
1004 // - if VR(X) = VR(R); or
1005 // - if VR(X) falls outside of the receiving window and VR(X) is not equal to VR(MR):
1006 // - stop and reset t-Reordering;
1007
1008 if (m_reorderingTimer.IsPending())
1009 {
1010 NS_LOG_LOGIC("Reordering timer is running");
1011 if ((m_vrX == m_vrR) || ((!IsInsideReceivingWindow(m_vrX)) && (m_vrX != m_vrMr)))
1012 {
1014 NS_LOG_LOGIC("Stop reordering timer");
1015 m_reorderingTimer.Cancel();
1016 }
1017 }
1018
1019 // - if t-Reordering is not running (includes the case t-Reordering is stopped due to
1020 // actions above):
1021 // - if VR (H) > VR(R):
1022 // - start t-Reordering;
1023 // - set VR(X) to VR(H).
1024
1025 if (!m_reorderingTimer.IsPending())
1026 {
1027 NS_LOG_LOGIC("Reordering timer is not running");
1028 if (m_vrH > m_vrR)
1029 {
1030 NS_LOG_LOGIC("Start reordering timer");
1031 m_reorderingTimer = Simulator::Schedule(m_reorderingTimerValue,
1032 &NrRlcAm::ExpireReorderingTimer,
1033 this);
1034 m_vrX = m_vrH;
1035 NS_LOG_LOGIC("New VR(X) = " << m_vrX);
1036 }
1037 }
1038 }
1039 else if (rlcAmHeader.IsControlPdu())
1040 {
1041 NS_LOG_INFO("Control AM RLC PDU");
1042
1043 nr::SequenceNumber10 ackSn = rlcAmHeader.GetAckSn();
1045
1046 NS_LOG_INFO("ackSn = " << ackSn);
1047 NS_LOG_INFO("VT(A) = " << m_vtA);
1048 NS_LOG_INFO("VT(S) = " << m_vtS);
1049 NS_LOG_LOGIC("retxBufferSize = " << m_retxBufferSize);
1050 NS_LOG_LOGIC("txedBufferSize = " << m_txedBufferSize);
1051
1052 m_vtA.SetModulusBase(m_vtA);
1053 m_vtS.SetModulusBase(m_vtA);
1054 m_vtMs.SetModulusBase(m_vtA);
1055 ackSn.SetModulusBase(m_vtA);
1056 sn.SetModulusBase(m_vtA);
1057
1058 bool incrementVtA = true;
1059
1060 for (sn = m_vtA; sn < ackSn && sn < m_vtS; sn++)
1061 {
1062 NS_LOG_LOGIC("sn = " << sn);
1063
1064 uint16_t seqNumberValue = sn.GetValue();
1065
1066 if (m_pollRetransmitTimer.IsPending() && (seqNumberValue == m_pollSn.GetValue()))
1067 {
1068 m_pollRetransmitTimer.Cancel();
1069 }
1070
1071 if (rlcAmHeader.IsNackPresent(sn))
1072 {
1073 NS_LOG_LOGIC("sn " << sn << " is NACKed");
1074
1075 incrementVtA = false;
1076
1077 if (m_txedBuffer.at(seqNumberValue).m_pdu)
1078 {
1079 NS_LOG_INFO("Move SN = " << seqNumberValue << " to retxBuffer");
1080 m_retxBuffer.at(seqNumberValue).m_pdu =
1081 m_txedBuffer.at(seqNumberValue).m_pdu->Copy();
1082 m_retxBuffer.at(seqNumberValue).m_retxCount =
1083 m_txedBuffer.at(seqNumberValue).m_retxCount;
1084 m_retxBuffer.at(seqNumberValue).m_waitingSince =
1085 m_txedBuffer.at(seqNumberValue).m_waitingSince;
1086 m_retxBufferSize += m_retxBuffer.at(seqNumberValue).m_pdu->GetSize();
1087
1088 m_txedBufferSize -= m_txedBuffer.at(seqNumberValue).m_pdu->GetSize();
1089 m_txedBuffer.at(seqNumberValue).m_pdu = nullptr;
1090 m_txedBuffer.at(seqNumberValue).m_retxCount = 0;
1091 m_txedBuffer.at(seqNumberValue).m_waitingSince = MilliSeconds(0);
1092 }
1093
1094 NS_ASSERT(m_retxBuffer.at(seqNumberValue).m_pdu);
1095 }
1096 else
1097 {
1098 NS_LOG_LOGIC("sn " << sn << " is ACKed");
1099
1100 if (m_txedBuffer.at(seqNumberValue).m_pdu)
1101 {
1102 NS_LOG_INFO("ACKed SN = " << seqNumberValue << " from txedBuffer");
1103 // NS_LOG_INFO ("m_txedBuffer( " << m_vtA << " )->GetSize = " <<
1104 // m_txedBuffer.at (m_vtA.GetValue ())->GetSize ());
1105 m_txedBufferSize -= m_txedBuffer.at(seqNumberValue).m_pdu->GetSize();
1106 m_txedBuffer.at(seqNumberValue).m_pdu = nullptr;
1107 m_txedBuffer.at(seqNumberValue).m_waitingSince = MilliSeconds(0);
1108 NS_ASSERT(!m_retxBuffer.at(seqNumberValue).m_pdu);
1109 }
1110
1111 if (m_retxBuffer.at(seqNumberValue).m_pdu)
1112 {
1113 NS_LOG_INFO("ACKed SN = " << seqNumberValue << " from retxBuffer");
1114 m_retxBufferSize -= m_retxBuffer.at(seqNumberValue).m_pdu->GetSize();
1115 m_retxBuffer.at(seqNumberValue).m_pdu = nullptr;
1116 m_retxBuffer.at(seqNumberValue).m_retxCount = 0;
1117 m_retxBuffer.at(seqNumberValue).m_waitingSince = MilliSeconds(0);
1118 }
1119 }
1120
1121 NS_LOG_LOGIC("retxBufferSize = " << m_retxBufferSize);
1122 NS_LOG_LOGIC("txedBufferSize = " << m_txedBufferSize);
1123
1124 if (incrementVtA)
1125 {
1126 m_vtA++;
1127 m_vtMs = m_vtA + m_windowSize;
1128 NS_LOG_INFO("New VT(A) = " << m_vtA);
1129 m_vtA.SetModulusBase(m_vtA);
1130 m_vtMs.SetModulusBase(m_vtA);
1131 m_vtS.SetModulusBase(m_vtA);
1132 ackSn.SetModulusBase(m_vtA);
1133 sn.SetModulusBase(m_vtA);
1134 }
1135
1136 } // loop over SN : VT(A) <= SN < ACK SN
1137
1138 return;
1139 }
1140 else
1141 {
1142 NS_LOG_WARN("Wrong AM RLC PDU type");
1143 return;
1144 }
1145}
1146
1147bool
1148NrRlcAm::IsInsideReceivingWindow(nr::SequenceNumber10 seqNumber)
1149{
1150 NS_LOG_FUNCTION(this << seqNumber);
1151 NS_LOG_LOGIC("Receiving Window: " << m_vrR << " <= " << seqNumber << " <= " << m_vrMr);
1152
1153 m_vrR.SetModulusBase(m_vrR);
1154 m_vrMr.SetModulusBase(m_vrR);
1155 seqNumber.SetModulusBase(m_vrR);
1156
1157 if ((m_vrR <= seqNumber) && (seqNumber < m_vrMr))
1158 {
1159 NS_LOG_LOGIC(seqNumber << " is INSIDE the receiving window");
1160 return true;
1161 }
1162 else
1163 {
1164 NS_LOG_LOGIC(seqNumber << " is OUTSIDE the receiving window");
1165 return false;
1166 }
1167}
1168
1169void
1170NrRlcAm::ReassembleAndDeliver(Ptr<Packet> packet)
1171{
1172 NrRlcAmHeader rlcAmHeader;
1173 NrRlcTag rlcTag;
1174 bool ret = packet->FindFirstMatchingByteTag(rlcTag);
1175 NS_ASSERT(ret);
1176 packet->RemoveHeader(rlcAmHeader);
1177 ret = packet->FindFirstMatchingByteTag(rlcTag);
1178 NS_ASSERT(!ret);
1179 uint8_t framingInfo = rlcAmHeader.GetFramingInfo();
1180 nr::SequenceNumber10 currSeqNumber = rlcAmHeader.GetSequenceNumber();
1181 bool expectedSnLost;
1182
1183 if (currSeqNumber != m_expectedSeqNumber)
1184 {
1185 expectedSnLost = true;
1186 NS_LOG_LOGIC("There are losses. Expected SN = " << m_expectedSeqNumber
1187 << ". Current SN = " << currSeqNumber);
1188 m_expectedSeqNumber = currSeqNumber + 1;
1189 }
1190 else
1191 {
1192 expectedSnLost = false;
1193 NS_LOG_LOGIC("No losses. Expected SN = " << m_expectedSeqNumber
1194 << ". Current SN = " << currSeqNumber);
1195 m_expectedSeqNumber = m_expectedSeqNumber + 1;
1196 }
1197
1198 // Build list of SDUs
1199 uint8_t extensionBit;
1200 uint16_t lengthIndicator;
1201 do
1202 {
1203 extensionBit = rlcAmHeader.PopExtensionBit();
1204 NS_LOG_LOGIC("E = " << (uint16_t)extensionBit);
1205
1206 if (extensionBit == 0)
1207 {
1208 m_sdusBuffer.push_back(packet);
1209 }
1210 else // extensionBit == 1
1211 {
1212 lengthIndicator = rlcAmHeader.PopLengthIndicator();
1213 NS_LOG_LOGIC("LI = " << lengthIndicator);
1214
1215 // Check if there is enough data in the packet
1216 if (lengthIndicator >= packet->GetSize())
1217 {
1218 NS_LOG_LOGIC("INTERNAL ERROR: Not enough data in the packet ("
1219 << packet->GetSize() << "). Needed LI=" << lengthIndicator);
1221 }
1222
1223 // Split packet in two fragments
1224 Ptr<Packet> data_field = packet->CreateFragment(0, lengthIndicator);
1225 packet->RemoveAtStart(lengthIndicator);
1226
1227 m_sdusBuffer.push_back(data_field);
1228 }
1229 } while (extensionBit == 1);
1230
1231 // Current reassembling state
1232 if (m_reassemblingState == WAITING_S0_FULL)
1233 {
1234 NS_LOG_LOGIC("Reassembling State = 'WAITING_S0_FULL'");
1235 }
1236 else if (m_reassemblingState == WAITING_SI_SF)
1237 {
1238 NS_LOG_LOGIC("Reassembling State = 'WAITING_SI_SF'");
1239 }
1240 else
1241 {
1242 NS_LOG_LOGIC("Reassembling State = Unknown state");
1243 }
1244
1245 // Received framing Info
1246 NS_LOG_LOGIC("Framing Info = " << (uint16_t)framingInfo);
1247 NS_LOG_LOGIC("m_sdusBuffer = " << m_sdusBuffer.size());
1248
1249 // Reassemble the list of SDUs (when there is no losses)
1250 if (!expectedSnLost)
1251 {
1252 switch (m_reassemblingState)
1253 {
1254 case WAITING_S0_FULL:
1255 switch (framingInfo)
1256 {
1257 case (NrRlcAmHeader::FIRST_BYTE | NrRlcAmHeader::LAST_BYTE):
1258 m_reassemblingState = WAITING_S0_FULL;
1259
1263 for (auto it = m_sdusBuffer.begin(); it != m_sdusBuffer.end(); it++)
1264 {
1266 }
1267 m_sdusBuffer.clear();
1268 break;
1269
1270 case (NrRlcAmHeader::FIRST_BYTE | NrRlcAmHeader::NO_LAST_BYTE):
1271 m_reassemblingState = WAITING_SI_SF;
1272
1276 while (m_sdusBuffer.size() > 1)
1277 {
1278 m_rlcSapUser->ReceivePdcpPdu(m_sdusBuffer.front());
1279 m_sdusBuffer.pop_front();
1280 }
1281
1285 m_keepS0 = m_sdusBuffer.front();
1286 m_sdusBuffer.pop_front();
1287 break;
1288
1289 case (NrRlcAmHeader::NO_FIRST_BYTE | NrRlcAmHeader::LAST_BYTE):
1290 case (NrRlcAmHeader::NO_FIRST_BYTE | NrRlcAmHeader::NO_LAST_BYTE):
1291 default:
1295 NS_LOG_LOGIC(
1296 "INTERNAL ERROR: Transition not possible. FI = " << (uint32_t)framingInfo);
1297 break;
1298 }
1299 break;
1300
1301 case WAITING_SI_SF:
1302 switch (framingInfo)
1303 {
1304 case (NrRlcAmHeader::NO_FIRST_BYTE | NrRlcAmHeader::LAST_BYTE):
1305 m_reassemblingState = WAITING_S0_FULL;
1306
1310 m_keepS0->AddAtEnd(m_sdusBuffer.front());
1311 m_sdusBuffer.pop_front();
1312 m_rlcSapUser->ReceivePdcpPdu(m_keepS0);
1313
1317 while (!m_sdusBuffer.empty())
1318 {
1319 m_rlcSapUser->ReceivePdcpPdu(m_sdusBuffer.front());
1320 m_sdusBuffer.pop_front();
1321 }
1322 break;
1323
1324 case (NrRlcAmHeader::NO_FIRST_BYTE | NrRlcAmHeader::NO_LAST_BYTE):
1325 m_reassemblingState = WAITING_SI_SF;
1326
1330 if (m_sdusBuffer.size() == 1)
1331 {
1332 m_keepS0->AddAtEnd(m_sdusBuffer.front());
1333 m_sdusBuffer.pop_front();
1334 }
1335 else // m_sdusBuffer.size () > 1
1336 {
1340 m_keepS0->AddAtEnd(m_sdusBuffer.front());
1341 m_sdusBuffer.pop_front();
1342 m_rlcSapUser->ReceivePdcpPdu(m_keepS0);
1343
1347 while (m_sdusBuffer.size() > 1)
1348 {
1349 m_rlcSapUser->ReceivePdcpPdu(m_sdusBuffer.front());
1350 m_sdusBuffer.pop_front();
1351 }
1352
1356 m_keepS0 = m_sdusBuffer.front();
1357 m_sdusBuffer.pop_front();
1358 }
1359 break;
1360
1361 case (NrRlcAmHeader::FIRST_BYTE | NrRlcAmHeader::LAST_BYTE):
1362 case (NrRlcAmHeader::FIRST_BYTE | NrRlcAmHeader::NO_LAST_BYTE):
1363 default:
1367 NS_LOG_LOGIC(
1368 "INTERNAL ERROR: Transition not possible. FI = " << (uint32_t)framingInfo);
1369 break;
1370 }
1371 break;
1372
1373 default:
1374 NS_LOG_LOGIC(
1375 "INTERNAL ERROR: Wrong reassembling state = " << (uint32_t)m_reassemblingState);
1376 break;
1377 }
1378 }
1379 else // Reassemble the list of SDUs (when there are losses, i.e. the received SN is not the
1380 // expected one)
1381 {
1382 switch (m_reassemblingState)
1383 {
1384 case WAITING_S0_FULL:
1385 switch (framingInfo)
1386 {
1387 case (NrRlcAmHeader::FIRST_BYTE | NrRlcAmHeader::LAST_BYTE):
1388 m_reassemblingState = WAITING_S0_FULL;
1389
1393 for (auto it = m_sdusBuffer.begin(); it != m_sdusBuffer.end(); it++)
1394 {
1396 }
1397 m_sdusBuffer.clear();
1398 break;
1399
1400 case (NrRlcAmHeader::FIRST_BYTE | NrRlcAmHeader::NO_LAST_BYTE):
1401 m_reassemblingState = WAITING_SI_SF;
1402
1406 while (m_sdusBuffer.size() > 1)
1407 {
1408 m_rlcSapUser->ReceivePdcpPdu(m_sdusBuffer.front());
1409 m_sdusBuffer.pop_front();
1410 }
1411
1415 m_keepS0 = m_sdusBuffer.front();
1416 m_sdusBuffer.pop_front();
1417 break;
1418
1419 case (NrRlcAmHeader::NO_FIRST_BYTE | NrRlcAmHeader::LAST_BYTE):
1420 m_reassemblingState = WAITING_S0_FULL;
1421
1425 m_sdusBuffer.pop_front();
1426
1430 while (!m_sdusBuffer.empty())
1431 {
1432 m_rlcSapUser->ReceivePdcpPdu(m_sdusBuffer.front());
1433 m_sdusBuffer.pop_front();
1434 }
1435 break;
1436
1437 case (NrRlcAmHeader::NO_FIRST_BYTE | NrRlcAmHeader::NO_LAST_BYTE):
1438 if (m_sdusBuffer.size() == 1)
1439 {
1440 m_reassemblingState = WAITING_S0_FULL;
1441 }
1442 else
1443 {
1444 m_reassemblingState = WAITING_SI_SF;
1445 }
1446
1450 m_sdusBuffer.pop_front();
1451
1452 if (!m_sdusBuffer.empty())
1453 {
1457 while (m_sdusBuffer.size() > 1)
1458 {
1459 m_rlcSapUser->ReceivePdcpPdu(m_sdusBuffer.front());
1460 m_sdusBuffer.pop_front();
1461 }
1462
1466 m_keepS0 = m_sdusBuffer.front();
1467 m_sdusBuffer.pop_front();
1468 }
1469 break;
1470
1471 default:
1475 NS_LOG_LOGIC(
1476 "INTERNAL ERROR: Transition not possible. FI = " << (uint32_t)framingInfo);
1477 break;
1478 }
1479 break;
1480
1481 case WAITING_SI_SF:
1482 switch (framingInfo)
1483 {
1484 case (NrRlcAmHeader::FIRST_BYTE | NrRlcAmHeader::LAST_BYTE):
1485 m_reassemblingState = WAITING_S0_FULL;
1486
1490 m_keepS0 = nullptr;
1491
1495 while (!m_sdusBuffer.empty())
1496 {
1497 m_rlcSapUser->ReceivePdcpPdu(m_sdusBuffer.front());
1498 m_sdusBuffer.pop_front();
1499 }
1500 break;
1501
1502 case (NrRlcAmHeader::FIRST_BYTE | NrRlcAmHeader::NO_LAST_BYTE):
1503 m_reassemblingState = WAITING_SI_SF;
1504
1508 m_keepS0 = nullptr;
1509
1513 while (m_sdusBuffer.size() > 1)
1514 {
1515 m_rlcSapUser->ReceivePdcpPdu(m_sdusBuffer.front());
1516 m_sdusBuffer.pop_front();
1517 }
1518
1522 m_keepS0 = m_sdusBuffer.front();
1523 m_sdusBuffer.pop_front();
1524
1525 break;
1526
1527 case (NrRlcAmHeader::NO_FIRST_BYTE | NrRlcAmHeader::LAST_BYTE):
1528 m_reassemblingState = WAITING_S0_FULL;
1529
1533 m_keepS0 = nullptr;
1534
1538 m_sdusBuffer.pop_front();
1539
1543 while (!m_sdusBuffer.empty())
1544 {
1545 m_rlcSapUser->ReceivePdcpPdu(m_sdusBuffer.front());
1546 m_sdusBuffer.pop_front();
1547 }
1548 break;
1549
1550 case (NrRlcAmHeader::NO_FIRST_BYTE | NrRlcAmHeader::NO_LAST_BYTE):
1551 if (m_sdusBuffer.size() == 1)
1552 {
1553 m_reassemblingState = WAITING_S0_FULL;
1554 }
1555 else
1556 {
1557 m_reassemblingState = WAITING_SI_SF;
1558 }
1559
1563 m_keepS0 = nullptr;
1564
1568 m_sdusBuffer.pop_front();
1569
1570 if (!m_sdusBuffer.empty())
1571 {
1575 while (m_sdusBuffer.size() > 1)
1576 {
1577 m_rlcSapUser->ReceivePdcpPdu(m_sdusBuffer.front());
1578 m_sdusBuffer.pop_front();
1579 }
1580
1584 m_keepS0 = m_sdusBuffer.front();
1585 m_sdusBuffer.pop_front();
1586 }
1587 break;
1588
1589 default:
1593 NS_LOG_LOGIC(
1594 "INTERNAL ERROR: Transition not possible. FI = " << (uint32_t)framingInfo);
1595 break;
1596 }
1597 break;
1598
1599 default:
1600 NS_LOG_LOGIC(
1601 "INTERNAL ERROR: Wrong reassembling state = " << (uint32_t)m_reassemblingState);
1602 break;
1603 }
1604 }
1605}
1606
1607void
1608NrRlcAm::DoTransmitBufferStatusReport()
1609{
1610 NS_LOG_FUNCTION(this);
1611
1612 Time now = Simulator::Now();
1613
1614 NS_LOG_LOGIC("txonBufferSize = " << m_txonBufferSize);
1615 NS_LOG_LOGIC("retxBufferSize = " << m_retxBufferSize);
1616 NS_LOG_LOGIC("txedBufferSize = " << m_txedBufferSize);
1617 NS_LOG_LOGIC("VT(A) = " << m_vtA);
1618 NS_LOG_LOGIC("VT(S) = " << m_vtS);
1619
1620 // Transmission Queue HOL time
1621 Time txonQueueHolDelay(0);
1622 if (m_txonBufferSize > 0)
1623 {
1624 txonQueueHolDelay = now - m_txonBuffer.front().m_waitingSince;
1625 }
1626
1627 // Retransmission Queue HOL time
1628 Time retxQueueHolDelay;
1629 if (m_retxBufferSize > 0)
1630 {
1631 Time senderTimestamp;
1632 if (m_retxBuffer.at(m_vtA.GetValue()).m_pdu)
1633 {
1634 senderTimestamp = m_retxBuffer.at(m_vtA.GetValue()).m_waitingSince;
1635 }
1636 else
1637 {
1638 senderTimestamp = m_txedBuffer.at(m_vtA.GetValue()).m_waitingSince;
1639 }
1640 retxQueueHolDelay = now - senderTimestamp;
1641 }
1642 else
1643 {
1644 retxQueueHolDelay = Seconds(0);
1645 }
1646
1647 NrMacSapProvider::BufferStatusReportParameters r;
1648 r.rnti = m_rnti;
1649 r.lcid = m_lcid;
1650 r.txQueueSize = m_txonBufferSize;
1651 r.txQueueHolDelay = txonQueueHolDelay.GetMilliSeconds();
1652 r.retxQueueSize = m_retxBufferSize + m_txedBufferSize;
1653 r.retxQueueHolDelay = retxQueueHolDelay.GetMilliSeconds();
1654
1655 if (m_statusPduRequested && !m_statusProhibitTimer.IsPending())
1656 {
1657 r.statusPduSize = m_statusPduBufferSize;
1658 }
1659 else
1660 {
1661 r.statusPduSize = 0;
1662 }
1663
1664 if (r.txQueueSize != 0 || r.retxQueueSize != 0 || r.statusPduSize != 0)
1665 {
1666 NS_LOG_INFO("Send BufferStatusReport: " << r.txQueueSize << ", " << r.txQueueHolDelay
1667 << ", " << r.retxQueueSize << ", "
1668 << r.retxQueueHolDelay << ", " << r.statusPduSize);
1670 }
1671 else
1672 {
1673 NS_LOG_INFO("BufferStatusReport don't needed");
1674 }
1675}
1676
1677void
1678NrRlcAm::ExpireReorderingTimer()
1679{
1680 NS_LOG_FUNCTION(this);
1681 NS_LOG_LOGIC("Reordering Timer has expired");
1682
1683 // 5.1.3.2.4 Actions when t-Reordering expires
1684 // When t-Reordering expires, the receiving side of an AM RLC entity shall:
1685 // - update VR(MS) to the SN of the first AMD PDU with SN >= VR(X) for which not all byte
1686 // segments
1687 // have been received;
1688 // - if VR(H) > VR(MS):
1689 // - start t-Reordering;
1690 // - set VR(X) to VR(H).
1691
1692 m_vrMs = m_vrX;
1693 int firstVrMs = m_vrMs.GetValue();
1694 auto it = m_rxonBuffer.find(m_vrMs.GetValue());
1695 while (it != m_rxonBuffer.end() && it->second.m_pduComplete)
1696 {
1697 m_vrMs++;
1698 it = m_rxonBuffer.find(m_vrMs.GetValue());
1699
1700 NS_ASSERT_MSG(firstVrMs != m_vrMs.GetValue(), "Infinite loop in ExpireReorderingTimer");
1701 }
1702 NS_LOG_LOGIC("New VR(MS) = " << m_vrMs);
1703
1704 if (m_vrH > m_vrMs)
1705 {
1706 NS_LOG_LOGIC("Start reordering timer");
1707 m_reorderingTimer =
1708 Simulator::Schedule(m_reorderingTimerValue, &NrRlcAm::ExpireReorderingTimer, this);
1709 m_vrX = m_vrH;
1710 NS_LOG_LOGIC("New VR(MS) = " << m_vrMs);
1711 }
1712
1713 // Section 5.2.3 Status Reporting:
1714 // - The receiving side of an AM RLC entity shall trigger a
1715 // STATUS report when T_reordering expires.
1716 m_statusPduRequested = true;
1717}
1718
1719void
1720NrRlcAm::ExpirePollRetransmitTimer()
1721{
1722 NS_LOG_FUNCTION(this);
1723 NS_LOG_LOGIC("PollRetransmit Timer has expired");
1724
1725 NS_LOG_LOGIC("txonBufferSize = " << m_txonBufferSize);
1726 NS_LOG_LOGIC("retxBufferSize = " << m_retxBufferSize);
1727 NS_LOG_LOGIC("txedBufferSize = " << m_txedBufferSize);
1728 NS_LOG_LOGIC("statusPduRequested = " << m_statusPduRequested);
1729
1730 m_pollRetransmitTimerJustExpired = true;
1731
1732 // see section 5.2.2.3
1733 // note the difference between Rel 8 and Rel 11 specs; we follow Rel 11 here
1734 NS_ASSERT(m_vtS <= m_vtMs);
1735 if ((m_txonBufferSize == 0 && m_retxBufferSize == 0) || (m_vtS == m_vtMs))
1736 {
1737 NS_LOG_INFO("txonBuffer and retxBuffer empty. Move PDUs up to = " << m_vtS.GetValue() - 1
1738 << " to retxBuffer");
1739 for (nr::SequenceNumber10 sn = m_vtA; sn < m_vtS; sn++)
1740 {
1741 bool pduAvailable = (bool)m_txedBuffer.at(sn.GetValue()).m_pdu;
1742
1743 if (pduAvailable)
1744 {
1745 uint16_t snValue = sn.GetValue();
1746 NS_LOG_INFO("Move PDU " << sn << " from txedBuffer to retxBuffer");
1747 m_retxBuffer.at(snValue).m_pdu = m_txedBuffer.at(snValue).m_pdu->Copy();
1748 m_retxBuffer.at(snValue).m_retxCount = m_txedBuffer.at(snValue).m_retxCount;
1749 m_retxBuffer.at(snValue).m_waitingSince = m_txedBuffer.at(snValue).m_waitingSince;
1750 m_retxBufferSize += m_retxBuffer.at(snValue).m_pdu->GetSize();
1751
1752 m_txedBufferSize -= m_txedBuffer.at(snValue).m_pdu->GetSize();
1753 m_txedBuffer.at(snValue).m_pdu = nullptr;
1754 m_txedBuffer.at(snValue).m_retxCount = 0;
1755 m_txedBuffer.at(snValue).m_waitingSince = MilliSeconds(0);
1756 }
1757 }
1758 }
1759
1760 DoTransmitBufferStatusReport();
1761}
1762
1763void
1764NrRlcAm::ExpireStatusProhibitTimer()
1765{
1766 NS_LOG_FUNCTION(this);
1767}
1768
1769void
1770NrRlcAm::ExpireBsrTimer()
1771{
1772 NS_LOG_LOGIC("BSR Timer expires");
1773
1774 if (m_txonBufferSize + m_txedBufferSize + m_retxBufferSize > 0)
1775 {
1776 DoTransmitBufferStatusReport();
1777 m_bsrTimer = Simulator::Schedule(m_bsrTimerValue, &NrRlcAm::ExpireBsrTimer, this);
1778 }
1779}
1780
1781} // namespace ns3
virtual void TransmitPdu(TransmitPduParameters params)=0
virtual void BufferStatusReport(BufferStatusReportParameters params)=0
The packet header for the AM Radio Link Control (RLC) protocol packets.
void SetPollingBit(uint8_t pollingBit)
nr::SequenceNumber10 GetSequenceNumber() const
bool IsNackPresent(nr::SequenceNumber10 nack)
void SetResegmentationFlag(uint8_t resegFlag)
bool OneMoreNackWouldFitIn(uint16_t bytes)
void SetFramingInfo(uint8_t framingInfo)
bool IsControlPdu() const
nr::SequenceNumber10 GetAckSn() const
void SetDataPdu()
Set data PDU function.
void PushNack(int nack)
uint8_t GetPollingBit() const
void SetAckSn(nr::SequenceNumber10 ackSn)
static constexpr uint8_t STATUS_PDU
Control PDU type status.
void SetSegmentOffset(uint16_t segmentOffset)
void SetControlPdu(uint8_t controlPduType)
uint8_t GetResegmentationFlag() const
void SetSequenceNumber(nr::SequenceNumber10 sequenceNumber)
void PushLengthIndicator(uint16_t lengthIndicator)
void PushExtensionBit(uint8_t extensionBit)
void SetLastSegmentFlag(uint8_t lsf)
void DoNotifyHarqDeliveryFailure() override
Definition nr-rlc-am.cc:768
static TypeId GetTypeId()
Get the type ID.
Definition nr-rlc-am.cc:74
void DoNotifyTxOpportunity(NrMacSapUser::TxOpportunityParameters txOpParams) override
Definition nr-rlc-am.cc:186
void DoReceivePdu(NrMacSapUser::ReceivePduParameters rxPduParams) override
Definition nr-rlc-am.cc:774
void DoTransmitPdcpPdu(Ptr< Packet > p) override
Definition nr-rlc-am.cc:148
TracedCallback< Ptr< const Packet > > m_txDropTrace
Definition nr-rlc.h:176
TracedCallback< uint16_t, uint8_t, uint32_t, uint64_t > m_rxPdu
Definition nr-rlc.h:171
uint16_t m_rnti
RNTI.
Definition nr-rlc.h:159
NrRlcSapUser * m_rlcSapUser
RLC SAP user.
Definition nr-rlc.h:135
uint8_t m_lcid
LCID.
Definition nr-rlc.h:160
NrMacSapProvider * m_macSapProvider
MAC SAP provider.
Definition nr-rlc.h:157
TracedCallback< uint16_t, uint8_t, uint32_t > m_txPdu
Definition nr-rlc.h:167
virtual void ReceivePdcpPdu(Ptr< Packet > p)=0
This class implements a tag that carries the status of a RLC SDU for the fragmentation process Status...
void SetStatus(uint8_t status)
Time GetSenderTimestamp() const
Definition nr-rlc-tag.h:51
void SetSenderTimestamp(Time senderTimestamp)
Definition nr-rlc-tag.h:61
uint16_t GetValue() const
Extracts the numeric value of the sequence number.
void SetModulusBase(SequenceNumber10 modulusBase)
Set modulus base.