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  // Send RLC PDU to MAC layer
261  params.pdu = packet;
262  params.rnti = m_rnti;
263  params.lcid = m_lcid;
264  params.layer = layer;
265  params.harqProcessId = harqId;
266 
267  m_macSapProvider->TransmitPdu (params);
268 
269  m_statusPduRequested = false;
273  return;
274  }
275  else if ( m_retxBufferSize > 0 )
276  {
277  NS_LOG_LOGIC ("retxBufferSize = " << m_retxBufferSize);
278  NS_LOG_LOGIC ("Sending data from Retransmission Buffer");
279  NS_ASSERT (m_vtA < m_vtS);
280  SequenceNumber10 sn;
281  sn.SetModulusBase (m_vtA);
282  bool found = false;
283  for (sn = m_vtA; sn < m_vtS; sn++)
284  {
285  uint16_t seqNumberValue = sn.GetValue ();
286  NS_LOG_LOGIC ("SN = " << seqNumberValue << " m_pdu " << m_retxBuffer.at (seqNumberValue).m_pdu);
287 
288  if (m_retxBuffer.at (seqNumberValue).m_pdu != 0)
289  {
290 
291  Ptr<Packet> packet = m_retxBuffer.at (seqNumberValue).m_pdu->Copy ();
292 
293  if (( packet->GetSize () <= bytes )
295  {
296  found = true;
297  // According to 5.2.1, the data field is left as is, but we rebuild the header
298  LteRlcAmHeader rlcAmHeader;
299  packet->RemoveHeader (rlcAmHeader);
300  NS_LOG_LOGIC ("old AM RLC header: " << rlcAmHeader);
301 
302  // Calculate the Polling Bit (5.2.2.1)
304 
305  NS_LOG_LOGIC ("polling conditions: m_txonBuffer.empty=" << m_txonBuffer.empty ()
306  << " retxBufferSize=" << m_retxBufferSize
307  << " packet->GetSize ()=" << packet->GetSize ());
308  if (((m_txonBuffer.empty ()) && (m_retxBufferSize == packet->GetSize () + rlcAmHeader.GetSerializedSize ()))
309  || (m_vtS >= m_vtMs)
311  {
314  m_pduWithoutPoll = 0;
315  m_byteWithoutPoll = 0;
316 
317  m_pollSn = m_vtS - 1;
318  NS_LOG_LOGIC ("New POLL_SN = " << m_pollSn);
319 
321  {
322  NS_LOG_LOGIC ("Start PollRetransmit timer");
323 
326  }
327  else
328  {
329  NS_LOG_LOGIC ("Restart PollRetransmit timer");
330 
334  }
335  }
336 
337  packet->AddHeader (rlcAmHeader);
338  NS_LOG_LOGIC ("new AM RLC header: " << rlcAmHeader);
339 
340  // Send RLC PDU to MAC layer
342  params.pdu = packet;
343  params.rnti = m_rnti;
344  params.lcid = m_lcid;
345  params.layer = layer;
346  params.harqProcessId = harqId;
347 
348  m_macSapProvider->TransmitPdu (params);
349 
350  m_retxBuffer.at (seqNumberValue).m_retxCount++;
351  NS_LOG_INFO ("Incr RETX_COUNT for SN = " << seqNumberValue);
352  if (m_retxBuffer.at (seqNumberValue).m_retxCount >= m_maxRetxThreshold)
353  {
354  NS_LOG_INFO ("Max RETX_COUNT for SN = " << seqNumberValue);
355  }
356 
357  NS_LOG_INFO ("Move SN = " << seqNumberValue << " back to txedBuffer");
358  m_txedBuffer.at (seqNumberValue).m_pdu = m_retxBuffer.at (seqNumberValue).m_pdu->Copy ();
359  m_txedBuffer.at (seqNumberValue).m_retxCount = m_retxBuffer.at (seqNumberValue).m_retxCount;
360  m_txedBufferSize += m_txedBuffer.at (seqNumberValue).m_pdu->GetSize ();
361 
362  m_retxBufferSize -= m_retxBuffer.at (seqNumberValue).m_pdu->GetSize ();
363  m_retxBuffer.at (seqNumberValue).m_pdu = 0;
364  m_retxBuffer.at (seqNumberValue).m_retxCount = 0;
365 
366  NS_LOG_LOGIC ("retxBufferSize = " << m_retxBufferSize);
367 
368  return;
369  }
370  else
371  {
372  NS_LOG_LOGIC ("TxOpportunity (size = " << bytes << ") too small for retransmission of the packet (size = " << packet->GetSize () << ")");
373  NS_LOG_LOGIC ("Waiting for bigger TxOpportunity");
374  return;
375  }
376  }
377  }
378  NS_ASSERT_MSG (found, "m_retxBufferSize > 0, but no PDU considered for retx found");
379  }
380  else if ( m_txonBufferSize > 0 )
381  {
382  if (bytes < 7)
383  {
384  // Stingy MAC: We need more bytes for new DATA PDUs.
385  NS_LOG_LOGIC ("TxOpportunity (size = " << bytes << ") too small for DATA PDU");
386  NS_ASSERT_MSG (false, "TxOpportunity (size = " << bytes << ") too small for DATA PDU\n"
387  << "Your MAC scheduler is assigned too few resource blocks.");
388  return;
389  }
390 
391  NS_ASSERT (m_vtS <= m_vtMs);
392  if (m_vtS == m_vtMs)
393  {
394  NS_LOG_INFO ("cannot transmit new RLC PDU due to window stalling");
395  return;
396  }
397 
398  NS_LOG_LOGIC ("Sending data from Transmission Buffer");
399  }
400  else
401  {
402  NS_LOG_LOGIC ("No data pending");
403  return;
404  }
405 
406  //
407  //
408  // Build new PDU
409  //
410  //
411 
412  Ptr<Packet> packet = Create<Packet> ();
413  LteRlcAmHeader rlcAmHeader;
414  rlcAmHeader.SetDataPdu ();
415 
416  // Build Data field
417  uint32_t nextSegmentSize = bytes - 4;
418  uint32_t nextSegmentId = 1;
419  uint32_t dataFieldTotalSize = 0;
420  uint32_t dataFieldAddedSize = 0;
421  std::vector < Ptr<Packet> > dataField;
422 
423  // Remove the first packet from the transmission buffer.
424  // If only a segment of the packet is taken, then the remaining is given back later
425  if ( m_txonBuffer.size () == 0 )
426  {
427  NS_LOG_LOGIC ("No data pending");
428  return;
429  }
430 
431  NS_LOG_LOGIC ("SDUs in TxonBuffer = " << m_txonBuffer.size ());
432  NS_LOG_LOGIC ("First SDU buffer = " << *(m_txonBuffer.begin()));
433  NS_LOG_LOGIC ("First SDU size = " << (*(m_txonBuffer.begin()))->GetSize ());
434  NS_LOG_LOGIC ("Next segment size = " << nextSegmentSize);
435  NS_LOG_LOGIC ("Remove SDU from TxBuffer");
436  Ptr<Packet> firstSegment = (*(m_txonBuffer.begin ()))->Copy ();
437  m_txonBufferSize -= (*(m_txonBuffer.begin()))->GetSize ();
438  NS_LOG_LOGIC ("txBufferSize = " << m_txonBufferSize );
439  m_txonBuffer.erase (m_txonBuffer.begin ());
440 
441  while ( firstSegment && (firstSegment->GetSize () > 0) && (nextSegmentSize > 0) )
442  {
443  NS_LOG_LOGIC ("WHILE ( firstSegment && firstSegment->GetSize > 0 && nextSegmentSize > 0 )");
444  NS_LOG_LOGIC (" firstSegment size = " << firstSegment->GetSize ());
445  NS_LOG_LOGIC (" nextSegmentSize = " << nextSegmentSize);
446  if ( (firstSegment->GetSize () > nextSegmentSize) ||
447  // Segment larger than 2047 octets can only be mapped to the end of the Data field
448  (firstSegment->GetSize () > 2047)
449  )
450  {
451  // Take the minimum size, due to the 2047-bytes 3GPP exception
452  // This exception is due to the length of the LI field (just 11 bits)
453  uint32_t currSegmentSize = std::min (firstSegment->GetSize (), nextSegmentSize);
454 
455  NS_LOG_LOGIC (" IF ( firstSegment > nextSegmentSize ||");
456  NS_LOG_LOGIC (" firstSegment > 2047 )");
457 
458  // Segment txBuffer.FirstBuffer and
459  // Give back the remaining segment to the transmission buffer
460  Ptr<Packet> newSegment = firstSegment->CreateFragment (0, currSegmentSize);
461  NS_LOG_LOGIC (" newSegment size = " << newSegment->GetSize ());
462 
463  // Status tag of the new and remaining segments
464  // Note: This is the only place where a PDU is segmented and
465  // therefore its status can change
466  LteRlcSduStatusTag oldTag, newTag;
467  firstSegment->RemovePacketTag (oldTag);
468  newSegment->RemovePacketTag (newTag);
469  if (oldTag.GetStatus () == LteRlcSduStatusTag::FULL_SDU)
470  {
471  newTag.SetStatus (LteRlcSduStatusTag::FIRST_SEGMENT);
472  oldTag.SetStatus (LteRlcSduStatusTag::LAST_SEGMENT);
473  }
474  else if (oldTag.GetStatus () == LteRlcSduStatusTag::LAST_SEGMENT)
475  {
476  newTag.SetStatus (LteRlcSduStatusTag::MIDDLE_SEGMENT);
477  //oldTag.SetStatus (LteRlcSduStatusTag::LAST_SEGMENT);
478  }
479 
480  // Give back the remaining segment to the transmission buffer
481  firstSegment->RemoveAtStart (currSegmentSize);
482  NS_LOG_LOGIC (" firstSegment size (after RemoveAtStart) = " << firstSegment->GetSize ());
483  if (firstSegment->GetSize () > 0)
484  {
485  firstSegment->AddPacketTag (oldTag);
486 
487  m_txonBuffer.insert (m_txonBuffer.begin (), firstSegment);
488  m_txonBufferSize += (*(m_txonBuffer.begin()))->GetSize ();
489 
490  NS_LOG_LOGIC (" Txon buffer: Give back the remaining segment");
491  NS_LOG_LOGIC (" Txon buffers = " << m_txonBuffer.size ());
492  NS_LOG_LOGIC (" Front buffer size = " << (*(m_txonBuffer.begin()))->GetSize ());
493  NS_LOG_LOGIC (" txonBufferSize = " << m_txonBufferSize );
494  }
495  else
496  {
497  // Whole segment was taken, so adjust tag
498  if (newTag.GetStatus () == LteRlcSduStatusTag::FIRST_SEGMENT)
499  {
500  newTag.SetStatus (LteRlcSduStatusTag::FULL_SDU);
501  }
502  else if (newTag.GetStatus () == LteRlcSduStatusTag::MIDDLE_SEGMENT)
503  {
504  newTag.SetStatus (LteRlcSduStatusTag::LAST_SEGMENT);
505  }
506  }
507  // Segment is completely taken or
508  // the remaining segment is given back to the transmission buffer
509  firstSegment = 0;
510 
511  // Put status tag once it has been adjusted
512  newSegment->AddPacketTag (newTag);
513 
514  // Add Segment to Data field
515  dataFieldAddedSize = newSegment->GetSize ();
516  dataFieldTotalSize += dataFieldAddedSize;
517  dataField.push_back (newSegment);
518  newSegment = 0;
519 
520  // ExtensionBit (Next_Segment - 1) = 0
521  rlcAmHeader.PushExtensionBit (LteRlcAmHeader::DATA_FIELD_FOLLOWS);
522 
523  // no LengthIndicator for the last one
524 
525  nextSegmentSize -= dataFieldAddedSize;
526  nextSegmentId++;
527 
528  // nextSegmentSize MUST be zero (only if segment is smaller or equal to 2047)
529 
530  // (NO more segments) ? exit
531  // break;
532  }
533  else if ( (nextSegmentSize - firstSegment->GetSize () <= 2) || (m_txonBuffer.size () == 0) )
534  {
535  NS_LOG_LOGIC (" IF nextSegmentSize - firstSegment->GetSize () <= 2 || txonBuffer.size == 0");
536 
537  // Add txBuffer.FirstBuffer to DataField
538  dataFieldAddedSize = firstSegment->GetSize ();
539  dataFieldTotalSize += dataFieldAddedSize;
540  dataField.push_back (firstSegment);
541  firstSegment = 0;
542 
543  // ExtensionBit (Next_Segment - 1) = 0
544  rlcAmHeader.PushExtensionBit (LteRlcAmHeader::DATA_FIELD_FOLLOWS);
545 
546  // no LengthIndicator for the last one
547 
548  nextSegmentSize -= dataFieldAddedSize;
549  nextSegmentId++;
550 
551  NS_LOG_LOGIC (" SDUs in TxBuffer = " << m_txonBuffer.size ());
552  if (m_txonBuffer.size () > 0)
553  {
554  NS_LOG_LOGIC (" First SDU buffer = " << *(m_txonBuffer.begin()));
555  NS_LOG_LOGIC (" First SDU size = " << (*(m_txonBuffer.begin()))->GetSize ());
556  }
557  NS_LOG_LOGIC (" Next segment size = " << nextSegmentSize);
558 
559  // nextSegmentSize <= 2 (only if txBuffer is not empty)
560 
561  // (NO more segments) ? exit
562  // break;
563  }
564  else // (firstSegment->GetSize () < m_nextSegmentSize) && (m_txBuffer.size () > 0)
565  {
566  NS_LOG_LOGIC (" IF firstSegment < NextSegmentSize && txonBuffer.size > 0");
567  // Add txBuffer.FirstBuffer to DataField
568  dataFieldAddedSize = firstSegment->GetSize ();
569  dataFieldTotalSize += dataFieldAddedSize;
570  dataField.push_back (firstSegment);
571 
572  // ExtensionBit (Next_Segment - 1) = 1
573  rlcAmHeader.PushExtensionBit (LteRlcAmHeader::E_LI_FIELDS_FOLLOWS);
574 
575  // LengthIndicator (Next_Segment) = txBuffer.FirstBuffer.length()
576  rlcAmHeader.PushLengthIndicator (firstSegment->GetSize ());
577 
578  nextSegmentSize -= ((nextSegmentId % 2) ? (2) : (1)) + dataFieldAddedSize;
579  nextSegmentId++;
580 
581  NS_LOG_LOGIC (" SDUs in TxBuffer = " << m_txonBuffer.size ());
582  if (m_txonBuffer.size () > 0)
583  {
584  NS_LOG_LOGIC (" First SDU buffer = " << *(m_txonBuffer.begin()));
585  NS_LOG_LOGIC (" First SDU size = " << (*(m_txonBuffer.begin()))->GetSize ());
586  }
587  NS_LOG_LOGIC (" Next segment size = " << nextSegmentSize);
588  NS_LOG_LOGIC (" Remove SDU from TxBuffer");
589 
590  // (more segments)
591  firstSegment = (*(m_txonBuffer.begin ()))->Copy ();
592  m_txonBufferSize -= (*(m_txonBuffer.begin()))->GetSize ();
593  m_txonBuffer.erase (m_txonBuffer.begin ());
594  NS_LOG_LOGIC (" txBufferSize = " << m_txonBufferSize );
595  }
596 
597  }
598 
599  //
600  // Build RLC header
601  //
602 
603  rlcAmHeader.SetSequenceNumber ( m_vtS++ );
604  rlcAmHeader.SetResegmentationFlag (LteRlcAmHeader::PDU);
605  rlcAmHeader.SetLastSegmentFlag (LteRlcAmHeader::LAST_PDU_SEGMENT);
606  rlcAmHeader.SetSegmentOffset (0);
607 
608  NS_ASSERT_MSG(rlcAmHeader.GetSequenceNumber () < m_vtMs, "SN above TX window");
609  NS_ASSERT_MSG(rlcAmHeader.GetSequenceNumber () >= m_vtA, "SN below TX window");
610 
611  // Calculate FramingInfo flag according the status of the SDUs in the DataField
612  uint8_t framingInfo = 0;
613  std::vector< Ptr<Packet> >::iterator it;
614  it = dataField.begin ();
615 
616  // FIRST SEGMENT
617  LteRlcSduStatusTag tag;
618  (*it)->RemovePacketTag (tag);
619  if ( (tag.GetStatus () == LteRlcSduStatusTag::FULL_SDU) ||
621  )
622  {
623  framingInfo |= LteRlcAmHeader::FIRST_BYTE;
624  }
625  else
626  {
627  framingInfo |= LteRlcAmHeader::NO_FIRST_BYTE;
628  }
629  (*it)->AddPacketTag (tag);
630 
631  // Add all SDUs (in DataField) to the Packet
632  while (it < dataField.end ())
633  {
634  NS_LOG_LOGIC ("Adding SDU/segment to packet, length = " << (*it)->GetSize ());
635 
636  packet->AddAtEnd (*it);
637  it++;
638  }
639 
640  // LAST SEGMENT (Note: There could be only one and be the first one)
641  it--;
642  (*it)->RemovePacketTag (tag);
643  if ( (tag.GetStatus () == LteRlcSduStatusTag::FULL_SDU) ||
645  {
646  framingInfo |= LteRlcAmHeader::LAST_BYTE;
647  }
648  else
649  {
650  framingInfo |= LteRlcAmHeader::NO_LAST_BYTE;
651  }
652  (*it)->AddPacketTag (tag);
653 
654  // Set the FramingInfo flag after the calculation
655  rlcAmHeader.SetFramingInfo (framingInfo);
656 
657 
658  // Calculate the Polling Bit (5.2.2.1)
659  rlcAmHeader.SetPollingBit (LteRlcAmHeader::STATUS_REPORT_NOT_REQUESTED);
660 
662  NS_LOG_LOGIC ("PDU_WITHOUT_POLL = " << m_pduWithoutPoll);
663  m_byteWithoutPoll += packet->GetSize ();
664  NS_LOG_LOGIC ("BYTE_WITHOUT_POLL = " << m_byteWithoutPoll);
665 
667  ( (m_txonBuffer.empty ()) && (m_retxBufferSize == 0) ) ||
668  (m_vtS >= m_vtMs)
670  )
671  {
673  rlcAmHeader.SetPollingBit (LteRlcAmHeader::STATUS_REPORT_IS_REQUESTED);
674  m_pduWithoutPoll = 0;
675  m_byteWithoutPoll = 0;
676 
677  m_pollSn = m_vtS - 1;
678  NS_LOG_LOGIC ("New POLL_SN = " << m_pollSn);
679 
681  {
682  NS_LOG_LOGIC ("Start PollRetransmit timer");
683 
686  }
687  else
688  {
689  NS_LOG_LOGIC ("Restart PollRetransmit timer");
690 
694  }
695  }
696 
697 
698  // Build RLC PDU with DataField and Header
699  NS_LOG_LOGIC ("AM RLC header: " << rlcAmHeader);
700  packet->AddHeader (rlcAmHeader);
701 
702  // Store new PDU into the Transmitted PDU Buffer
703  NS_LOG_LOGIC ("Put transmitted PDU in the txedBuffer");
704  m_txedBufferSize += packet->GetSize ();
705  m_txedBuffer.at ( rlcAmHeader.GetSequenceNumber ().GetValue () ).m_pdu = packet->Copy ();
706  m_txedBuffer.at ( rlcAmHeader.GetSequenceNumber ().GetValue () ).m_retxCount = 0;
707 
708  // Sender timestamp
709  RlcTag rlcTag (Simulator::Now ());
710  packet->AddByteTag (rlcTag);
711  m_txPdu (m_rnti, m_lcid, packet->GetSize ());
712 
713  // Send RLC PDU to MAC layer
715  params.pdu = packet;
716  params.rnti = m_rnti;
717  params.lcid = m_lcid;
718  params.layer = layer;
719  params.harqProcessId = harqId;
720 
721  m_macSapProvider->TransmitPdu (params);
722 }
723 
724 void
726 {
727  NS_LOG_FUNCTION (this);
728 }
729 
730 
731 void
733 {
734  NS_LOG_FUNCTION (this << m_rnti << (uint32_t) m_lcid << p->GetSize ());
735 
736  // Receiver timestamp
737  RlcTag rlcTag;
738  Time delay;
739  if (p->FindFirstMatchingByteTag (rlcTag))
740  {
741  delay = Simulator::Now() - rlcTag.GetSenderTimestamp ();
742  }
743  m_rxPdu (m_rnti, m_lcid, p->GetSize (), delay.GetNanoSeconds ());
744 
745  // Get RLC header parameters
746  LteRlcAmHeader rlcAmHeader;
747  p->PeekHeader (rlcAmHeader);
748  NS_LOG_LOGIC ("RLC header: " << rlcAmHeader);
749 
750  if ( rlcAmHeader.IsDataPdu () )
751  {
752 
753  // 5.1.3.1 Transmit operations
754 
755  // 5.1.3.1.1 General
756  //
757  // The transmitting side of an AM RLC entity shall prioritize transmission of RLC control PDUs
758  // over RLC data PDUs. The transmitting side of an AM RLC entity shall prioritize retransmission
759  // of RLC data PDUs over transmission of new AMD PDUs.
760  //
761  // The transmitting side of an AM RLC entity shall maintain a transmitting window according to
762  // state variables VT(A) and VT(MS) as follows:
763  // - a SN falls within the transmitting window if VT(A) <= SN < VT(MS);
764  // - a SN falls outside of the transmitting window otherwise.
765  //
766  // The transmitting side of an AM RLC entity shall not deliver to lower layer any RLC data PDU
767  // whose SN falls outside of the transmitting window.
768  //
769  // When delivering a new AMD PDU to lower layer, the transmitting side of an AM RLC entity shall:
770  // - set the SN of the AMD PDU to VT(S), and then increment VT(S) by one.
771  //
772  // The transmitting side of an AM RLC entity can receive a positive acknowledgement (confirmation
773  // of successful reception by its peer AM RLC entity) for a RLC data PDU by the following:
774  // - STATUS PDU from its peer AM RLC entity.
775  //
776  // When receiving a positive acknowledgement for an AMD PDU with SN = VT(A), the transmitting
777  // side of an AM RLC entity shall:
778  // - set VT(A) equal to the SN of the AMD PDU with the smallest SN, whose SN falls within the
779  // range VT(A) <= SN <= VT(S) and for which a positive acknowledgment has not been received yet.
780  // - if positive acknowledgements have been received for all AMD PDUs associated with
781  // a transmitted RLC SDU:
782  // - send an indication to the upper layers of successful delivery of the RLC SDU.
783 
784 
785  // 5.1.3.2 Receive operations
786  //
787  // 5.1.3.2.1 General
788  //
789  // The receiving side of an AM RLC entity shall maintain a receiving window according to state
790  // variables VR(R) and VR(MR) as follows:
791  // - a SN falls within the receiving window if VR(R) <= SN < VR(MR);
792  // - a SN falls outside of the receiving window otherwise.
793  //
794  // When receiving a RLC data PDU from lower layer, the receiving side of an AM RLC entity shall:
795  // - either discard the received RLC data PDU or place it in the reception buffer (see sub clause 5.1.3.2.2);
796  // - if the received RLC data PDU was placed in the reception buffer:
797  // - 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).
798  //
799  // When t-Reordering expires, the receiving side of an AM RLC entity shall:
800  // - update state variables and start t-Reordering as needed (see sub clause 5.1.3.2.4).
801 
802 
803  SequenceNumber10 seqNumber = rlcAmHeader.GetSequenceNumber ();
804  seqNumber.SetModulusBase (m_vrR);
805 
806  if ( rlcAmHeader.GetResegmentationFlag () == LteRlcAmHeader::SEGMENT )
807  {
808  NS_LOG_LOGIC ("PDU segment received ( SN = " << seqNumber << " )");
809  }
810  else if ( rlcAmHeader.GetResegmentationFlag () == LteRlcAmHeader::PDU )
811  {
812  NS_LOG_LOGIC ("PDU received ( SN = " << seqNumber << " )");
813  }
814  else
815  {
816  NS_ASSERT_MSG (false, "Neither a PDU segment nor a PDU received");
817  return ;
818  }
819 
820  // STATUS PDU is requested
821  if ( rlcAmHeader.GetPollingBit () == LteRlcAmHeader::STATUS_REPORT_IS_REQUESTED )
822  {
823  m_statusPduRequested = true;
825 
827  {
829  }
830  }
831 
832  // 5.1.3.2.2 Actions when a RLC data PDU is received from lower layer
833  //
834  // When a RLC data PDU is received from lower layer, where the RLC data PDU contains
835  // byte segment numbers y to z of an AMD PDU with SN = x, the receiving side of an AM RLC entity shall:
836  // - if x falls outside of the receiving window; or
837  // - if byte segment numbers y to z of the AMD PDU with SN = x have been received before:
838  // - discard the received RLC data PDU;
839  // - else:
840  // - place the received RLC data PDU in the reception buffer;
841  // - if some byte segments of the AMD PDU contained in the RLC data PDU have been received before:
842  // - discard the duplicate byte segments.
843 
844  NS_LOG_LOGIC ("VR(R) = " << m_vrR);
845  NS_LOG_LOGIC ("VR(MR) = " << m_vrMr);
846  NS_LOG_LOGIC ("VR(X) = " << m_vrX);
847  NS_LOG_LOGIC ("VR(MS) = " << m_vrMs);
848  NS_LOG_LOGIC ("VR(H) = " << m_vrH);
849 
850  // - if x falls outside of the receiving window; or
851  // - if byte segment numbers y to z of the AMD PDU with SN = x have been received before:
852  if ( ! IsInsideReceivingWindow (seqNumber) )
853  {
854  NS_LOG_LOGIC ("PDU discarded");
855  return;
856  }
857  else
858  {
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  // note: re-segmentation of AMD PDU is currently not supported,
862  // so we just check that the segment was not received before
863  std::map <uint16_t, PduBuffer>::iterator it = m_rxonBuffer.find (seqNumber.GetValue ());
864  if (it != m_rxonBuffer.end () )
865  {
866  NS_ASSERT (it->second.m_byteSegments.size () > 0);
867  NS_ASSERT_MSG (it->second.m_byteSegments.size () == 1, "re-segmentation not supported");
868  NS_LOG_LOGIC ("PDU segment already received, discarded");
869  }
870  else
871  {
872  NS_LOG_LOGIC ("Place PDU in the reception buffer ( SN = " << seqNumber << " )");
873  m_rxonBuffer[ seqNumber.GetValue () ].m_byteSegments.push_back (p);
874  m_rxonBuffer[ seqNumber.GetValue () ].m_pduComplete = true;
875  }
876 
877 
878  }
879 
880  // 5.1.3.2.3 Actions when a RLC data PDU is placed in the reception buffer
881  // When a RLC data PDU with SN = x is placed in the reception buffer,
882  // the receiving side of an AM RLC entity shall:
883 
884  // - if x >= VR(H)
885  // - update VR(H) to x+ 1;
886 
887  if ( seqNumber >= m_vrH )
888  {
889  m_vrH = seqNumber + 1;
890  NS_LOG_LOGIC ("New VR(H) = " << m_vrH);
891  }
892 
893  // - if all byte segments of the AMD PDU with SN = VR(MS) are received:
894  // - update VR(MS) to the SN of the first AMD PDU with SN > current VR(MS) for
895  // which not all byte segments have been received;
896 
897  std::map <uint16_t, PduBuffer>::iterator it = m_rxonBuffer.find (m_vrMs.GetValue ());
898  if ( it != m_rxonBuffer.end () &&
899  it->second.m_pduComplete )
900  {
901  int firstVrMs = m_vrMs.GetValue ();
902  while ( it != m_rxonBuffer.end () &&
903  it->second.m_pduComplete )
904  {
905  m_vrMs++;
906  it = m_rxonBuffer.find (m_vrMs.GetValue ());
907  NS_LOG_LOGIC ("Incr VR(MS) = " << m_vrMs);
908 
909  NS_ASSERT_MSG (firstVrMs != m_vrMs.GetValue (), "Infinite loop in RxonBuffer");
910  }
911  NS_LOG_LOGIC ("New VR(MS) = " << m_vrMs);
912  }
913 
914  // - if x = VR(R):
915  // - if all byte segments of the AMD PDU with SN = VR(R) are received:
916  // - 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;
917  // - update VR(MR) to the updated VR(R) + AM_Window_Size;
918  // - 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;
919 
920  if ( seqNumber == m_vrR )
921  {
922  std::map <uint16_t, PduBuffer>::iterator it = m_rxonBuffer.find (seqNumber.GetValue ());
923  if ( it != m_rxonBuffer.end () &&
924  it->second.m_pduComplete )
925  {
926  it = m_rxonBuffer.find (m_vrR.GetValue ());
927  int firstVrR = m_vrR.GetValue ();
928  while ( it != m_rxonBuffer.end () &&
929  it->second.m_pduComplete )
930  {
931  NS_LOG_LOGIC ("Reassemble and Deliver ( SN = " << m_vrR << " )");
932  NS_ASSERT_MSG (it->second.m_byteSegments.size () == 1,
933  "Too many segments. PDU Reassembly process didn't work");
934  ReassembleAndDeliver (it->second.m_byteSegments.front ());
935  m_rxonBuffer.erase (m_vrR.GetValue ());
936 
937  m_vrR++;
942  it = m_rxonBuffer.find (m_vrR.GetValue ());
943 
944  NS_ASSERT_MSG (firstVrR != m_vrR.GetValue (), "Infinite loop in RxonBuffer");
945  }
946  NS_LOG_LOGIC ("New VR(R) = " << m_vrR);
948 
949  NS_LOG_LOGIC ("New VR(MR) = " << m_vrMr);
950  }
951 
952  }
953 
954  // - if t-Reordering is running:
955  // - if VR(X) = VR(R); or
956  // - if VR(X) falls outside of the receiving window and VR(X) is not equal to VR(MR):
957  // - stop and reset t-Reordering;
958 
959  if ( m_reorderingTimer.IsRunning () )
960  {
961  NS_LOG_LOGIC ("Reordering timer is running");
962  if ( (m_vrX == m_vrR) ||
963  ( (! IsInsideReceivingWindow (m_vrX)) && (m_vrX != m_vrMr) )
964  )
965  {
967  NS_LOG_LOGIC ("Stop reordering timer");
969  }
970  }
971 
972  // - if t-Reordering is not running (includes the case t-Reordering is stopped due to actions above):
973  // - if VR (H) > VR(R):
974  // - start t-Reordering;
975  // - set VR(X) to VR(H).
976 
977  if ( ! m_reorderingTimer.IsRunning () )
978  {
979  NS_LOG_LOGIC ("Reordering timer is not running");
980  if ( m_vrH > m_vrR )
981  {
982  NS_LOG_LOGIC ("Start reordering timer");
985  m_vrX = m_vrH;
986  NS_LOG_LOGIC ("New VR(X) = " << m_vrX);
987  }
988  }
989  }
990  else if ( rlcAmHeader.IsControlPdu () )
991  {
992  NS_LOG_INFO ("Control AM RLC PDU");
993 
994  SequenceNumber10 ackSn = rlcAmHeader.GetAckSn ();
995  SequenceNumber10 sn;
996 
997  NS_LOG_INFO ("ackSn = " << ackSn);
998  NS_LOG_INFO ("VT(A) = " << m_vtA);
999  NS_LOG_INFO ("VT(S) = " << m_vtS);
1000  NS_LOG_LOGIC ("retxBufferSize = " << m_retxBufferSize);
1001  NS_LOG_LOGIC ("txedBufferSize = " << m_txedBufferSize);
1002 
1006  ackSn.SetModulusBase (m_vtA);
1007  sn.SetModulusBase (m_vtA);
1008 
1009  bool incrementVtA = true;
1010 
1011  for (sn = m_vtA; sn < ackSn && sn < m_vtS; sn++)
1012  {
1013  NS_LOG_LOGIC ("sn = " << sn);
1014 
1015  uint16_t seqNumberValue = sn.GetValue ();
1016 
1018  && (seqNumberValue == m_pollSn.GetValue ()))
1019  {
1021  }
1022 
1023  if (rlcAmHeader.IsNackPresent (sn))
1024  {
1025  NS_LOG_LOGIC ("sn " << sn << " is NACKed");
1026 
1027  incrementVtA = false;
1028 
1029  if (m_txedBuffer.at (seqNumberValue).m_pdu != 0)
1030  {
1031  NS_LOG_INFO ("Move SN = " << seqNumberValue << " to retxBuffer");
1032  m_retxBuffer.at (seqNumberValue).m_pdu = m_txedBuffer.at (seqNumberValue).m_pdu->Copy ();
1033  m_retxBuffer.at (seqNumberValue).m_retxCount = m_txedBuffer.at (seqNumberValue).m_retxCount;
1034  m_retxBufferSize += m_retxBuffer.at (seqNumberValue).m_pdu->GetSize ();
1035 
1036  m_txedBufferSize -= m_txedBuffer.at (seqNumberValue).m_pdu->GetSize ();
1037  m_txedBuffer.at (seqNumberValue).m_pdu = 0;
1038  m_txedBuffer.at (seqNumberValue).m_retxCount = 0;
1039  }
1040 
1041  NS_ASSERT (m_retxBuffer.at (seqNumberValue).m_pdu != 0);
1042 
1043  }
1044  else
1045  {
1046  NS_LOG_LOGIC ("sn " << sn << " is ACKed");
1047 
1048  if (m_txedBuffer.at (seqNumberValue).m_pdu)
1049  {
1050  NS_LOG_INFO ("ACKed SN = " << seqNumberValue << " from txedBuffer");
1051  // NS_LOG_INFO ("m_txedBuffer( " << m_vtA << " )->GetSize = " << m_txedBuffer.at (m_vtA.GetValue ())->GetSize ());
1052  m_txedBufferSize -= m_txedBuffer.at (seqNumberValue).m_pdu->GetSize ();
1053  m_txedBuffer.at (seqNumberValue).m_pdu = 0;
1054  NS_ASSERT (m_retxBuffer.at (seqNumberValue).m_pdu == 0);
1055  }
1056 
1057  if (m_retxBuffer.at (seqNumberValue).m_pdu)
1058  {
1059  NS_LOG_INFO ("ACKed SN = " << seqNumberValue << " from retxBuffer");
1060  m_retxBufferSize -= m_retxBuffer.at (seqNumberValue).m_pdu->GetSize ();
1061  m_retxBuffer.at (seqNumberValue).m_pdu = 0;
1062  m_retxBuffer.at (seqNumberValue).m_retxCount = 0;
1063  }
1064 
1065  }
1066 
1067  NS_LOG_LOGIC ("retxBufferSize = " << m_retxBufferSize);
1068  NS_LOG_LOGIC ("txedBufferSize = " << m_txedBufferSize);
1069 
1070  if (incrementVtA)
1071  {
1072  m_vtA++;
1074  NS_LOG_INFO ("New VT(A) = " << m_vtA);
1077  m_vtS.SetModulusBase (m_vtA);
1078  ackSn.SetModulusBase (m_vtA);
1079  sn.SetModulusBase (m_vtA);
1080  }
1081 
1082  } // loop over SN : VT(A) <= SN < ACK SN
1083 
1084  return;
1085 
1086  }
1087  else
1088  {
1089  NS_LOG_WARN ("Wrong AM RLC PDU type");
1090  return;
1091  }
1092 
1093 }
1094 
1095 
1096 bool
1098 {
1099  NS_LOG_FUNCTION (this << seqNumber);
1100  NS_LOG_LOGIC ("Receiving Window: " <<
1101  m_vrR << " <= " << seqNumber << " <= " << m_vrMr);
1102 
1105  seqNumber.SetModulusBase (m_vrR);
1106 
1107  if ( (m_vrR <= seqNumber) && (seqNumber < m_vrMr ) )
1108  {
1109  NS_LOG_LOGIC (seqNumber << " is INSIDE the receiving window");
1110  return true;
1111  }
1112  else
1113  {
1114  NS_LOG_LOGIC (seqNumber << " is OUTSIDE the receiving window");
1115  return false;
1116  }
1117 }
1118 
1119 
1120 void
1122 {
1123  LteRlcAmHeader rlcAmHeader;
1124  packet->RemoveHeader (rlcAmHeader);
1125  uint8_t framingInfo = rlcAmHeader.GetFramingInfo ();
1126  SequenceNumber10 currSeqNumber = rlcAmHeader.GetSequenceNumber ();
1127  bool expectedSnLost;
1128 
1129  if ( currSeqNumber != m_expectedSeqNumber )
1130  {
1131  expectedSnLost = true;
1132  NS_LOG_LOGIC ("There are losses. Expected SN = " << m_expectedSeqNumber << ". Current SN = " << currSeqNumber);
1133  m_expectedSeqNumber = currSeqNumber + 1;
1134  }
1135  else
1136  {
1137  expectedSnLost = false;
1138  NS_LOG_LOGIC ("No losses. Expected SN = " << m_expectedSeqNumber << ". Current SN = " << currSeqNumber);
1140  }
1141 
1142  // Build list of SDUs
1143  uint8_t extensionBit;
1144  uint16_t lengthIndicator;
1145  do
1146  {
1147  extensionBit = rlcAmHeader.PopExtensionBit ();
1148  NS_LOG_LOGIC ("E = " << (uint16_t)extensionBit);
1149 
1150  if ( extensionBit == 0 )
1151  {
1152  m_sdusBuffer.push_back (packet);
1153  }
1154  else // extensionBit == 1
1155  {
1156  lengthIndicator = rlcAmHeader.PopLengthIndicator ();
1157  NS_LOG_LOGIC ("LI = " << lengthIndicator);
1158 
1159  // Check if there is enough data in the packet
1160  if ( lengthIndicator >= packet->GetSize () )
1161  {
1162  NS_LOG_LOGIC ("INTERNAL ERROR: Not enough data in the packet (" << packet->GetSize () << "). Needed LI=" << lengthIndicator);
1164  }
1165 
1166  // Split packet in two fragments
1167  Ptr<Packet> data_field = packet->CreateFragment (0, lengthIndicator);
1168  packet->RemoveAtStart (lengthIndicator);
1169 
1170  m_sdusBuffer.push_back (data_field);
1171  }
1172  }
1173  while ( extensionBit == 1 );
1174 
1175  std::list < Ptr<Packet> >::iterator it;
1176 
1177  // Current reassembling state
1178  if (m_reassemblingState == WAITING_S0_FULL) NS_LOG_LOGIC ("Reassembling State = 'WAITING_S0_FULL'");
1179  else if (m_reassemblingState == WAITING_SI_SF) NS_LOG_LOGIC ("Reassembling State = 'WAITING_SI_SF'");
1180  else NS_LOG_LOGIC ("Reassembling State = Unknown state");
1181 
1182  // Received framing Info
1183  NS_LOG_LOGIC ("Framing Info = " << (uint16_t)framingInfo);
1184  NS_LOG_LOGIC ("m_sdusBuffer = " << m_sdusBuffer.size ());
1185 
1186  // Reassemble the list of SDUs (when there is no losses)
1187  if (!expectedSnLost)
1188  {
1189  switch (m_reassemblingState)
1190  {
1191  case WAITING_S0_FULL:
1192  switch (framingInfo)
1193  {
1196 
1200  for ( it = m_sdusBuffer.begin () ; it != m_sdusBuffer.end () ; it++ )
1201  {
1203  }
1204  m_sdusBuffer.clear ();
1205  break;
1206 
1209 
1213  while ( m_sdusBuffer.size () > 1 )
1214  {
1216  m_sdusBuffer.pop_front ();
1217  }
1218 
1222  m_keepS0 = m_sdusBuffer.front ();
1223  m_sdusBuffer.pop_front ();
1224  break;
1225 
1228  default:
1232  NS_LOG_LOGIC ("INTERNAL ERROR: Transition not possible. FI = " << (uint32_t) framingInfo);
1233  break;
1234  }
1235  break;
1236 
1237  case WAITING_SI_SF:
1238  switch (framingInfo)
1239  {
1242 
1246  m_keepS0->AddAtEnd (m_sdusBuffer.front ());
1247  m_sdusBuffer.pop_front ();
1249 
1253  while ( ! m_sdusBuffer.empty () )
1254  {
1256  m_sdusBuffer.pop_front ();
1257  }
1258  break;
1259 
1262 
1266  if ( m_sdusBuffer.size () == 1 )
1267  {
1268  m_keepS0->AddAtEnd (m_sdusBuffer.front ());
1269  m_sdusBuffer.pop_front ();
1270  }
1271  else // m_sdusBuffer.size () > 1
1272  {
1276  m_keepS0->AddAtEnd (m_sdusBuffer.front ());
1277  m_sdusBuffer.pop_front ();
1279 
1283  while ( m_sdusBuffer.size () > 1 )
1284  {
1286  m_sdusBuffer.pop_front ();
1287  }
1288 
1292  m_keepS0 = m_sdusBuffer.front ();
1293  m_sdusBuffer.pop_front ();
1294  }
1295  break;
1296 
1299  default:
1303  NS_LOG_LOGIC ("INTERNAL ERROR: Transition not possible. FI = " << (uint32_t) framingInfo);
1304  break;
1305  }
1306  break;
1307 
1308  default:
1309  NS_LOG_LOGIC ("INTERNAL ERROR: Wrong reassembling state = " << (uint32_t) m_reassemblingState);
1310  break;
1311  }
1312  }
1313  else // Reassemble the list of SDUs (when there are losses, i.e. the received SN is not the expected one)
1314  {
1315  switch (m_reassemblingState)
1316  {
1317  case WAITING_S0_FULL:
1318  switch (framingInfo)
1319  {
1322 
1326  for ( it = m_sdusBuffer.begin () ; it != m_sdusBuffer.end () ; it++ )
1327  {
1329  }
1330  m_sdusBuffer.clear ();
1331  break;
1332 
1335 
1339  while ( m_sdusBuffer.size () > 1 )
1340  {
1342  m_sdusBuffer.pop_front ();
1343  }
1344 
1348  m_keepS0 = m_sdusBuffer.front ();
1349  m_sdusBuffer.pop_front ();
1350  break;
1351 
1354 
1358  m_sdusBuffer.pop_front ();
1359 
1363  while ( ! m_sdusBuffer.empty () )
1364  {
1366  m_sdusBuffer.pop_front ();
1367  }
1368  break;
1369 
1371  if ( m_sdusBuffer.size () == 1 )
1372  {
1374  }
1375  else
1376  {
1378  }
1379 
1383  m_sdusBuffer.pop_front ();
1384 
1385  if ( m_sdusBuffer.size () > 0 )
1386  {
1390  while ( m_sdusBuffer.size () > 1 )
1391  {
1393  m_sdusBuffer.pop_front ();
1394  }
1395 
1399  m_keepS0 = m_sdusBuffer.front ();
1400  m_sdusBuffer.pop_front ();
1401  }
1402  break;
1403 
1404  default:
1408  NS_LOG_LOGIC ("INTERNAL ERROR: Transition not possible. FI = " << (uint32_t) framingInfo);
1409  break;
1410  }
1411  break;
1412 
1413  case WAITING_SI_SF:
1414  switch (framingInfo)
1415  {
1418 
1422  m_keepS0 = 0;
1423 
1427  while ( ! m_sdusBuffer.empty () )
1428  {
1430  m_sdusBuffer.pop_front ();
1431  }
1432  break;
1433 
1436 
1440  m_keepS0 = 0;
1441 
1445  while ( m_sdusBuffer.size () > 1 )
1446  {
1448  m_sdusBuffer.pop_front ();
1449  }
1450 
1454  m_keepS0 = m_sdusBuffer.front ();
1455  m_sdusBuffer.pop_front ();
1456 
1457  break;
1458 
1461 
1465  m_keepS0 = 0;
1466 
1470  m_sdusBuffer.pop_front ();
1471 
1475  while ( ! m_sdusBuffer.empty () )
1476  {
1478  m_sdusBuffer.pop_front ();
1479  }
1480  break;
1481 
1483  if ( m_sdusBuffer.size () == 1 )
1484  {
1486  }
1487  else
1488  {
1490  }
1491 
1495  m_keepS0 = 0;
1496 
1500  m_sdusBuffer.pop_front ();
1501 
1502  if ( m_sdusBuffer.size () > 0 )
1503  {
1507  while ( m_sdusBuffer.size () > 1 )
1508  {
1510  m_sdusBuffer.pop_front ();
1511  }
1512 
1516  m_keepS0 = m_sdusBuffer.front ();
1517  m_sdusBuffer.pop_front ();
1518  }
1519  break;
1520 
1521  default:
1525  NS_LOG_LOGIC ("INTERNAL ERROR: Transition not possible. FI = " << (uint32_t) framingInfo);
1526  break;
1527  }
1528  break;
1529 
1530  default:
1531  NS_LOG_LOGIC ("INTERNAL ERROR: Wrong reassembling state = " << (uint32_t) m_reassemblingState);
1532  break;
1533  }
1534  }
1535 
1536 }
1537 
1538 void
1540 {
1541  NS_LOG_FUNCTION (this);
1542 
1543  Time now = Simulator::Now ();
1544 
1545  NS_LOG_LOGIC ("txonBufferSize = " << m_txonBufferSize);
1546  NS_LOG_LOGIC ("retxBufferSize = " << m_retxBufferSize);
1547  NS_LOG_LOGIC ("txedBufferSize = " << m_txedBufferSize);
1548  NS_LOG_LOGIC ("VT(A) = " << m_vtA);
1549  NS_LOG_LOGIC ("VT(S) = " << m_vtS);
1550 
1551  // Transmission Queue HOL time
1552  Time txonQueueHolDelay (0);
1553  if ( m_txonBufferSize > 0 )
1554  {
1555  RlcTag txonQueueHolTimeTag;
1556  m_txonBuffer.front ()->PeekPacketTag (txonQueueHolTimeTag);
1557  txonQueueHolDelay = now - txonQueueHolTimeTag.GetSenderTimestamp ();
1558  }
1559 
1560  // Retransmission Queue HOL time
1561  Time retxQueueHolDelay;
1562  RlcTag retxQueueHolTimeTag;
1563  if ( m_retxBufferSize > 0 )
1564  {
1565  if (m_retxBuffer.at (m_vtA.GetValue ()).m_pdu != 0)
1566  {
1567  m_retxBuffer.at (m_vtA.GetValue ()).m_pdu->PeekPacketTag (retxQueueHolTimeTag);
1568  }
1569  else
1570  {
1571  m_txedBuffer.at (m_vtA.GetValue ()).m_pdu->PeekPacketTag (retxQueueHolTimeTag);
1572  }
1573  retxQueueHolDelay = now - retxQueueHolTimeTag.GetSenderTimestamp ();
1574  }
1575  else
1576  {
1577  retxQueueHolDelay = Seconds (0);
1578  }
1579 
1581  r.rnti = m_rnti;
1582  r.lcid = m_lcid;
1584  r.txQueueHolDelay = txonQueueHolDelay.GetMilliSeconds ();
1586  r.retxQueueHolDelay = retxQueueHolDelay.GetMilliSeconds ();
1587 
1589  {
1591  }
1592  else
1593  {
1594  r.statusPduSize = 0;
1595  }
1596 
1597  if ( r.txQueueSize != 0 || r.retxQueueSize != 0 || r.statusPduSize != 0 )
1598  {
1599  NS_LOG_INFO ("Send ReportBufferStatus: " << r.txQueueSize << ", " << r.txQueueHolDelay << ", "
1600  << r.retxQueueSize << ", " << r.retxQueueHolDelay << ", "
1601  << r.statusPduSize);
1603  }
1604  else
1605  {
1606  NS_LOG_INFO ("ReportBufferStatus don't needed");
1607  }
1608 }
1609 
1610 
1611 void
1613 {
1614  NS_LOG_FUNCTION (this);
1615  NS_LOG_LOGIC ("Reordering Timer has expired");
1616 
1617  // 5.1.3.2.4 Actions when t-Reordering expires
1618  // When t-Reordering expires, the receiving side of an AM RLC entity shall:
1619  // - update VR(MS) to the SN of the first AMD PDU with SN >= VR(X) for which not all byte segments
1620  // have been received;
1621  // - if VR(H) > VR(MS):
1622  // - start t-Reordering;
1623  // - set VR(X) to VR(H).
1624 
1625  m_vrMs = m_vrX;
1626  int firstVrMs = m_vrMs.GetValue ();
1627  std::map <uint16_t, PduBuffer>::iterator it = m_rxonBuffer.find (m_vrMs.GetValue ());
1628  while ( it != m_rxonBuffer.end () &&
1629  it->second.m_pduComplete )
1630  {
1631  m_vrMs++;
1632  it = m_rxonBuffer.find (m_vrMs.GetValue ());
1633 
1634  NS_ASSERT_MSG (firstVrMs != m_vrMs.GetValue (), "Infinite loop in ExpireReorderingTimer");
1635  }
1636  NS_LOG_LOGIC ("New VR(MS) = " << m_vrMs);
1637 
1638  if ( m_vrH > m_vrMs )
1639  {
1640  NS_LOG_LOGIC ("Start reordering timer");
1643  m_vrX = m_vrH;
1644  NS_LOG_LOGIC ("New VR(MS) = " << m_vrMs);
1645  }
1646 
1647  // Section 5.2.3 Status Reporting:
1648  // - The receiving side of an AM RLC entity shall trigger a
1649  // STATUS report when T_reordering expires.
1650  m_statusPduRequested = true;
1651 }
1652 
1653 void
1655 {
1656  NS_LOG_FUNCTION (this);
1657  NS_LOG_LOGIC ("PollRetransmit Timer has expired");
1658 
1659  NS_LOG_LOGIC ("txonBufferSize = " << m_txonBufferSize);
1660  NS_LOG_LOGIC ("retxBufferSize = " << m_retxBufferSize);
1661  NS_LOG_LOGIC ("txedBufferSize = " << m_txedBufferSize);
1662  NS_LOG_LOGIC ("statusPduRequested = " << m_statusPduRequested);
1663 
1665 
1666  // see section 5.2.2.3
1667  // note the difference between Rel 8 and Rel 11 specs; we follow Rel 11 here
1668  NS_ASSERT (m_vtS <= m_vtMs);
1669  if ((m_txonBufferSize == 0 && m_retxBufferSize == 0)
1670  || (m_vtS == m_vtMs))
1671  {
1672  NS_LOG_INFO ("txonBuffer and retxBuffer empty. Move PDUs up to = " << m_vtS.GetValue () - 1 << " to retxBuffer");
1673  uint16_t sn = 0;
1674  for ( sn = m_vtA.GetValue(); sn < m_vtS.GetValue (); sn++ )
1675  {
1676  bool pduAvailable = m_txedBuffer.at (sn).m_pdu != 0;
1677 
1678  if ( pduAvailable )
1679  {
1680  NS_LOG_INFO ("Move PDU " << sn << " from txedBuffer to retxBuffer");
1681  m_retxBuffer.at (sn).m_pdu = m_txedBuffer.at (sn).m_pdu->Copy ();
1682  m_retxBuffer.at (sn).m_retxCount = m_txedBuffer.at (sn).m_retxCount;
1683  m_retxBufferSize += m_retxBuffer.at (sn).m_pdu->GetSize ();
1684 
1685  m_txedBufferSize -= m_txedBuffer.at (sn).m_pdu->GetSize ();
1686  m_txedBuffer.at (sn).m_pdu = 0;
1687  m_txedBuffer.at (sn).m_retxCount = 0;
1688  }
1689  }
1690  }
1691 
1693 }
1694 
1695 
1696 void
1698 {
1699  NS_LOG_FUNCTION (this);
1700 }
1701 
1702 void
1704 {
1705  NS_LOG_LOGIC ("RBS Timer expires");
1706 
1708  {
1711  }
1712 }
1713 
1714 } // 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
bool FindFirstMatchingByteTag(Tag &tag) const
Finds the first tag matching the parameter Tag type.
Definition: packet.cc:807
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:732
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:1539
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:786
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:1097
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
uint8_t lcid
the logical channel id corresponding to the sending RLC instance
Definition: lte-mac-sap.h:49
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:1703
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
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:1216
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
uint16_t rnti
the C-RNTI identifying the UE
Definition: lte-mac-sap.h:48
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.
uint8_t layer
the layer value that was passed by the MAC in the call to NotifyTxOpportunity that generated this PDU...
Definition: lte-mac-sap.h:50
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:223
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:725
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:1697
void ExpirePollRetransmitTimer(void)
Definition: lte-rlc-am.cc:1654
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:1121
uint16_t m_windowSize
Constants.
Definition: lte-rlc-am.h:144
uint8_t harqProcessId
the HARQ process id that was passed by the MAC in the call to NotifyTxOpportunity that generated this...
Definition: lte-mac-sap.h:51
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:826
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:1612
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
void AddByteTag(const Tag &tag) const
Tag each byte included in this packet with a new byte tag.
Definition: packet.cc:791
Parameters for LteMacSapProvider::TransmitPdu.
Definition: lte-mac-sap.h:45