A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
lte-enb-rrc.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: Nicola Baldo <nbaldo@cttc.es>
19  * Modified by: Marco Miozzo <mmiozzo@cttc.es>
20  * add transmission Mode and SRS related functionalities
21  */
22 
23 #include <ns3/fatal-error.h>
24 #include <ns3/log.h>
25 #include <ns3/abort.h>
26 #include "ns3/pointer.h"
27 #include "ns3/object-map.h"
28 #include "ns3/object-factory.h"
29 
30 #include "lte-enb-rrc.h"
31 #include "lte-rlc.h"
32 #include "lte-pdcp.h"
33 #include "lte-pdcp-sap.h"
34 #include "lte-radio-bearer-info.h"
35 #include "lte-radio-bearer-tag.h"
36 #include "ns3/object-map.h"
37 #include <ns3/ff-mac-csched-sap.h>
38 
39 #include <ns3/simulator.h>
40 
41 // WILD HACK for UE-RRC direct communications
42 #include <ns3/node-list.h>
43 #include <ns3/node.h>
44 #include <ns3/lte-ue-net-device.h>
45 #include <ns3/lte-ue-rrc.h>
46 
47 
48 
49 NS_LOG_COMPONENT_DEFINE ("LteEnbRrc");
50 
51 namespace ns3 {
52 
53 
54 
55 
56 
57 // ///////////////////////////
58 // CMAC SAP forwarder
59 // ///////////////////////////
60 
62 {
63 public:
65 
66  virtual void NotifyLcConfigResult (uint16_t rnti, uint8_t lcid, bool success);
67  virtual void RrcConfigurationUpdateInd (LteUeConfig_t params);
68 
69 private:
71 };
72 
74  : m_rrc (rrc)
75 {
76 }
77 
78 void
79 EnbRrcMemberLteEnbCmacSapUser::NotifyLcConfigResult (uint16_t rnti, uint8_t lcid, bool success)
80 {
81  m_rrc->DoNotifyLcConfigResult (rnti, lcid, success);
82 }
83 
84 void
86 {
88 }
89 
90 
92 // PDCP SAP Forwarder
94 
95 // not needed any more if the template works
96 
97 // class EnbRrcMemberLtePdcpSapUser : public LtePdcpSapUser
98 // {
99 // public:
100 // MemberLtePdcpSapUser (LteEnbRrc* rrc);
101 // virtual void ReceiveRrcPdu (Ptr<Packet> p);
102 // private:
103 // LteEnbRrc* m_rrc;
104 // };
105 
106 
107 // EnbRrcMemberLtePdcpSapUser::EnbRrcMemberLtePdcpSapUser (LteEnbRrc* rrc)
108 // : m_rrc (rrc)
109 // {
110 // }
111 
112 // void EnbRrcMemberLtePdcpSapUser::ReceiveRrcPdu (Ptr<Packet> p)
113 // {
114 // m_rrc->DoReceiveRrcPdu (p);
115 // }
116 
117 
118 
119 
121 // UeInfo
123 
124 
126 
128  : m_lastAllocatedId (0)
129 {
130  m_imsi = 0;
132  m_transmissionMode = 0;
133 }
134 
135 UeInfo::UeInfo (uint64_t imsi)
136  : m_lastAllocatedId (0)
137 {
138  m_imsi = imsi;
140  m_transmissionMode = 0;
141 }
142 
143 UeInfo::UeInfo (uint64_t imsi, uint16_t srsConfIndex)
144 : m_lastAllocatedId (0)
145 {
146  m_imsi = imsi;
147  m_srsConfigurationIndex = srsConfIndex;
148  m_transmissionMode = 0;
149 }
150 
151 
152 
154 {
155  // Nothing to do here
156 }
157 
159 {
160  static TypeId tid = TypeId ("ns3::UeInfo")
161  .SetParent<Object> ()
162  .AddConstructor<UeInfo> ()
163  .AddAttribute ("RadioBearerMap", "List of UE RadioBearerInfo by LCID.",
164  ObjectMapValue (),
166  MakeObjectMapChecker<LteRadioBearerInfo> ())
167  ;
168  return tid;
169 }
170 
171 uint64_t
173 {
174  return m_imsi;
175 }
176 
177 uint16_t
179 {
181 }
182 
183 uint8_t
185 {
186  return m_transmissionMode;
187 }
188 
189 void
190 UeInfo::SetSrsConfigurationIndex (uint16_t srsConfIndex)
191 {
192  m_srsConfigurationIndex = srsConfIndex;
193 }
194 
195 void
197 {
198  m_transmissionMode = txMode;
199 }
200 
201 uint8_t
203 {
204  NS_LOG_FUNCTION (this);
205  for (uint8_t lcid = m_lastAllocatedId; lcid != m_lastAllocatedId - 1; ++lcid)
206  {
207  if (lcid != 0)
208  {
209  if (m_rbMap.find (lcid) == m_rbMap.end ())
210  {
211  m_rbMap.insert (std::pair<uint8_t, Ptr<LteRadioBearerInfo> > (lcid, rbi));
212  m_lastAllocatedId = lcid;
213  return lcid;
214  }
215  }
216  }
217  NS_LOG_WARN ("no more logical channel ids available");
218  return 0;
219 }
220 
223 {
224  NS_LOG_FUNCTION (this << (uint32_t) lcid);
225  NS_ASSERT (0 != lcid);
226  std::map<uint8_t, Ptr<LteRadioBearerInfo> >::iterator it = m_rbMap.find (lcid);
227  NS_ABORT_IF (it == m_rbMap.end ());
228  return it->second;
229 }
230 
231 
232 void
234 {
235  NS_LOG_FUNCTION (this << (uint32_t) lcid);
236  std::map <uint8_t, Ptr<LteRadioBearerInfo> >::iterator it = m_rbMap.find (lcid);
237  NS_ASSERT_MSG (it != m_rbMap.end (), "request to remove radio bearer with unknown lcid " << lcid);
238  m_rbMap.erase (it);
239 }
240 
241 
242 
243 
244 
245 // ///////////////////////////
246 // eNB RRC methods
247 // ///////////////////////////
248 
250 
252  : m_cmacSapProvider (0),
253  m_ffMacSchedSapProvider (0),
254  m_macSapProvider (0),
255  m_configured (false),
256  m_lastAllocatedRnti (0),
257  m_srsCurrentPeriodicityId (0),
258  m_lastAllocatedConfigurationIndex (0),
259  m_reconfigureUes (false)
260 {
261  NS_LOG_FUNCTION (this);
264 }
265 
266 
268 {
269  NS_LOG_FUNCTION (this);
270 }
271 
272 
273 void
275 {
276  NS_LOG_FUNCTION (this);
277  delete m_cmacSapUser;
278  delete m_pdcpSapUser;
279 }
280 
281 TypeId
283 {
284  NS_LOG_FUNCTION ("LteEnbRrc::GetTypeId");
285  static TypeId tid = TypeId ("ns3::LteEnbRrc")
286  .SetParent<Object> ()
287  .AddConstructor<LteEnbRrc> ()
288  .AddAttribute ("UeMap", "List of UE Info by C-RNTI.",
289  ObjectMapValue (),
291  MakeObjectMapChecker<UeInfo> ())
292  .AddAttribute ("DefaultTransmissionMode",
293  "The default UEs' transmission mode (0: SISO)",
294  UintegerValue (0), // default tx-mode
295  MakeUintegerAccessor (&LteEnbRrc::m_defaultTransmissionMode),
296  MakeUintegerChecker<uint8_t> ())
297 
298  ;
299  return tid;
300 }
301 
302 uint16_t
304 {
305  NS_LOG_FUNCTION (this);
306  return m_lastAllocatedRnti;
307 }
308 std::map<uint16_t,Ptr<UeInfo> > LteEnbRrc::GetUeMap (void) const
309 {
310  return m_ueMap;
311 }
312 
313 void LteEnbRrc::SetUeMap (std::map<uint16_t,Ptr<UeInfo> > ueMap)
314 {
315  this->m_ueMap = ueMap;
316 }
317 
318 
319 void
320 LteEnbRrc::SetLastAllocatedRnti (uint16_t lastAllocatedRnti)
321 {
322  NS_LOG_FUNCTION (this << lastAllocatedRnti);
323  m_lastAllocatedRnti = lastAllocatedRnti;
324 }
325 
326 
327 
328 void
330 {
331  NS_LOG_FUNCTION (this << s);
332  m_cmacSapProvider = s;
333 }
334 
337 {
338  NS_LOG_FUNCTION (this);
339  return m_cmacSapUser;
340 }
341 
342 void
344 {
345  NS_LOG_FUNCTION (this);
347 }
348 
349 
350 void
352 {
353  NS_LOG_FUNCTION (this);
354  m_macSapProvider = s;
355 }
356 
358 LteEnbRrc::GetLtePdcpSapProvider (uint16_t rnti, uint8_t lcid)
359 {
360  return GetUeInfo (rnti)->GetRadioBearer (lcid)->m_pdcp->GetLtePdcpSapProvider ();
361 }
362 
363 void
364 LteEnbRrc::ConfigureCell (uint8_t ulBandwidth, uint8_t dlBandwidth)
365 {
366  NS_LOG_FUNCTION (this);
368  m_cmacSapProvider->ConfigureMac (ulBandwidth, dlBandwidth);
369  m_configured = true;
370 }
371 
372 uint16_t
373 LteEnbRrc::AddUe (uint64_t imsi)
374 {
375  NS_LOG_FUNCTION (this << imsi);
376  // no Call Admission Control for now
377  uint16_t rnti = CreateUeInfo (imsi); // side effect: create UeInfo for this UE
378  NS_ASSERT_MSG (rnti != 0, "CreateUeInfo returned RNTI==0");
379  m_cmacSapProvider->AddUe (rnti);
380  return rnti;
381 }
382 
383 void
384 LteEnbRrc::RemoveUe (uint16_t rnti)
385 {
386  NS_LOG_FUNCTION (this << (uint32_t) rnti);
387  RemoveUeInfo (rnti);
388  NS_FATAL_ERROR ("missing RemoveUe method in CMAC SAP");
389 }
390 
391 uint8_t
392 LteEnbRrc::SetupRadioBearer (uint16_t rnti, EpsBearer bearer, TypeId rlcTypeId)
393 {
394  NS_LOG_FUNCTION (this << (uint32_t) rnti);
395  Ptr<UeInfo> ueInfo = GetUeInfo (rnti);
396 
397  // create RLC instance
398 
399  ObjectFactory rlcObjectFactory;
400  rlcObjectFactory.SetTypeId (rlcTypeId);
401  Ptr<LteRlc> rlc = rlcObjectFactory.Create ()->GetObject<LteRlc> ();
403  rlc->SetRnti (rnti);
404 
405  Ptr<LteRadioBearerInfo> rbInfo = CreateObject<LteRadioBearerInfo> ();
406  rbInfo->m_rlc = rlc;
407  uint8_t lcid = ueInfo->AddRadioBearer (rbInfo);
408  rlc->SetLcId (lcid);
409 
410  // we need PDCP only for real RLC, i.e., RLC/UM or RLC/AM
411  // if we are using RLC/SM we don't care of anything above RLC
412  if (rlcTypeId != LteRlcSm::GetTypeId ())
413  {
414  Ptr<LtePdcp> pdcp = CreateObject<LtePdcp> ();
415  pdcp->SetRnti (rnti);
416  pdcp->SetLcId (lcid);
419  rlc->SetLteRlcSapUser (pdcp->GetLteRlcSapUser ());
420  rbInfo->m_pdcp = pdcp;
421  }
422 
424  lcinfo.rnti = rnti;
425  lcinfo.lcId = lcid;
426  lcinfo.lcGroup = 0; // TBD
427  lcinfo.qci = bearer.qci;
428  lcinfo.isGbr = bearer.IsGbr ();
429  lcinfo.mbrUl = bearer.gbrQosInfo.mbrUl;
430  lcinfo.mbrDl = bearer.gbrQosInfo.mbrDl;
431  lcinfo.gbrUl = bearer.gbrQosInfo.gbrUl;
432  lcinfo.gbrDl = bearer.gbrQosInfo.gbrDl;
433  m_cmacSapProvider->AddLc (lcinfo, rlc->GetLteMacSapUser ());
434 
435  return lcid;
436 }
437 
438 void
439 LteEnbRrc::ReleaseRadioBearer (uint16_t rnti, uint8_t lcId)
440 {
441  NS_LOG_FUNCTION (this << (uint32_t) rnti);
442  Ptr<UeInfo> ueInfo = GetUeInfo (rnti);
443  ueInfo->RemoveRadioBearer (lcId);
444 }
445 
446 
447 
448 bool
450 {
451  NS_LOG_FUNCTION (this << packet);
452 
453  LteRadioBearerTag tag;
454  bool found = packet->RemovePacketTag (tag);
455  NS_ASSERT (found);
456 
458  params.rrcPdu = packet;
459  params.rnti = tag.GetRnti ();
460  params.lcid = tag.GetLcid ();
461  LtePdcpSapProvider* pdcpSapProvider = GetLtePdcpSapProvider (tag.GetRnti (), tag.GetLcid ());
462  pdcpSapProvider->TransmitRrcPdu (params);
463 
464  return true;
465 }
466 
467 void
469 {
470  m_forwardUpCallback = cb;
471 }
472 
473 
474 void
476 {
477  NS_LOG_FUNCTION (this);
478  // this tag is needed by the EpcEnbApplication to determine the S1 bearer that corresponds to this radio bearer
479  LteRadioBearerTag tag;
480  tag.SetRnti (params.rnti);
481  tag.SetLcid (params.lcid);
482  params.rrcPdu->AddPacketTag (tag);
483  m_forwardUpCallback (params.rrcPdu);
484 }
485 
486 
487 
488 void
489 LteEnbRrc::DoNotifyLcConfigResult (uint16_t rnti, uint8_t lcid, bool success)
490 {
491  NS_LOG_FUNCTION (this << (uint32_t) rnti);
492  NS_FATAL_ERROR ("not implemented");
493 }
494 
495 
496 
497 // /////////////////////////////////////////
498 // management of multiple UE info instances
499 // /////////////////////////////////////////
500 
501 // from 3GPP TS 36.213 table 8.2-1 UE Specific SRS Periodicity
502 #define SRS_ENTRIES 9
503 uint16_t g_srsPeriodicity[SRS_ENTRIES] = {0, 2, 5, 10, 20, 40, 80, 160, 320};
504 uint16_t g_srsCiLow[SRS_ENTRIES] = {0, 0, 2, 7, 17, 37, 77, 157, 317};
505 uint16_t g_srsCiHigh[SRS_ENTRIES] = {0, 1, 6, 16, 36, 76, 156, 316, 636};
506 
507 void
508 LteEnbRrc::SetCellId (uint16_t cellId)
509 {
510  m_cellId = cellId;
511 }
512 
513 uint16_t
514 LteEnbRrc::CreateUeInfo (uint64_t imsi)
515 {
516  NS_LOG_FUNCTION (this << imsi);
517  for (uint16_t rnti = m_lastAllocatedRnti; rnti != m_lastAllocatedRnti - 1; ++rnti)
518  {
519  if (rnti != 0)
520  {
521  if (m_ueMap.find (rnti) == m_ueMap.end ())
522  {
523  m_lastAllocatedRnti = rnti;
524  Ptr<UeInfo> ueInfo = CreateObject<UeInfo> (imsi, GetNewSrsConfigurationIndex ());
525  m_ueMap.insert (std::pair<uint16_t, Ptr<UeInfo> > (rnti, ueInfo));
526  NS_LOG_DEBUG (this << " New UE RNTI " << rnti << " cellId " << m_cellId << " srs CI " << ueInfo->GetSrsConfigurationIndex ());
527  return rnti;
528  }
529  }
530  }
531 
532  return 0;
533 }
534 
535 uint16_t
537 {
539  // SRS
541  {
542  // no UEs -> init
543  m_ueSrsConfigurationIndexSet.insert (0);
546 
547  return 0;
548  }
550  NS_LOG_DEBUG (this << " SRS p " << g_srsPeriodicity[m_srsCurrentPeriodicityId] << " set " << m_ueSrsConfigurationIndexSet.size ());
552  {
553 // NS_LOG_DEBUG (this << " SRS reconfigure CIs " << g_srsPeriodicity[m_srsCurrentPeriodicityId] << " to " << g_srsPeriodicity[m_srsCurrentPeriodicityId+1] << " at " << Simulator::Now ());
554  // increase the current periocity for having enough CIs
558  // update all the UE's CI
559  uint16_t srcCi = g_srsCiLow[m_srsCurrentPeriodicityId];
560  std::map<uint16_t, Ptr<UeInfo> >::iterator it;
561  for (it = m_ueMap.begin (); it != m_ueMap.end (); it++)
562  {
563  (*it).second->SetSrsConfigurationIndex (srcCi);
564  m_ueSrsConfigurationIndexSet.insert (srcCi);
566  srcCi++;
567  // send update to peer RRC
568  LteUeConfig_t ueConfig;
569  ueConfig.m_rnti = (*it).first;
570  ueConfig.m_transmissionMode = (*it).second->GetTransmissionMode ();
571  ueConfig.m_srsConfigurationIndex = (*it).second->GetSrsConfigurationIndex ();
572  ueConfig.m_reconfigureFlag = false;
573  NS_LOG_DEBUG (this << "\t rnti "<<ueConfig.m_rnti<< " CI " << ueConfig.m_srsConfigurationIndex);
574  SendUeConfigurationUpdate (ueConfig);
575  }
578  }
579  else
580  {
581  // find a CI from the available ones
582  std::set<uint16_t>::reverse_iterator rit = m_ueSrsConfigurationIndexSet.rbegin ();
583  NS_LOG_DEBUG (this << " lower bound " << (*rit) << " of " << g_srsCiHigh[m_srsCurrentPeriodicityId]);
584  if ((*rit) <= g_srsCiHigh[m_srsCurrentPeriodicityId])
585  {
586  // got it from the upper bound
589  }
590  else
591  {
592  // look for released ones
593  for (uint16_t srcCi = g_srsCiLow[m_srsCurrentPeriodicityId]; srcCi < g_srsCiHigh[m_srsCurrentPeriodicityId]; srcCi++)
594  {
595  std::set<uint16_t>::iterator it = m_ueSrsConfigurationIndexSet.find (srcCi);
596  if (it==m_ueSrsConfigurationIndexSet.end ())
597  {
599  m_ueSrsConfigurationIndexSet.insert (srcCi);
600  break;
601  }
602  }
603  }
604  }
606 
607 }
608 
609 
610 void
612 {
613  NS_LOG_FUNCTION (this << srcCi);
614  std::set<uint16_t>::iterator it = m_ueSrsConfigurationIndexSet.find (srcCi);
615  NS_ASSERT_MSG (it != m_ueSrsConfigurationIndexSet.end (), "request to remove unkwown SRS CI " << srcCi);
616  m_ueSrsConfigurationIndexSet.erase (it);
619  {
620  // reduce the periodicity
624  {
625  // no active users : renitialize structures
627  }
628  else
629  {
630  // update all the UE's CI
631  uint16_t srcCi = g_srsCiLow[m_srsCurrentPeriodicityId];
632  std::map<uint16_t, Ptr<UeInfo> >::iterator it;
633  for (it = m_ueMap.begin (); it != m_ueMap.end (); it++)
634  {
635  (*it).second->SetSrsConfigurationIndex (srcCi);
636  m_ueSrsConfigurationIndexSet.insert (srcCi);
638  srcCi++;
639  // send update to peer RRC
640  LteUeConfig_t ueConfig;
641  ueConfig.m_rnti = (*it).first;
642  ueConfig.m_transmissionMode = (*it).second->GetTransmissionMode ();
643  ueConfig.m_srsConfigurationIndex = (*it).second->GetSrsConfigurationIndex ();
644  ueConfig.m_reconfigureFlag = false;
645  NS_LOG_DEBUG (this << "\t rnti "<<ueConfig.m_rnti<< " CI " << ueConfig.m_srsConfigurationIndex);
646  if (Simulator::Now ()!=Seconds(0))
647  {
648  // avoid multiple reconfiguration during initialization
649  SendUeConfigurationUpdate (ueConfig);
650  }
651  }
652  }
653  }
654 }
655 
657 LteEnbRrc::GetUeInfo (uint16_t rnti)
658 {
659  NS_LOG_FUNCTION (this << (uint32_t) rnti);
660  NS_ASSERT (0 != rnti);
661  std::map<uint16_t, Ptr<UeInfo> >::iterator it = m_ueMap.find (rnti);
662  NS_ABORT_IF (it == m_ueMap.end ());
663  return it->second;
664 }
665 
666 void
667 LteEnbRrc::RemoveUeInfo (uint16_t rnti)
668 {
669  NS_LOG_FUNCTION (this << (uint32_t) rnti);
670  std::map <uint16_t, Ptr<UeInfo> >::iterator it = m_ueMap.find (rnti);
671  NS_ASSERT_MSG (it != m_ueMap.end (), "request to remove UE info with unknown rnti " << rnti);
672  RemoveSrsConfigurationIndex ((*it).second->GetSrsConfigurationIndex ());
673  m_ueMap.erase (it);
674  // remove SRS configuration index
675 }
676 
677 
678 void
680 {
681  NS_LOG_FUNCTION (this);
682  // at this stage used only by the scheduler for updating txMode
683  // retrieve UE info
684  std::map<uint16_t, Ptr<UeInfo> >::iterator it;
685  it = m_ueMap.find (params.m_rnti);
686  NS_ASSERT_MSG (it!=m_ueMap.end (), "Unable to find UeInfo");
687  params.m_srsConfigurationIndex = (*it).second->GetSrsConfigurationIndex ();
688  // update Tx Mode info
689  (*it).second->SetTransmissionMode (params.m_transmissionMode);
690  params.m_reconfigureFlag = true;
691  // answer to MAC (and scheduler) and forward info to UEs
692  SendUeConfigurationUpdate (params);
693 }
694 
695 void
697 {
698  NS_LOG_FUNCTION (this);
699  // retrieve UE info
700  std::map<uint16_t, Ptr<UeInfo> >::iterator it;
701  it = m_ueMap.find (rnti);
702  NS_ASSERT_MSG (it!=m_ueMap.end (), "Unable to find UeInfo");
703  LteUeConfig_t params;
704  params.m_rnti = rnti;
705  params.m_srsConfigurationIndex = (*it).second->GetSrsConfigurationIndex ();
706  params.m_transmissionMode = (*it).second->GetTransmissionMode ();
707  params.m_reconfigureFlag = false;
708  // answer to MAC (and scheduler) and forward info to UEs
709  SendUeConfigurationUpdate (params);
710 }
711 
712 void
714 {
715  NS_LOG_FUNCTION (this);
716  // send LteUeConfig_t to MAC layer and peer RRCs
718  NodeList::Iterator listEnd = NodeList::End ();
719  bool done = false;
720  params.m_reconfigureFlag = false;
721  for (NodeList::Iterator i = NodeList::Begin (); i != listEnd; i++)
722  {
723  Ptr<Node> node = *i;
724  int nDevs = node->GetNDevices ();
725  for (int j = 0; j < nDevs; j++)
726  {
727  Ptr<LteUeNetDevice> uedev = node->GetDevice (j)->GetObject <LteUeNetDevice> ();
728  if (!uedev)
729  {
730  continue;
731  }
732  else
733  {
734  Ptr<LteUeRrc> ueRrc = uedev->GetRrc ();
735  if ((ueRrc->GetRnti () == params.m_rnti)&&(ueRrc->GetCellId () == m_cellId))
736  {
737  ueRrc->DoRrcConfigurationUpdateInd (params);
738  done = true;
739  }
740  else
741  {
742  continue;
743  }
744  }
745  }
746  }
747  NS_ASSERT_MSG (done , " Unable to find peer UE-RRC, RNTI " << params.m_rnti);
748 }
749 
750 
751 
752 
753 } // namespace ns3
754