A Discrete-Event Network Simulator
API
lte-rlc-am.cc
Go to the documentation of this file.
1 /* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2011 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * Author: Manuel Requena <manuel.requena@cttc.es>
19  * Nicola Baldo <nbaldo@cttc.es>
20  */
21 
22 #include "ns3/simulator.h"
23 #include "ns3/log.h"
24 
25 #include "ns3/lte-rlc-am-header.h"
26 #include "ns3/lte-rlc-am.h"
27 #include "ns3/lte-rlc-sdu-status-tag.h"
28 #include "ns3/lte-rlc-tag.h"
29 
30 
31 namespace ns3 {
32 
33 NS_LOG_COMPONENT_DEFINE ("LteRlcAm");
34 
36 
37 
39 {
40  NS_LOG_FUNCTION (this);
41 
42  // Buffers
43  m_txonBufferSize = 0;
44  m_retxBuffer.resize (1024);
45  m_retxBufferSize = 0;
46  m_txedBuffer.resize (1024);
47  m_txedBufferSize = 0;
48 
49  m_statusPduRequested = false;
51 
52  // State variables: transmitting side
53  m_windowSize = 512;
54  m_vtA = 0;
56  m_vtS = 0;
57  m_pollSn = 0;
58 
59  // State variables: receiving side
60  m_vrR = 0;
62  m_vrX = 0;
63  m_vrMs = 0;
64  m_vrH = 0;
65 
66  // Counters
67  m_pduWithoutPoll = 0;
69 
70  // Configurable parameters
72  m_pollPdu = 1;
73  m_pollByte = 50;
74 
75  // SDU reassembling process
78 
80 }
81 
83 {
84  NS_LOG_FUNCTION (this);
85 }
86 
87 TypeId
89 {
90  static TypeId tid = TypeId ("ns3::LteRlcAm")
91  .SetParent<LteRlc> ()
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)",
96  TimeValue (MilliSeconds (20)),
98  MakeTimeChecker ())
99  .AddAttribute ("ReorderingTimer",
100  "Value of the t-Reordering timer (See section 7.3 of 3GPP TS 36.322)",
101  TimeValue (MilliSeconds (10)),
103  MakeTimeChecker ())
104  .AddAttribute ("StatusProhibitTimer",
105  "Value of the t-StatusProhibit timer (See section 7.3 of 3GPP TS 36.322)",
106  TimeValue (MilliSeconds (10)),
108  MakeTimeChecker ())
109  .AddAttribute ("ReportBufferStatusTimer",
110  "How much to wait to issue a new Report Buffer Status since the last time "
111  "a new SDU was received",
112  TimeValue (MilliSeconds (20)),
114  MakeTimeChecker ())
115  .AddAttribute ("TxOpportunityForRetxAlwaysBigEnough",
116  "If true, always pretend that the size of a TxOpportunity is big enough "
117  "for retransmission. If false (default and realistic behavior), no retx "
118  "is performed unless the corresponding TxOpportunity is big enough.",
119  BooleanValue (false),
122 
123  ;
124  return tid;
125 }
126 
127 void
129 {
130  NS_LOG_FUNCTION (this);
134  m_rbsTimer.Cancel ();
135 
136  m_txonBuffer.clear ();
137  m_txonBufferSize = 0;
138  m_txedBuffer.clear ();
139  m_txedBufferSize = 0;
140  m_retxBuffer.clear ();
141  m_retxBufferSize = 0;
142  m_rxonBuffer.clear ();
143  m_sdusBuffer.clear ();
144  m_keepS0 = 0;
145  m_controlPduBuffer = 0;
146 
148 }
149 
150 
155 void
157 {
158  NS_LOG_FUNCTION (this << m_rnti << (uint32_t) m_lcid << p->GetSize ());
159 
161  Time now = Simulator::Now ();
162  RlcTag timeTag (now);
163  p->AddPacketTag (timeTag);
164 
167  LteRlcSduStatusTag tag;
169  p->AddPacketTag (tag);
170 
171  NS_LOG_LOGIC ("Txon Buffer: New packet added");
172  m_txonBuffer.push_back (p);
173  m_txonBufferSize += p->GetSize ();
174  NS_LOG_LOGIC ("NumOfBuffers = " << m_txonBuffer.size() );
175  NS_LOG_LOGIC ("txonBufferSize = " << m_txonBufferSize);
176 
179  m_rbsTimer.Cancel ();
181 }
182 
183 
188 void
189 LteRlcAm::DoNotifyTxOpportunity (uint32_t bytes, uint8_t layer, uint8_t harqId)
190 {
191  NS_LOG_FUNCTION (this << m_rnti << (uint32_t) m_lcid << bytes);
192 
193  if (bytes < 4)
194  {
195  // Stingy MAC: In general, we need more bytes.
196  // There are a more restrictive test for each particular case
197  NS_LOG_LOGIC ("TxOpportunity (size = " << bytes << ") too small");
198  NS_ASSERT_MSG (false, "TxOpportunity (size = " << bytes << ") too small.\n"
199  << "Your MAC scheduler is assigned too few resource blocks.");
200  return;
201  }
202 
204  {
205  if (bytes < m_statusPduBufferSize)
206  {
207  // Stingy MAC: We need more bytes for the STATUS PDU
208  NS_LOG_LOGIC ("TxOpportunity (size = " << bytes << ") too small for the STATUS PDU (size = " << m_statusPduBufferSize << ")");
209  NS_ASSERT_MSG (false, "TxOpportunity (size = " << bytes << ") too small for the STATUS PDU (size = " << m_statusPduBufferSize << ")\n"
210  << "Your MAC scheduler is assigned too few resource blocks.");
211  return;
212  }
213 
214  NS_LOG_LOGIC ("Sending STATUS PDU");
215 
216  Ptr<Packet> packet = Create<Packet> ();
217  LteRlcAmHeader rlcAmHeader;
219 
220  NS_LOG_LOGIC ("Check for SNs to NACK from " << m_vrR.GetValue() << " to " << m_vrMs.GetValue());
221  SequenceNumber10 sn;
222  sn.SetModulusBase (m_vrR);
223  std::map<uint16_t, PduBuffer>::iterator pduIt;
224  for (sn = m_vrR; sn < m_vrMs; sn++)
225  {
226  NS_LOG_LOGIC ("SN = " << sn);
227  if (!rlcAmHeader.OneMoreNackWouldFitIn (bytes))
228  {
229  NS_LOG_LOGIC ("Can't fit more NACKs in STATUS PDU");
230  break;
231  }
232  pduIt = m_rxonBuffer.find (sn.GetValue ());
233  if (pduIt == m_rxonBuffer.end () || (!(pduIt->second.m_pduComplete)))
234  {
235  NS_LOG_LOGIC ("adding NACK_SN " << sn.GetValue ());
236  rlcAmHeader.PushNack (sn.GetValue ());
237  }
238  }
239  NS_LOG_LOGIC ("SN at end of NACK loop = " << sn);
240  // 3GPP TS 36.322 section 6.2.2.1.4 ACK SN
241  // find the SN of the next not received RLC Data PDU
242  // which is not reported as missing in the STATUS PDU.
243  pduIt = m_rxonBuffer.find (sn.GetValue ());
244  while ((sn < m_vrMs) && (pduIt != m_rxonBuffer.end ()) && (pduIt->second.m_pduComplete))
245  {
246  NS_LOG_LOGIC ("SN = " << sn << " < " << m_vrMs << " = " << (sn < m_vrMs));
247  sn++;
248  NS_LOG_LOGIC ("SN = " << sn);
249  pduIt = m_rxonBuffer.find (sn.GetValue ());
250  }
251 
252  NS_ASSERT_MSG (sn <= m_vrMs, "first SN not reported as missing = " << sn << ", VR(MS) = " << m_vrMs);
253  rlcAmHeader.SetAckSn (sn);
254 
255 
256  NS_LOG_LOGIC ("RLC header: " << rlcAmHeader);
257  packet->AddHeader (rlcAmHeader);
258 
259  // Sender timestamp
260  RlcTag rlcTag (Simulator::Now ());
261  NS_ASSERT_MSG (!packet->PeekPacketTag (rlcTag), "RlcTag is already present");
262  packet->AddPacketTag (rlcTag);
263  m_txPdu (m_rnti, m_lcid, packet->GetSize ());
264 
265  // Send RLC PDU to MAC layer
267  params.pdu = packet;
268  params.rnti = m_rnti;
269  params.lcid = m_lcid;
270  params.layer = layer;
271  params.harqProcessId = harqId;
272 
273  m_macSapProvider->TransmitPdu (params);
274 
275  m_statusPduRequested = false;
279  return;
280  }
281  else if ( m_retxBufferSize > 0 )
282  {
283  NS_LOG_LOGIC ("retxBufferSize = " << m_retxBufferSize);
284  NS_LOG_LOGIC ("Sending data from Retransmission Buffer");
285  NS_ASSERT (m_vtA < m_vtS);
286  SequenceNumber10 sn;
287  sn.SetModulusBase (m_vtA);
288  bool found = false;
289  for (sn = m_vtA; sn < m_vtS; sn++)
290  {
291  uint16_t seqNumberValue = sn.GetValue ();
292  NS_LOG_LOGIC ("SN = " << seqNumberValue << " m_pdu " << m_retxBuffer.at (seqNumberValue).m_pdu);
293 
294  if (m_retxBuffer.at (seqNumberValue).m_pdu != 0)
295  {
296 
297  Ptr<Packet> packet = m_retxBuffer.at (seqNumberValue).m_pdu->Copy ();
298 
299  if (( packet->GetSize () <= bytes )
301  {
302  found = true;
303  // According to 5.2.1, the data field is left as is, but we rebuild the header
304  LteRlcAmHeader rlcAmHeader;
305  packet->RemoveHeader (rlcAmHeader);
306  NS_LOG_LOGIC ("old AM RLC header: " << rlcAmHeader);
307 
308  // Calculate the Polling Bit (5.2.2.1)
310 
311  NS_LOG_LOGIC ("polling conditions: m_txonBuffer.empty=" << m_txonBuffer.empty ()
312  << " retxBufferSize=" << m_retxBufferSize
313  << " packet->GetSize ()=" << packet->GetSize ());
314  if (((m_txonBuffer.empty ()) && (m_retxBufferSize == packet->GetSize () + rlcAmHeader.GetSerializedSize ()))
315  || (m_vtS >= m_vtMs)
317  {
320  m_pduWithoutPoll = 0;
321  m_byteWithoutPoll = 0;
322 
323  m_pollSn = m_vtS - 1;
324  NS_LOG_LOGIC ("New POLL_SN = " << m_pollSn);
325 
327  {
328  NS_LOG_LOGIC ("Start PollRetransmit timer");
329 
332  }
333  else
334  {
335  NS_LOG_LOGIC ("Restart PollRetransmit timer");
336 
340  }
341  }
342 
343  packet->AddHeader (rlcAmHeader);
344  NS_LOG_LOGIC ("new AM RLC header: " << rlcAmHeader);
345 
346  // Sender timestamp
347  RlcTag rlcTag (Simulator::Now ());
348  NS_ASSERT_MSG (packet->PeekPacketTag (rlcTag), "RlcTag is missing");
349  packet->ReplacePacketTag (rlcTag);
350  m_txPdu (m_rnti, m_lcid, packet->GetSize ());
351 
352  // Send RLC PDU to MAC layer
354  params.pdu = packet;
355  params.rnti = m_rnti;
356  params.lcid = m_lcid;
357  params.layer = layer;
358  params.harqProcessId = harqId;
359 
360  m_macSapProvider->TransmitPdu (params);
361 
362  m_retxBuffer.at (seqNumberValue).m_retxCount++;
363  NS_LOG_INFO ("Incr RETX_COUNT for SN = " << seqNumberValue);
364  if (m_retxBuffer.at (seqNumberValue).m_retxCount >= m_maxRetxThreshold)
365  {
366  NS_LOG_INFO ("Max RETX_COUNT for SN = " << seqNumberValue);
367  }
368 
369  NS_LOG_INFO ("Move SN = " << seqNumberValue << " back to txedBuffer");
370  m_txedBuffer.at (seqNumberValue).m_pdu = m_retxBuffer.at (seqNumberValue).m_pdu->Copy ();
371  m_txedBuffer.at (seqNumberValue).m_retxCount = m_retxBuffer.at (seqNumberValue).m_retxCount;
372  m_txedBufferSize += m_txedBuffer.at (seqNumberValue).m_pdu->GetSize ();
373 
374  m_retxBufferSize -= m_retxBuffer.at (seqNumberValue).m_pdu->GetSize ();
375  m_retxBuffer.at (seqNumberValue).m_pdu = 0;
376  m_retxBuffer.at (seqNumberValue).m_retxCount = 0;
377 
378  NS_LOG_LOGIC ("retxBufferSize = " << m_retxBufferSize);
379 
380  return;
381  }
382  else
383  {
384  NS_LOG_LOGIC ("TxOpportunity (size = " << bytes << ") too small for retransmission of the packet (size = " << packet->GetSize () << ")");
385  NS_LOG_LOGIC ("Waiting for bigger TxOpportunity");
386  return;
387  }
388  }
389  }
390  NS_ASSERT_MSG (found, "m_retxBufferSize > 0, but no PDU considered for retx found");
391  }
392  else if ( m_txonBufferSize > 0 )
393  {
394  if (bytes < 7)
395  {
396  // Stingy MAC: We need more bytes for new DATA PDUs.
397  NS_LOG_LOGIC ("TxOpportunity (size = " << bytes << ") too small for DATA PDU");
398  NS_ASSERT_MSG (false, "TxOpportunity (size = " << bytes << ") too small for DATA PDU\n"
399  << "Your MAC scheduler is assigned too few resource blocks.");
400  return;
401  }
402 
403  NS_ASSERT (m_vtS <= m_vtMs);
404  if (m_vtS == m_vtMs)
405  {
406  NS_LOG_INFO ("cannot transmit new RLC PDU due to window stalling");
407  return;
408  }
409 
410  NS_LOG_LOGIC ("Sending data from Transmission Buffer");
411  }
412  else
413  {
414  NS_LOG_LOGIC ("No data pending");
415  return;
416  }
417 
418  //
419  //
420  // Build new PDU
421  //
422  //
423 
424  Ptr<Packet> packet = Create<Packet> ();
425  LteRlcAmHeader rlcAmHeader;
426  rlcAmHeader.SetDataPdu ();
427 
428  // Build Data field
429  uint32_t nextSegmentSize = bytes - 4;
430  uint32_t nextSegmentId = 1;
431  uint32_t dataFieldTotalSize = 0;
432  uint32_t dataFieldAddedSize = 0;
433  std::vector < Ptr<Packet> > dataField;
434 
435  // Remove the first packet from the transmission buffer.
436  // If only a segment of the packet is taken, then the remaining is given back later
437  if ( m_txonBuffer.size () == 0 )
438  {
439  NS_LOG_LOGIC ("No data pending");
440  return;
441  }
442 
443  NS_LOG_LOGIC ("SDUs in TxonBuffer = " << m_txonBuffer.size ());
444  NS_LOG_LOGIC ("First SDU buffer = " << *(m_txonBuffer.begin()));
445  NS_LOG_LOGIC ("First SDU size = " << (*(m_txonBuffer.begin()))->GetSize ());
446  NS_LOG_LOGIC ("Next segment size = " << nextSegmentSize);
447  NS_LOG_LOGIC ("Remove SDU from TxBuffer");
448  Ptr<Packet> firstSegment = (*(m_txonBuffer.begin ()))->Copy ();
449  m_txonBufferSize -= (*(m_txonBuffer.begin()))->GetSize ();
450  NS_LOG_LOGIC ("txBufferSize = " << m_txonBufferSize );
451  m_txonBuffer.erase (m_txonBuffer.begin ());
452 
453  while ( firstSegment && (firstSegment->GetSize () > 0) && (nextSegmentSize > 0) )
454  {
455  NS_LOG_LOGIC ("WHILE ( firstSegment && firstSegment->GetSize > 0 && nextSegmentSize > 0 )");
456  NS_LOG_LOGIC (" firstSegment size = " << firstSegment->GetSize ());
457  NS_LOG_LOGIC (" nextSegmentSize = " << nextSegmentSize);
458  if ( (firstSegment->GetSize () > nextSegmentSize) ||
459  // Segment larger than 2047 octets can only be mapped to the end of the Data field
460  (firstSegment->GetSize () > 2047)
461  )
462  {
463  // Take the minimum size, due to the 2047-bytes 3GPP exception
464  // This exception is due to the length of the LI field (just 11 bits)
465  uint32_t currSegmentSize = std::min (firstSegment->GetSize (), nextSegmentSize);
466 
467  NS_LOG_LOGIC (" IF ( firstSegment > nextSegmentSize ||");
468  NS_LOG_LOGIC (" firstSegment > 2047 )");
469 
470  // Segment txBuffer.FirstBuffer and
471  // Give back the remaining segment to the transmission buffer
472  Ptr<Packet> newSegment = firstSegment->CreateFragment (0, currSegmentSize);
473  NS_LOG_LOGIC (" newSegment size = " << newSegment->GetSize ());
474 
475  // Status tag of the new and remaining segments
476  // Note: This is the only place where a PDU is segmented and
477  // therefore its status can change
478  LteRlcSduStatusTag oldTag, newTag;
479  firstSegment->RemovePacketTag (oldTag);
480  newSegment->RemovePacketTag (newTag);
481  if (oldTag.GetStatus () == LteRlcSduStatusTag::FULL_SDU)
482  {
483  newTag.SetStatus (LteRlcSduStatusTag::FIRST_SEGMENT);
484  oldTag.SetStatus (LteRlcSduStatusTag::LAST_SEGMENT);
485  }
486  else if (oldTag.GetStatus () == LteRlcSduStatusTag::LAST_SEGMENT)
487  {
488  newTag.SetStatus (LteRlcSduStatusTag::MIDDLE_SEGMENT);
489  //oldTag.SetStatus (LteRlcSduStatusTag::LAST_SEGMENT);
490  }
491 
492  // Give back the remaining segment to the transmission buffer
493  firstSegment->RemoveAtStart (currSegmentSize);
494  NS_LOG_LOGIC (" firstSegment size (after RemoveAtStart) = " << firstSegment->GetSize ());
495  if (firstSegment->GetSize () > 0)
496  {
497  firstSegment->AddPacketTag (oldTag);
498 
499  m_txonBuffer.insert (m_txonBuffer.begin (), firstSegment);
500  m_txonBufferSize += (*(m_txonBuffer.begin()))->GetSize ();
501 
502  NS_LOG_LOGIC (" Txon buffer: Give back the remaining segment");
503  NS_LOG_LOGIC (" Txon buffers = " << m_txonBuffer.size ());
504  NS_LOG_LOGIC (" Front buffer size = " << (*(m_txonBuffer.begin()))->GetSize ());
505  NS_LOG_LOGIC (" txonBufferSize = " << m_txonBufferSize );
506  }
507  else
508  {
509  // Whole segment was taken, so adjust tag
510  if (newTag.GetStatus () == LteRlcSduStatusTag::FIRST_SEGMENT)
511  {
512  newTag.SetStatus (LteRlcSduStatusTag::FULL_SDU);
513  }
514  else if (newTag.GetStatus () == LteRlcSduStatusTag::MIDDLE_SEGMENT)
515  {
516  newTag.SetStatus (LteRlcSduStatusTag::LAST_SEGMENT);
517  }
518  }
519  // Segment is completely taken or
520  // the remaining segment is given back to the transmission buffer
521  firstSegment = 0;
522 
523  // Put status tag once it has been adjusted
524  newSegment->AddPacketTag (newTag);
525 
526  // Add Segment to Data field
527  dataFieldAddedSize = newSegment->GetSize ();
528  dataFieldTotalSize += dataFieldAddedSize;
529  dataField.push_back (newSegment);
530  newSegment = 0;
531 
532  // ExtensionBit (Next_Segment - 1) = 0
533  rlcAmHeader.PushExtensionBit (LteRlcAmHeader::DATA_FIELD_FOLLOWS);
534 
535  // no LengthIndicator for the last one
536 
537  nextSegmentSize -= dataFieldAddedSize;
538  nextSegmentId++;
539 
540  // nextSegmentSize MUST be zero (only if segment is smaller or equal to 2047)
541 
542  // (NO more segments) ? exit
543  // break;
544  }
545  else if ( (nextSegmentSize - firstSegment->GetSize () <= 2) || (m_txonBuffer.size () == 0) )
546  {
547  NS_LOG_LOGIC (" IF nextSegmentSize - firstSegment->GetSize () <= 2 || txonBuffer.size == 0");
548 
549  // Add txBuffer.FirstBuffer to DataField
550  dataFieldAddedSize = firstSegment->GetSize ();
551  dataFieldTotalSize += dataFieldAddedSize;
552  dataField.push_back (firstSegment);
553  firstSegment = 0;
554 
555  // ExtensionBit (Next_Segment - 1) = 0
556  rlcAmHeader.PushExtensionBit (LteRlcAmHeader::DATA_FIELD_FOLLOWS);
557 
558  // no LengthIndicator for the last one
559 
560  nextSegmentSize -= dataFieldAddedSize;
561  nextSegmentId++;
562 
563  NS_LOG_LOGIC (" SDUs in TxBuffer = " << m_txonBuffer.size ());
564  if (m_txonBuffer.size () > 0)
565  {
566  NS_LOG_LOGIC (" First SDU buffer = " << *(m_txonBuffer.begin()));
567  NS_LOG_LOGIC (" First SDU size = " << (*(m_txonBuffer.begin()))->GetSize ());
568  }
569  NS_LOG_LOGIC (" Next segment size = " << nextSegmentSize);
570 
571  // nextSegmentSize <= 2 (only if txBuffer is not empty)
572 
573  // (NO more segments) ? exit
574  // break;
575  }
576  else // (firstSegment->GetSize () < m_nextSegmentSize) && (m_txBuffer.size () > 0)
577  {
578  NS_LOG_LOGIC (" IF firstSegment < NextSegmentSize && txonBuffer.size > 0");
579  // Add txBuffer.FirstBuffer to DataField
580  dataFieldAddedSize = firstSegment->GetSize ();
581  dataFieldTotalSize += dataFieldAddedSize;
582  dataField.push_back (firstSegment);
583 
584  // ExtensionBit (Next_Segment - 1) = 1
585  rlcAmHeader.PushExtensionBit (LteRlcAmHeader::E_LI_FIELDS_FOLLOWS);
586 
587  // LengthIndicator (Next_Segment) = txBuffer.FirstBuffer.length()
588  rlcAmHeader.PushLengthIndicator (firstSegment->GetSize ());
589 
590  nextSegmentSize -= ((nextSegmentId % 2) ? (2) : (1)) + dataFieldAddedSize;
591  nextSegmentId++;
592 
593  NS_LOG_LOGIC (" SDUs in TxBuffer = " << m_txonBuffer.size ());
594  if (m_txonBuffer.size () > 0)
595  {
596  NS_LOG_LOGIC (" First SDU buffer = " << *(m_txonBuffer.begin()));
597  NS_LOG_LOGIC (" First SDU size = " << (*(m_txonBuffer.begin()))->GetSize ());
598  }
599  NS_LOG_LOGIC (" Next segment size = " << nextSegmentSize);
600  NS_LOG_LOGIC (" Remove SDU from TxBuffer");
601 
602  // (more segments)
603  firstSegment = (*(m_txonBuffer.begin ()))->Copy ();
604  m_txonBufferSize -= (*(m_txonBuffer.begin()))->GetSize ();
605  m_txonBuffer.erase (m_txonBuffer.begin ());
606  NS_LOG_LOGIC (" txBufferSize = " << m_txonBufferSize );
607  }
608 
609  }
610 
611  //
612  // Build RLC header
613  //
614 
615  rlcAmHeader.SetSequenceNumber ( m_vtS++ );
616  rlcAmHeader.SetResegmentationFlag (LteRlcAmHeader::PDU);
617  rlcAmHeader.SetLastSegmentFlag (LteRlcAmHeader::LAST_PDU_SEGMENT);
618  rlcAmHeader.SetSegmentOffset (0);
619 
620  NS_ASSERT_MSG(rlcAmHeader.GetSequenceNumber () < m_vtMs, "SN above TX window");
621  NS_ASSERT_MSG(rlcAmHeader.GetSequenceNumber () >= m_vtA, "SN below TX window");
622 
623  // Calculate FramingInfo flag according the status of the SDUs in the DataField
624  uint8_t framingInfo = 0;
625  std::vector< Ptr<Packet> >::iterator it;
626  it = dataField.begin ();
627 
628  // FIRST SEGMENT
629  LteRlcSduStatusTag tag;
630  NS_ASSERT_MSG ((*it)->PeekPacketTag (tag), "LteRlcSduStatusTag is missing");
631  (*it)->PeekPacketTag (tag);
632  if ( (tag.GetStatus () == LteRlcSduStatusTag::FULL_SDU) ||
634  )
635  {
636  framingInfo |= LteRlcAmHeader::FIRST_BYTE;
637  }
638  else
639  {
640  framingInfo |= LteRlcAmHeader::NO_FIRST_BYTE;
641  }
642 
643  // Add all SDUs (in DataField) to the Packet
644  while (it < dataField.end ())
645  {
646  NS_LOG_LOGIC ("Adding SDU/segment to packet, length = " << (*it)->GetSize ());
647 
648  NS_ASSERT_MSG ((*it)->PeekPacketTag (tag), "LteRlcSduStatusTag is missing");
649  (*it)->RemovePacketTag (tag);
650  if (packet->GetSize () > 0)
651  {
652  packet->AddAtEnd (*it);
653  }
654  else
655  {
656  packet = (*it);
657  }
658  it++;
659  }
660 
661  // LAST SEGMENT (Note: There could be only one and be the first one)
662  it--;
663  if ( (tag.GetStatus () == LteRlcSduStatusTag::FULL_SDU) ||
665  {
666  framingInfo |= LteRlcAmHeader::LAST_BYTE;
667  }
668  else
669  {
670  framingInfo |= LteRlcAmHeader::NO_LAST_BYTE;
671  }
672 
673  // Set the FramingInfo flag after the calculation
674  rlcAmHeader.SetFramingInfo (framingInfo);
675 
676 
677  // Calculate the Polling Bit (5.2.2.1)
678  rlcAmHeader.SetPollingBit (LteRlcAmHeader::STATUS_REPORT_NOT_REQUESTED);
679 
681  NS_LOG_LOGIC ("PDU_WITHOUT_POLL = " << m_pduWithoutPoll);
682  m_byteWithoutPoll += packet->GetSize ();
683  NS_LOG_LOGIC ("BYTE_WITHOUT_POLL = " << m_byteWithoutPoll);
684 
686  ( (m_txonBuffer.empty ()) && (m_retxBufferSize == 0) ) ||
687  (m_vtS >= m_vtMs)
689  )
690  {
692  rlcAmHeader.SetPollingBit (LteRlcAmHeader::STATUS_REPORT_IS_REQUESTED);
693  m_pduWithoutPoll = 0;
694  m_byteWithoutPoll = 0;
695 
696  m_pollSn = m_vtS - 1;
697  NS_LOG_LOGIC ("New POLL_SN = " << m_pollSn);
698 
700  {
701  NS_LOG_LOGIC ("Start PollRetransmit timer");
702 
705  }
706  else
707  {
708  NS_LOG_LOGIC ("Restart PollRetransmit timer");
709 
713  }
714  }
715 
716 
717  // Build RLC PDU with DataField and Header
718  NS_LOG_LOGIC ("AM RLC header: " << rlcAmHeader);
719  packet->AddHeader (rlcAmHeader);
720 
721  // Store new PDU into the Transmitted PDU Buffer
722  NS_LOG_LOGIC ("Put transmitted PDU in the txedBuffer");
723  m_txedBufferSize += packet->GetSize ();
724  m_txedBuffer.at ( rlcAmHeader.GetSequenceNumber ().GetValue () ).m_pdu = packet->Copy ();
725  m_txedBuffer.at ( rlcAmHeader.GetSequenceNumber ().GetValue () ).m_retxCount = 0;
726 
727  // Sender timestamp
728  RlcTag rlcTag (Simulator::Now ());
729  packet->ReplacePacketTag (rlcTag);
730  m_txPdu (m_rnti, m_lcid, packet->GetSize ());
731 
732  // Send RLC PDU to MAC layer
734  params.pdu = packet;
735  params.rnti = m_rnti;
736  params.lcid = m_lcid;
737  params.layer = layer;
738  params.harqProcessId = harqId;
739 
740  m_macSapProvider->TransmitPdu (params);
741 }
742 
743 void
745 {
746  NS_LOG_FUNCTION (this);
747 }
748 
749 
750 void
752 {
753  NS_LOG_FUNCTION (this << m_rnti << (uint32_t) m_lcid << p->GetSize ());
754 
755  // Receiver timestamp
756  RlcTag rlcTag;
757  Time delay;
758  NS_ASSERT_MSG (p->PeekPacketTag (rlcTag), "RlcTag is missing");
759  p->RemovePacketTag (rlcTag);
760  delay = Simulator::Now() - rlcTag.GetSenderTimestamp ();
761  m_rxPdu (m_rnti, m_lcid, p->GetSize (), delay.GetNanoSeconds ());
762 
763  // Get RLC header parameters
764  LteRlcAmHeader rlcAmHeader;
765  p->PeekHeader (rlcAmHeader);
766  NS_LOG_LOGIC ("RLC header: " << rlcAmHeader);
767 
768  if ( rlcAmHeader.IsDataPdu () )
769  {
770 
771  // 5.1.3.1 Transmit operations
772 
773  // 5.1.3.1.1 General
774  //
775  // The transmitting side of an AM RLC entity shall prioritize transmission of RLC control PDUs
776  // over RLC data PDUs. The transmitting side of an AM RLC entity shall prioritize retransmission
777  // of RLC data PDUs over transmission of new AMD PDUs.
778  //
779  // The transmitting side of an AM RLC entity shall maintain a transmitting window according to
780  // state variables VT(A) and VT(MS) as follows:
781  // - a SN falls within the transmitting window if VT(A) <= SN < VT(MS);
782  // - a SN falls outside of the transmitting window otherwise.
783  //
784  // The transmitting side of an AM RLC entity shall not deliver to lower layer any RLC data PDU
785  // whose SN falls outside of the transmitting window.
786  //
787  // When delivering a new AMD PDU to lower layer, the transmitting side of an AM RLC entity shall:
788  // - set the SN of the AMD PDU to VT(S), and then increment VT(S) by one.
789  //
790  // The transmitting side of an AM RLC entity can receive a positive acknowledgement (confirmation
791  // of successful reception by its peer AM RLC entity) for a RLC data PDU by the following:
792  // - STATUS PDU from its peer AM RLC entity.
793  //
794  // When receiving a positive acknowledgement for an AMD PDU with SN = VT(A), the transmitting
795  // side of an AM RLC entity shall:
796  // - set VT(A) equal to the SN of the AMD PDU with the smallest SN, whose SN falls within the
797  // range VT(A) <= SN <= VT(S) and for which a positive acknowledgment has not been received yet.
798  // - if positive acknowledgements have been received for all AMD PDUs associated with
799  // a transmitted RLC SDU:
800  // - send an indication to the upper layers of successful delivery of the RLC SDU.
801 
802 
803  // 5.1.3.2 Receive operations
804  //
805  // 5.1.3.2.1 General
806  //
807  // The receiving side of an AM RLC entity shall maintain a receiving window according to state
808  // variables VR(R) and VR(MR) as follows:
809  // - a SN falls within the receiving window if VR(R) <= SN < VR(MR);
810  // - a SN falls outside of the receiving window otherwise.
811  //
812  // When receiving a RLC data PDU from lower layer, the receiving side of an AM RLC entity shall:
813  // - either discard the received RLC data PDU or place it in the reception buffer (see sub clause 5.1.3.2.2);
814  // - if the received RLC data PDU was placed in the reception buffer:
815  // - update state variables, reassemble and deliver RLC SDUs to upper layer and start/stop t-Reordering as needed (see sub clause 5.1.3.2.3).
816  //
817  // When t-Reordering expires, the receiving side of an AM RLC entity shall:
818  // - update state variables and start t-Reordering as needed (see sub clause 5.1.3.2.4).
819 
820 
821  SequenceNumber10 seqNumber = rlcAmHeader.GetSequenceNumber ();
822  seqNumber.SetModulusBase (m_vrR);
823 
824  if ( rlcAmHeader.GetResegmentationFlag () == LteRlcAmHeader::SEGMENT )
825  {
826  NS_LOG_LOGIC ("PDU segment received ( SN = " << seqNumber << " )");
827  }
828  else if ( rlcAmHeader.GetResegmentationFlag () == LteRlcAmHeader::PDU )
829  {
830  NS_LOG_LOGIC ("PDU received ( SN = " << seqNumber << " )");
831  }
832  else
833  {
834  NS_ASSERT_MSG (false, "Neither a PDU segment nor a PDU received");
835  return ;
836  }
837 
838  // STATUS PDU is requested
839  if ( rlcAmHeader.GetPollingBit () == LteRlcAmHeader::STATUS_REPORT_IS_REQUESTED )
840  {
841  m_statusPduRequested = true;
843 
845  {
847  }
848  }
849 
850  // 5.1.3.2.2 Actions when a RLC data PDU is received from lower layer
851  //
852  // When a RLC data PDU is received from lower layer, where the RLC data PDU contains
853  // byte segment numbers y to z of an AMD PDU with SN = x, the receiving side of an AM RLC entity shall:
854  // - if x falls outside of the receiving window; or
855  // - if byte segment numbers y to z of the AMD PDU with SN = x have been received before:
856  // - discard the received RLC data PDU;
857  // - else:
858  // - place the received RLC data PDU in the reception buffer;
859  // - if some byte segments of the AMD PDU contained in the RLC data PDU have been received before:
860  // - discard the duplicate byte segments.
861 
862  NS_LOG_LOGIC ("VR(R) = " << m_vrR);
863  NS_LOG_LOGIC ("VR(MR) = " << m_vrMr);
864  NS_LOG_LOGIC ("VR(X) = " << m_vrX);
865  NS_LOG_LOGIC ("VR(MS) = " << m_vrMs);
866  NS_LOG_LOGIC ("VR(H) = " << m_vrH);
867 
868  // - if x falls outside of the receiving window; or
869  // - if byte segment numbers y to z of the AMD PDU with SN = x have been received before:
870  if ( ! IsInsideReceivingWindow (seqNumber) )
871  {
872  NS_LOG_LOGIC ("PDU discarded");
873  return;
874  }
875  else
876  {
877  // - if some byte segments of the AMD PDU contained in the RLC data PDU have been received before:
878  // - discard the duplicate byte segments.
879  // note: re-segmentation of AMD PDU is currently not supported,
880  // so we just check that the segment was not received before
881  std::map <uint16_t, PduBuffer>::iterator it = m_rxonBuffer.find (seqNumber.GetValue ());
882  if (it != m_rxonBuffer.end () )
883  {
884  NS_ASSERT (it->second.m_byteSegments.size () > 0);
885  NS_ASSERT_MSG (it->second.m_byteSegments.size () == 1, "re-segmentation not supported");
886  NS_LOG_LOGIC ("PDU segment already received, discarded");
887  }
888  else
889  {
890  NS_LOG_LOGIC ("Place PDU in the reception buffer ( SN = " << seqNumber << " )");
891  m_rxonBuffer[ seqNumber.GetValue () ].m_byteSegments.push_back (p);
892  m_rxonBuffer[ seqNumber.GetValue () ].m_pduComplete = true;
893  }
894 
895 
896  }
897 
898  // 5.1.3.2.3 Actions when a RLC data PDU is placed in the reception buffer
899  // When a RLC data PDU with SN = x is placed in the reception buffer,
900  // the receiving side of an AM RLC entity shall:
901 
902  // - if x >= VR(H)
903  // - update VR(H) to x+ 1;
904 
905  if ( seqNumber >= m_vrH )
906  {
907  m_vrH = seqNumber + 1;
908  NS_LOG_LOGIC ("New VR(H) = " << m_vrH);
909  }
910 
911  // - if all byte segments of the AMD PDU with SN = VR(MS) are received:
912  // - update VR(MS) to the SN of the first AMD PDU with SN > current VR(MS) for
913  // which not all byte segments have been received;
914 
915  std::map <uint16_t, PduBuffer>::iterator it = m_rxonBuffer.find (m_vrMs.GetValue ());
916  if ( it != m_rxonBuffer.end () &&
917  it->second.m_pduComplete )
918  {
919  int firstVrMs = m_vrMs.GetValue ();
920  while ( it != m_rxonBuffer.end () &&
921  it->second.m_pduComplete )
922  {
923  m_vrMs++;
924  it = m_rxonBuffer.find (m_vrMs.GetValue ());
925  NS_LOG_LOGIC ("Incr VR(MS) = " << m_vrMs);
926 
927  NS_ASSERT_MSG (firstVrMs != m_vrMs.GetValue (), "Infinite loop in RxonBuffer");
928  }
929  NS_LOG_LOGIC ("New VR(MS) = " << m_vrMs);
930  }
931 
932  // - if x = VR(R):
933  // - if all byte segments of the AMD PDU with SN = VR(R) are received:
934  // - update VR(R) to the SN of the first AMD PDU with SN > current VR(R) for which not all byte segments have been received;
935  // - update VR(MR) to the updated VR(R) + AM_Window_Size;
936  // - reassemble RLC SDUs from any byte segments of AMD PDUs with SN that falls outside of the receiving window and in-sequence byte segments of the AMD PDU with SN = VR(R), remove RLC headers when doing so and deliver the reassembled RLC SDUs to upper layer in sequence if not delivered before;
937 
938  if ( seqNumber == m_vrR )
939  {
940  std::map <uint16_t, PduBuffer>::iterator it = m_rxonBuffer.find (seqNumber.GetValue ());
941  if ( it != m_rxonBuffer.end () &&
942  it->second.m_pduComplete )
943  {
944  it = m_rxonBuffer.find (m_vrR.GetValue ());
945  int firstVrR = m_vrR.GetValue ();
946  while ( it != m_rxonBuffer.end () &&
947  it->second.m_pduComplete )
948  {
949  NS_LOG_LOGIC ("Reassemble and Deliver ( SN = " << m_vrR << " )");
950  NS_ASSERT_MSG (it->second.m_byteSegments.size () == 1,
951  "Too many segments. PDU Reassembly process didn't work");
952  ReassembleAndDeliver (it->second.m_byteSegments.front ());
953  m_rxonBuffer.erase (m_vrR.GetValue ());
954 
955  m_vrR++;
960  it = m_rxonBuffer.find (m_vrR.GetValue ());
961 
962  NS_ASSERT_MSG (firstVrR != m_vrR.GetValue (), "Infinite loop in RxonBuffer");
963  }
964  NS_LOG_LOGIC ("New VR(R) = " << m_vrR);
966 
967  NS_LOG_LOGIC ("New VR(MR) = " << m_vrMr);
968  }
969 
970  }
971 
972  // - if t-Reordering is running:
973  // - if VR(X) = VR(R); or
974  // - if VR(X) falls outside of the receiving window and VR(X) is not equal to VR(MR):
975  // - stop and reset t-Reordering;
976 
977  if ( m_reorderingTimer.IsRunning () )
978  {
979  NS_LOG_LOGIC ("Reordering timer is running");
980  if ( (m_vrX == m_vrR) ||
981  ( (! IsInsideReceivingWindow (m_vrX)) && (m_vrX != m_vrMr) )
982  )
983  {
985  NS_LOG_LOGIC ("Stop reordering timer");
987  }
988  }
989 
990  // - if t-Reordering is not running (includes the case t-Reordering is stopped due to actions above):
991  // - if VR (H) > VR(R):
992  // - start t-Reordering;
993  // - set VR(X) to VR(H).
994 
995  if ( ! m_reorderingTimer.IsRunning () )
996  {
997  NS_LOG_LOGIC ("Reordering timer is not running");
998  if ( m_vrH > m_vrR )
999  {
1000  NS_LOG_LOGIC ("Start reordering timer");
1003  m_vrX = m_vrH;
1004  NS_LOG_LOGIC ("New VR(X) = " << m_vrX);
1005  }
1006  }
1007  }
1008  else if ( rlcAmHeader.IsControlPdu () )
1009  {
1010  NS_LOG_INFO ("Control AM RLC PDU");
1011 
1012  SequenceNumber10 ackSn = rlcAmHeader.GetAckSn ();
1013  SequenceNumber10 sn;
1014 
1015  NS_LOG_INFO ("ackSn = " << ackSn);
1016  NS_LOG_INFO ("VT(A) = " << m_vtA);
1017  NS_LOG_INFO ("VT(S) = " << m_vtS);
1018  NS_LOG_LOGIC ("retxBufferSize = " << m_retxBufferSize);
1019  NS_LOG_LOGIC ("txedBufferSize = " << m_txedBufferSize);
1020 
1024  ackSn.SetModulusBase (m_vtA);
1025  sn.SetModulusBase (m_vtA);
1026 
1027  bool incrementVtA = true;
1028 
1029  for (sn = m_vtA; sn < ackSn && sn < m_vtS; sn++)
1030  {
1031  NS_LOG_LOGIC ("sn = " << sn);
1032 
1033  uint16_t seqNumberValue = sn.GetValue ();
1034 
1036  && (seqNumberValue == m_pollSn.GetValue ()))
1037  {
1039  }
1040 
1041  if (rlcAmHeader.IsNackPresent (sn))
1042  {
1043  NS_LOG_LOGIC ("sn " << sn << " is NACKed");
1044 
1045  incrementVtA = false;
1046 
1047  if (m_txedBuffer.at (seqNumberValue).m_pdu != 0)
1048  {
1049  NS_LOG_INFO ("Move SN = " << seqNumberValue << " to retxBuffer");
1050  m_retxBuffer.at (seqNumberValue).m_pdu = m_txedBuffer.at (seqNumberValue).m_pdu->Copy ();
1051  m_retxBuffer.at (seqNumberValue).m_retxCount = m_txedBuffer.at (seqNumberValue).m_retxCount;
1052  m_retxBufferSize += m_retxBuffer.at (seqNumberValue).m_pdu->GetSize ();
1053 
1054  m_txedBufferSize -= m_txedBuffer.at (seqNumberValue).m_pdu->GetSize ();
1055  m_txedBuffer.at (seqNumberValue).m_pdu = 0;
1056  m_txedBuffer.at (seqNumberValue).m_retxCount = 0;
1057  }
1058 
1059  NS_ASSERT (m_retxBuffer.at (seqNumberValue).m_pdu != 0);
1060 
1061  }
1062  else
1063  {
1064  NS_LOG_LOGIC ("sn " << sn << " is ACKed");
1065 
1066  if (m_txedBuffer.at (seqNumberValue).m_pdu)
1067  {
1068  NS_LOG_INFO ("ACKed SN = " << seqNumberValue << " from txedBuffer");
1069  // NS_LOG_INFO ("m_txedBuffer( " << m_vtA << " )->GetSize = " << m_txedBuffer.at (m_vtA.GetValue ())->GetSize ());
1070  m_txedBufferSize -= m_txedBuffer.at (seqNumberValue).m_pdu->GetSize ();
1071  m_txedBuffer.at (seqNumberValue).m_pdu = 0;
1072  NS_ASSERT (m_retxBuffer.at (seqNumberValue).m_pdu == 0);
1073  }
1074 
1075  if (m_retxBuffer.at (seqNumberValue).m_pdu)
1076  {
1077  NS_LOG_INFO ("ACKed SN = " << seqNumberValue << " from retxBuffer");
1078  m_retxBufferSize -= m_retxBuffer.at (seqNumberValue).m_pdu->GetSize ();
1079  m_retxBuffer.at (seqNumberValue).m_pdu = 0;
1080  m_retxBuffer.at (seqNumberValue).m_retxCount = 0;
1081  }
1082 
1083  }
1084 
1085  NS_LOG_LOGIC ("retxBufferSize = " << m_retxBufferSize);
1086  NS_LOG_LOGIC ("txedBufferSize = " << m_txedBufferSize);
1087 
1088  if (incrementVtA)
1089  {
1090  m_vtA++;
1092  NS_LOG_INFO ("New VT(A) = " << m_vtA);
1095  m_vtS.SetModulusBase (m_vtA);
1096  ackSn.SetModulusBase (m_vtA);
1097  sn.SetModulusBase (m_vtA);
1098  }
1099 
1100  } // loop over SN : VT(A) <= SN < ACK SN
1101 
1102  return;
1103 
1104  }
1105  else
1106  {
1107  NS_LOG_WARN ("Wrong AM RLC PDU type");
1108  return;
1109  }
1110 
1111 }
1112 
1113 
1114 bool
1116 {
1117  NS_LOG_FUNCTION (this << seqNumber);
1118  NS_LOG_LOGIC ("Receiving Window: " <<
1119  m_vrR << " <= " << seqNumber << " <= " << m_vrMr);
1120 
1123  seqNumber.SetModulusBase (m_vrR);
1124 
1125  if ( (m_vrR <= seqNumber) && (seqNumber < m_vrMr ) )
1126  {
1127  NS_LOG_LOGIC (seqNumber << " is INSIDE the receiving window");
1128  return true;
1129  }
1130  else
1131  {
1132  NS_LOG_LOGIC (seqNumber << " is OUTSIDE the receiving window");
1133  return false;
1134  }
1135 }
1136 
1137 
1138 void
1140 {
1141  LteRlcAmHeader rlcAmHeader;
1142  packet->RemoveHeader (rlcAmHeader);
1143  uint8_t framingInfo = rlcAmHeader.GetFramingInfo ();
1144  SequenceNumber10 currSeqNumber = rlcAmHeader.GetSequenceNumber ();
1145  bool expectedSnLost;
1146 
1147  if ( currSeqNumber != m_expectedSeqNumber )
1148  {
1149  expectedSnLost = true;
1150  NS_LOG_LOGIC ("There are losses. Expected SN = " << m_expectedSeqNumber << ". Current SN = " << currSeqNumber);
1151  m_expectedSeqNumber = currSeqNumber + 1;
1152  }
1153  else
1154  {
1155  expectedSnLost = false;
1156  NS_LOG_LOGIC ("No losses. Expected SN = " << m_expectedSeqNumber << ". Current SN = " << currSeqNumber);
1158  }
1159 
1160  // Build list of SDUs
1161  uint8_t extensionBit;
1162  uint16_t lengthIndicator;
1163  do
1164  {
1165  extensionBit = rlcAmHeader.PopExtensionBit ();
1166  NS_LOG_LOGIC ("E = " << (uint16_t)extensionBit);
1167 
1168  if ( extensionBit == 0 )
1169  {
1170  m_sdusBuffer.push_back (packet);
1171  }
1172  else // extensionBit == 1
1173  {
1174  lengthIndicator = rlcAmHeader.PopLengthIndicator ();
1175  NS_LOG_LOGIC ("LI = " << lengthIndicator);
1176 
1177  // Check if there is enough data in the packet
1178  if ( lengthIndicator >= packet->GetSize () )
1179  {
1180  NS_LOG_LOGIC ("INTERNAL ERROR: Not enough data in the packet (" << packet->GetSize () << "). Needed LI=" << lengthIndicator);
1182  }
1183 
1184  // Split packet in two fragments
1185  Ptr<Packet> data_field = packet->CreateFragment (0, lengthIndicator);
1186  packet->RemoveAtStart (lengthIndicator);
1187 
1188  m_sdusBuffer.push_back (data_field);
1189  }
1190  }
1191  while ( extensionBit == 1 );
1192 
1193  std::list < Ptr<Packet> >::iterator it;
1194 
1195  // Current reassembling state
1196  if (m_reassemblingState == WAITING_S0_FULL) NS_LOG_LOGIC ("Reassembling State = 'WAITING_S0_FULL'");
1197  else if (m_reassemblingState == WAITING_SI_SF) NS_LOG_LOGIC ("Reassembling State = 'WAITING_SI_SF'");
1198  else NS_LOG_LOGIC ("Reassembling State = Unknown state");
1199 
1200  // Received framing Info
1201  NS_LOG_LOGIC ("Framing Info = " << (uint16_t)framingInfo);
1202  NS_LOG_LOGIC ("m_sdusBuffer = " << m_sdusBuffer.size ());
1203 
1204  // Reassemble the list of SDUs (when there is no losses)
1205  if (!expectedSnLost)
1206  {
1207  switch (m_reassemblingState)
1208  {
1209  case WAITING_S0_FULL:
1210  switch (framingInfo)
1211  {
1214 
1218  for ( it = m_sdusBuffer.begin () ; it != m_sdusBuffer.end () ; it++ )
1219  {
1221  }
1222  m_sdusBuffer.clear ();
1223  break;
1224 
1227 
1231  while ( m_sdusBuffer.size () > 1 )
1232  {
1234  m_sdusBuffer.pop_front ();
1235  }
1236 
1240  m_keepS0 = m_sdusBuffer.front ();
1241  m_sdusBuffer.pop_front ();
1242  break;
1243 
1246  default:
1250  NS_LOG_LOGIC ("INTERNAL ERROR: Transition not possible. FI = " << (uint32_t) framingInfo);
1251  break;
1252  }
1253  break;
1254 
1255  case WAITING_SI_SF:
1256  switch (framingInfo)
1257  {
1260 
1264  m_keepS0->AddAtEnd (m_sdusBuffer.front ());
1265  m_sdusBuffer.pop_front ();
1267 
1271  while ( ! m_sdusBuffer.empty () )
1272  {
1274  m_sdusBuffer.pop_front ();
1275  }
1276  break;
1277 
1280 
1284  if ( m_sdusBuffer.size () == 1 )
1285  {
1286  m_keepS0->AddAtEnd (m_sdusBuffer.front ());
1287  m_sdusBuffer.pop_front ();
1288  }
1289  else // m_sdusBuffer.size () > 1
1290  {
1294  m_keepS0->AddAtEnd (m_sdusBuffer.front ());
1295  m_sdusBuffer.pop_front ();
1297 
1301  while ( m_sdusBuffer.size () > 1 )
1302  {
1304  m_sdusBuffer.pop_front ();
1305  }
1306 
1310  m_keepS0 = m_sdusBuffer.front ();
1311  m_sdusBuffer.pop_front ();
1312  }
1313  break;
1314 
1317  default:
1321  NS_LOG_LOGIC ("INTERNAL ERROR: Transition not possible. FI = " << (uint32_t) framingInfo);
1322  break;
1323  }
1324  break;
1325 
1326  default:
1327  NS_LOG_LOGIC ("INTERNAL ERROR: Wrong reassembling state = " << (uint32_t) m_reassemblingState);
1328  break;
1329  }
1330  }
1331  else // Reassemble the list of SDUs (when there are losses, i.e. the received SN is not the expected one)
1332  {
1333  switch (m_reassemblingState)
1334  {
1335  case WAITING_S0_FULL:
1336  switch (framingInfo)
1337  {
1340 
1344  for ( it = m_sdusBuffer.begin () ; it != m_sdusBuffer.end () ; it++ )
1345  {
1347  }
1348  m_sdusBuffer.clear ();
1349  break;
1350 
1353 
1357  while ( m_sdusBuffer.size () > 1 )
1358  {
1360  m_sdusBuffer.pop_front ();
1361  }
1362 
1366  m_keepS0 = m_sdusBuffer.front ();
1367  m_sdusBuffer.pop_front ();
1368  break;
1369 
1372 
1376  m_sdusBuffer.pop_front ();
1377 
1381  while ( ! m_sdusBuffer.empty () )
1382  {
1384  m_sdusBuffer.pop_front ();
1385  }
1386  break;
1387 
1389  if ( m_sdusBuffer.size () == 1 )
1390  {
1392  }
1393  else
1394  {
1396  }
1397 
1401  m_sdusBuffer.pop_front ();
1402 
1403  if ( m_sdusBuffer.size () > 0 )
1404  {
1408  while ( m_sdusBuffer.size () > 1 )
1409  {
1411  m_sdusBuffer.pop_front ();
1412  }
1413 
1417  m_keepS0 = m_sdusBuffer.front ();
1418  m_sdusBuffer.pop_front ();
1419  }
1420  break;
1421 
1422  default:
1426  NS_LOG_LOGIC ("INTERNAL ERROR: Transition not possible. FI = " << (uint32_t) framingInfo);
1427  break;
1428  }
1429  break;
1430 
1431  case WAITING_SI_SF:
1432  switch (framingInfo)
1433  {
1436 
1440  m_keepS0 = 0;
1441 
1445  while ( ! m_sdusBuffer.empty () )
1446  {
1448  m_sdusBuffer.pop_front ();
1449  }
1450  break;
1451 
1454 
1458  m_keepS0 = 0;
1459 
1463  while ( m_sdusBuffer.size () > 1 )
1464  {
1466  m_sdusBuffer.pop_front ();
1467  }
1468 
1472  m_keepS0 = m_sdusBuffer.front ();
1473  m_sdusBuffer.pop_front ();
1474 
1475  break;
1476 
1479 
1483  m_keepS0 = 0;
1484 
1488  m_sdusBuffer.pop_front ();
1489 
1493  while ( ! m_sdusBuffer.empty () )
1494  {
1496  m_sdusBuffer.pop_front ();
1497  }
1498  break;
1499 
1501  if ( m_sdusBuffer.size () == 1 )
1502  {
1504  }
1505  else
1506  {
1508  }
1509 
1513  m_keepS0 = 0;
1514 
1518  m_sdusBuffer.pop_front ();
1519 
1520  if ( m_sdusBuffer.size () > 0 )
1521  {
1525  while ( m_sdusBuffer.size () > 1 )
1526  {
1528  m_sdusBuffer.pop_front ();
1529  }
1530 
1534  m_keepS0 = m_sdusBuffer.front ();
1535  m_sdusBuffer.pop_front ();
1536  }
1537  break;
1538 
1539  default:
1543  NS_LOG_LOGIC ("INTERNAL ERROR: Transition not possible. FI = " << (uint32_t) framingInfo);
1544  break;
1545  }
1546  break;
1547 
1548  default:
1549  NS_LOG_LOGIC ("INTERNAL ERROR: Wrong reassembling state = " << (uint32_t) m_reassemblingState);
1550  break;
1551  }
1552  }
1553 
1554 }
1555 
1556 void
1558 {
1559  NS_LOG_FUNCTION (this);
1560 
1561  Time now = Simulator::Now ();
1562 
1563  NS_LOG_LOGIC ("txonBufferSize = " << m_txonBufferSize);
1564  NS_LOG_LOGIC ("retxBufferSize = " << m_retxBufferSize);
1565  NS_LOG_LOGIC ("txedBufferSize = " << m_txedBufferSize);
1566  NS_LOG_LOGIC ("VT(A) = " << m_vtA);
1567  NS_LOG_LOGIC ("VT(S) = " << m_vtS);
1568 
1569  // Transmission Queue HOL time
1570  Time txonQueueHolDelay (0);
1571  if ( m_txonBufferSize > 0 )
1572  {
1573  RlcTag txonQueueHolTimeTag;
1574  m_txonBuffer.front ()->PeekPacketTag (txonQueueHolTimeTag);
1575  txonQueueHolDelay = now - txonQueueHolTimeTag.GetSenderTimestamp ();
1576  }
1577 
1578  // Retransmission Queue HOL time
1579  Time retxQueueHolDelay;
1580  RlcTag retxQueueHolTimeTag;
1581  if ( m_retxBufferSize > 0 )
1582  {
1583  if (m_retxBuffer.at (m_vtA.GetValue ()).m_pdu != 0)
1584  {
1585  m_retxBuffer.at (m_vtA.GetValue ()).m_pdu->PeekPacketTag (retxQueueHolTimeTag);
1586  }
1587  else
1588  {
1589  m_txedBuffer.at (m_vtA.GetValue ()).m_pdu->PeekPacketTag (retxQueueHolTimeTag);
1590  }
1591  retxQueueHolDelay = now - retxQueueHolTimeTag.GetSenderTimestamp ();
1592  }
1593  else
1594  {
1595  retxQueueHolDelay = Seconds (0);
1596  }
1597 
1599  r.rnti = m_rnti;
1600  r.lcid = m_lcid;
1602  r.txQueueHolDelay = txonQueueHolDelay.GetMilliSeconds ();
1604  r.retxQueueHolDelay = retxQueueHolDelay.GetMilliSeconds ();
1605 
1607  {
1609  }
1610  else
1611  {
1612  r.statusPduSize = 0;
1613  }
1614 
1615  if ( r.txQueueSize != 0 || r.retxQueueSize != 0 || r.statusPduSize != 0 )
1616  {
1617  NS_LOG_INFO ("Send ReportBufferStatus: " << r.txQueueSize << ", " << r.txQueueHolDelay << ", "
1618  << r.retxQueueSize << ", " << r.retxQueueHolDelay << ", "
1619  << r.statusPduSize);
1621  }
1622  else
1623  {
1624  NS_LOG_INFO ("ReportBufferStatus don't needed");
1625  }
1626 }
1627 
1628 
1629 void
1631 {
1632  NS_LOG_FUNCTION (this);
1633  NS_LOG_LOGIC ("Reordering Timer has expired");
1634 
1635  // 5.1.3.2.4 Actions when t-Reordering expires
1636  // When t-Reordering expires, the receiving side of an AM RLC entity shall:
1637  // - update VR(MS) to the SN of the first AMD PDU with SN >= VR(X) for which not all byte segments
1638  // have been received;
1639  // - if VR(H) > VR(MS):
1640  // - start t-Reordering;
1641  // - set VR(X) to VR(H).
1642 
1643  m_vrMs = m_vrX;
1644  int firstVrMs = m_vrMs.GetValue ();
1645  std::map <uint16_t, PduBuffer>::iterator it = m_rxonBuffer.find (m_vrMs.GetValue ());
1646  while ( it != m_rxonBuffer.end () &&
1647  it->second.m_pduComplete )
1648  {
1649  m_vrMs++;
1650  it = m_rxonBuffer.find (m_vrMs.GetValue ());
1651 
1652  NS_ASSERT_MSG (firstVrMs != m_vrMs.GetValue (), "Infinite loop in ExpireReorderingTimer");
1653  }
1654  NS_LOG_LOGIC ("New VR(MS) = " << m_vrMs);
1655 
1656  if ( m_vrH > m_vrMs )
1657  {
1658  NS_LOG_LOGIC ("Start reordering timer");
1661  m_vrX = m_vrH;
1662  NS_LOG_LOGIC ("New VR(MS) = " << m_vrMs);
1663  }
1664 
1665  // Section 5.2.3 Status Reporting:
1666  // - The receiving side of an AM RLC entity shall trigger a
1667  // STATUS report when T_reordering expires.
1668  m_statusPduRequested = true;
1669 }
1670 
1671 void
1673 {
1674  NS_LOG_FUNCTION (this);
1675  NS_LOG_LOGIC ("PollRetransmit Timer has expired");
1676 
1677  NS_LOG_LOGIC ("txonBufferSize = " << m_txonBufferSize);
1678  NS_LOG_LOGIC ("retxBufferSize = " << m_retxBufferSize);
1679  NS_LOG_LOGIC ("txedBufferSize = " << m_txedBufferSize);
1680  NS_LOG_LOGIC ("statusPduRequested = " << m_statusPduRequested);
1681 
1683 
1684  // see section 5.2.2.3
1685  // note the difference between Rel 8 and Rel 11 specs; we follow Rel 11 here
1686  NS_ASSERT (m_vtS <= m_vtMs);
1687  if ((m_txonBufferSize == 0 && m_retxBufferSize == 0)
1688  || (m_vtS == m_vtMs))
1689  {
1690  NS_LOG_INFO ("txonBuffer and retxBuffer empty. Move PDUs up to = " << m_vtS.GetValue () - 1 << " to retxBuffer");
1691  uint16_t sn = 0;
1692  for ( sn = m_vtA.GetValue(); sn < m_vtS.GetValue (); sn++ )
1693  {
1694  bool pduAvailable = m_txedBuffer.at (sn).m_pdu != 0;
1695 
1696  if ( pduAvailable )
1697  {
1698  NS_LOG_INFO ("Move PDU " << sn << " from txedBuffer to retxBuffer");
1699  m_retxBuffer.at (sn).m_pdu = m_txedBuffer.at (sn).m_pdu->Copy ();
1700  m_retxBuffer.at (sn).m_retxCount = m_txedBuffer.at (sn).m_retxCount;
1701  m_retxBufferSize += m_retxBuffer.at (sn).m_pdu->GetSize ();
1702 
1703  m_txedBufferSize -= m_txedBuffer.at (sn).m_pdu->GetSize ();
1704  m_txedBuffer.at (sn).m_pdu = 0;
1705  m_txedBuffer.at (sn).m_retxCount = 0;
1706  }
1707  }
1708  }
1709 
1711 }
1712 
1713 
1714 void
1716 {
1717  NS_LOG_FUNCTION (this);
1718 }
1719 
1720 void
1722 {
1723  NS_LOG_LOGIC ("RBS Timer expires");
1724 
1726  {
1729  }
1730 }
1731 
1732 } // namespace ns3
uint8_t PopExtensionBit(void)
uint32_t RemoveHeader(Header &header)
Deserialize and remove the header from the internal buffer.
Definition: packet.cc:268
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:150
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:102
EventId m_statusProhibitTimer
Definition: lte-rlc-am.h:153
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by "...
uint32_t m_byteWithoutPoll
Definition: lte-rlc-am.h:139
AttributeValue implementation for Boolean.
Definition: boolean.h:34
uint16_t GetValue() const
Extracts the numeric value of the sequence number.
virtual void DoReceivePdu(Ptr< Packet > p)
Definition: lte-rlc-am.cc:751
EventId m_rbsTimer
Definition: lte-rlc-am.h:155
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:44
#define min(a, b)
Definition: 80211b.c:44
virtual void DoNotifyTxOpportunity(uint32_t bytes, uint8_t layer, uint8_t harqId)
MAC SAP.
Definition: lte-rlc-am.cc:189
uint32_t m_statusPduBufferSize
Definition: lte-rlc-am.h:100
Ptr< const AttributeAccessor > MakeBooleanAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method...
Definition: boolean.h:81
SequenceNumber10 m_vtS
Definition: lte-rlc-am.h:125
void DoReportBufferStatus()
Definition: lte-rlc-am.cc:1557
void AddPacketTag(const Tag &tag) const
Add a packet tag.
Definition: packet.cc:824
Tag to calculate the per-PDU delay from eNb RLC to UE RLC.
Definition: lte-rlc-tag.h:36
SequenceNumber10 m_vtMs
Definition: lte-rlc-am.h:124
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file...
Definition: assert.h:67
Time m_reorderingTimerValue
Definition: lte-rlc-am.h:152
SequenceNumber10 m_vrMs
Definition: lte-rlc-am.h:132
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:201
void SetPollingBit(uint8_t pollingBit)
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:903
Time m_pollRetransmitTimerValue
Definition: lte-rlc-am.h:150
SequenceNumber10 m_vrR
Definition: lte-rlc-am.h:129
uint32_t GetSize(void) const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:792
EventId m_reorderingTimer
Definition: lte-rlc-am.h:151
Time m_rbsTimerValue
Definition: lte-rlc-am.h:156
uint32_t retxQueueSize
the current size of the RLC retransmission queue in bytes
Definition: lte-mac-sap.h:72
#define NS_LOG_INFO(msg)
Use NS_LOG to output a message of level LOG_INFO.
Definition: log.h:244
uint16_t m_rnti
Definition: lte-rlc.h:144
bool IsRunning(void) const
This method is syntactic sugar for !IsExpired().
Definition: event-id.cc:65
bool IsInsideReceivingWindow(SequenceNumber10 seqNumber)
Definition: lte-rlc-am.cc:1115
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:90
uint8_t m_lcid
Definition: lte-rlc.h:145
uint16_t rnti
the C-RNTI identifying the UE
Definition: lte-mac-sap.h:68
EventId m_pollRetransmitTimer
Timers.
Definition: lte-rlc-am.h:149
void SetModulusBase(SequenceNumber10 modulusBase)
void ExpireRbsTimer(void)
Definition: lte-rlc-am.cc:1721
Parameters for LteMacSapProvider::ReportBufferStatus.
Definition: lte-mac-sap.h:66
Ptr< const AttributeChecker > MakeTimeChecker(const Time min, const Time max)
Helper to make a Time checker with bounded range.
Definition: time.cc:446
uint32_t m_txonBufferSize
Definition: lte-rlc-am.h:95
uint16_t txQueueHolDelay
the Head Of Line delay of the transmission queue
Definition: lte-mac-sap.h:71
Ptr< Packet > CreateFragment(uint32_t start, uint32_t length) const
Create a new packet which contains a fragment of the original packet.
Definition: packet.cc:228
void AddAtEnd(Ptr< const Packet > packet)
Concatenate the input packet at the end of the current packet.
Definition: packet.cc:313
bool PeekPacketTag(Tag &tag) const
Search a matching tag and call Tag::Deserialize if it is found.
Definition: packet.cc:846
SequenceNumber10 m_expectedSeqNumber
Expected Sequence Number.
Definition: lte-rlc-am.h:180
LteRlcSapUser * m_rlcSapUser
Definition: lte-rlc.h:133
void RemoveAtStart(uint32_t size)
Remove size bytes from the start of the current packet.
Definition: packet.cc:340
static EventId Schedule(Time const &delay, MEM mem_ptr, OBJ obj)
Schedule an event to expire after delay.
Definition: simulator.h:1238
std::map< uint16_t, PduBuffer > m_rxonBuffer
Definition: lte-rlc-am.h:110
AttributeValue implementation for Time.
Definition: nstime.h:957
uint8_t GetFramingInfo() const
virtual uint32_t GetSerializedSize(void) const
bool ReplacePacketTag(Tag &tag)
Replace the value of a packet tag.
Definition: packet.cc:838
uint16_t m_pollPdu
Definition: lte-rlc-am.h:162
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...
uint8_t GetStatus(void) const
Ptr< Packet > m_keepS0
Definition: lte-rlc-am.h:175
virtual void DoDispose()
Destructor implementation.
Definition: lte-rlc.cc:119
SequenceNumber10 m_pollSn
Definition: lte-rlc-am.h:126
LteMacSapProvider * m_macSapProvider
Definition: lte-rlc.h:142
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:252
Ptr< Packet > Copy(void) const
performs a COW copy of the packet.
Definition: packet.cc:122
uint32_t PeekHeader(Header &header) const
Deserialize but does not remove the header from the internal buffer.
Definition: packet.cc:278
void SetControlPdu(uint8_t controlPduType)
The packet header for the AM Radio Link Control (RLC) protocol packets.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
std::list< Ptr< Packet > > m_sdusBuffer
Definition: lte-rlc-am.h:117
uint16_t m_pollByte
Definition: lte-rlc-am.h:163
SequenceNumber10 m_vrH
Definition: lte-rlc-am.h:133
Ptr< const AttributeChecker > MakeBooleanChecker(void)
Definition: boolean.cc:121
bool m_pollRetransmitTimerJustExpired
Definition: lte-rlc-am.h:166
SequenceNumber10 m_vrMr
Definition: lte-rlc-am.h:130
Time GetSenderTimestamp(void) const
Get the instant when the RLC delivers the PDU to the MAC SAP provider.
Definition: lte-rlc-tag.h:60
Ptr< const AttributeAccessor > MakeTimeAccessor(T1 a1)
Create an AttributeAccessor for a class data member, or a lone class get functor or set method...
Definition: nstime.h:958
SequenceNumber10 m_vrX
Definition: lte-rlc-am.h:131
uint8_t lcid
the logical channel id corresponding to the sending RLC instance
Definition: lte-mac-sap.h:69
uint32_t m_pduWithoutPoll
Counters.
Definition: lte-rlc-am.h:138
uint32_t txQueueSize
the current size of the RLC transmission queue
Definition: lte-mac-sap.h:70
static Time Now(void)
Return the current simulation virtual time.
Definition: simulator.cc:224
uint32_t m_txedBufferSize
Definition: lte-rlc-am.h:97
Time m_statusProhibitTimerValue
Definition: lte-rlc-am.h:154
virtual void DoNotifyHarqDeliveryFailure()
Definition: lte-rlc-am.cc:744
uint16_t m_maxRetxThreshold
Configurable parameters.
Definition: lte-rlc-am.h:161
#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:90
int64_t GetNanoSeconds(void) const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:353
uint16_t statusPduSize
the current size of the pending STATUS RLC PDU message in bytes
Definition: lte-mac-sap.h:74
This class implements a tag that carries the status of a RLC SDU for the fragmentation process Status...
virtual void DoDispose()
Destructor implementation.
Definition: lte-rlc-am.cc:128
#define NS_LOG_WARN(msg)
Use NS_LOG to output a message of level LOG_WARN.
Definition: log.h:228
void ExpireStatusProhibitTimer(void)
method called when the T_status_prohibit timer expires
Definition: lte-rlc-am.cc:1715
void ExpirePollRetransmitTimer(void)
Definition: lte-rlc-am.cc:1672
SequenceNumber10 m_vtA
State variables.
Definition: lte-rlc-am.h:123
bool RemovePacketTag(Tag &tag)
Remove a packet tag.
Definition: packet.cc:831
uint16_t PopLengthIndicator(void)
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:895
std::vector< RetxPdu > m_retxBuffer
Buffer for PDUs considered for retransmission.
Definition: lte-rlc-am.h:93
void SetStatus(uint8_t status)
uint16_t retxQueueHolDelay
the Head Of Line delay of the retransmission queue
Definition: lte-mac-sap.h:73
void Cancel(void)
This method is syntactic sugar for the ns3::Simulator::Cancel method.
Definition: event-id.cc:53
virtual void ReportBufferStatus(ReportBufferStatusParameters params)=0
Report the RLC buffer status to the MAC.
std::vector< Ptr< Packet > > m_txonBuffer
Definition: lte-rlc-am.h:82
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:154
LTE RLC Acknowledged Mode (AM), see 3GPP TS 36.322.
Definition: lte-rlc-am.h:36
Ptr< Packet > m_controlPduBuffer
Definition: lte-rlc-am.h:112
void ReassembleAndDeliver(Ptr< Packet > packet)
Definition: lte-rlc-am.cc:1139
uint16_t m_windowSize
Constants.
Definition: lte-rlc-am.h:144
bool m_txOpportunityForRetxAlwaysBigEnough
Definition: lte-rlc-am.h:165
virtual void TransmitPdu(TransmitPduParameters params)=0
send an RLC PDU to the MAC for transmission.
ReassemblingState_t m_reassemblingState
Definition: lte-rlc-am.h:174
This abstract base class defines the API to interact with the Radio Link Control (LTE_RLC) in LTE...
Definition: lte-rlc.h:50
a unique identifier for an interface.
Definition: type-id.h:58
uint32_t m_retxBufferSize
Definition: lte-rlc-am.h:96
int64_t GetMilliSeconds(void) const
Get an approximation of the time stored in this instance in the indicated unit.
Definition: nstime.h:345
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:904
static TypeId GetTypeId(void)
Definition: lte-rlc-am.cc:88
bool m_statusPduRequested
Definition: lte-rlc-am.h:99
void ExpireReorderingTimer(void)
This method will schedule a timeout at WaitReplyTimeout interval in the future, unless a timer is alr...
Definition: lte-rlc-am.cc:1630
virtual void DoTransmitPdcpPdu(Ptr< Packet > p)
RLC SAP.
Definition: lte-rlc-am.cc:156
void AddHeader(const Header &header)
Add header to this packet.
Definition: packet.cc:257
virtual ~LteRlcAm()
Definition: lte-rlc-am.cc:82
SequenceNumber10 GetSequenceNumber() const
Parameters for LteMacSapProvider::TransmitPdu.
Definition: lte-mac-sap.h:45