improved LTE Random Access model
authorNicola Baldo <nbaldo@cttc.es>
Tue, 20 Nov 2012 18:18:01 +0100
changeset 9413 20f1c6678ee2
parent 9412 da31245666bb
child 9414 7b0db3dbf19b
improved LTE Random Access model
src/lte/examples/lena-x2-handover.cc
src/lte/model/lte-control-messages.cc
src/lte/model/lte-control-messages.h
src/lte/model/lte-enb-cmac-sap.h
src/lte/model/lte-enb-mac.cc
src/lte/model/lte-enb-mac.h
src/lte/model/lte-enb-phy.cc
src/lte/model/lte-enb-rrc.cc
src/lte/model/lte-enb-rrc.h
src/lte/model/lte-rrc-sap.h
src/lte/model/lte-ue-cmac-sap.h
src/lte/model/lte-ue-mac.cc
src/lte/model/lte-ue-mac.h
src/lte/model/lte-ue-phy.cc
src/lte/model/lte-ue-rrc.cc
src/lte/test/lte-test-pf-ff-mac-scheduler.cc
--- a/src/lte/examples/lena-x2-handover.cc	Wed Nov 14 16:05:54 2012 +0100
+++ b/src/lte/examples/lena-x2-handover.cc	Tue Nov 20 18:18:01 2012 +0100
@@ -39,22 +39,22 @@
 int
 main (int argc, char *argv[])
 {
-  LogLevel logLevel = (LogLevel)(LOG_PREFIX_FUNC | LOG_PREFIX_TIME | LOG_LEVEL_ALL);
+  // LogLevel logLevel = (LogLevel)(LOG_PREFIX_FUNC | LOG_PREFIX_TIME | LOG_LEVEL_ALL);
 
-  LogComponentEnable ("LteHelper", logLevel);
-  LogComponentEnable ("EpcHelper", logLevel);
-  LogComponentEnable ("EpcEnbApplication", logLevel);
-  LogComponentEnable ("EpcX2", logLevel);
-  LogComponentEnable ("EpcSgwPgwApplication", logLevel);
+  // LogComponentEnable ("LteHelper", logLevel);
+  // LogComponentEnable ("EpcHelper", logLevel);
+  // LogComponentEnable ("EpcEnbApplication", logLevel);
+  // LogComponentEnable ("EpcX2", logLevel);
+  // LogComponentEnable ("EpcSgwPgwApplication", logLevel);
 
-  LogComponentEnable ("LteEnbRrc", logLevel);
-  LogComponentEnable ("LteEnbNetDevice", logLevel);
-  LogComponentEnable ("LteUeRrc", logLevel);
-  LogComponentEnable ("LteUeNetDevice", logLevel);
+  // LogComponentEnable ("LteEnbRrc", logLevel);
+  // LogComponentEnable ("LteEnbNetDevice", logLevel);
+  // LogComponentEnable ("LteUeRrc", logLevel);
+  // LogComponentEnable ("LteUeNetDevice", logLevel);
 
   uint16_t numberOfUes = 1;
   uint16_t numberOfEnbs = 2;
-  double simTime = 6.0;
+  double simTime = 2.0;
   double distance = 60.0;
 
   // Command line arguments
@@ -145,7 +145,7 @@
   lteHelper->AddX2Interface (enbNodes);
 
   // X2-based Handover
-  lteHelper->HandoverRequest (Seconds (2.0), ueLteDevs.Get (0), enbLteDevs.Get (0), enbLteDevs.Get (1));
+  lteHelper->HandoverRequest (Seconds (1.0), ueLteDevs.Get (0), enbLteDevs.Get (0), enbLteDevs.Get (1));
   
   
   // Uncomment to enable PCAP tracing
--- a/src/lte/model/lte-control-messages.cc	Wed Nov 14 16:05:54 2012 +0100
+++ b/src/lte/model/lte-control-messages.cc	Tue Nov 20 18:18:01 2012 +0100
@@ -182,19 +182,18 @@
 }
 
 void
-RachPreambleLteControlMessage::SetPrachId (uint32_t prachId)
+RachPreambleLteControlMessage::SetRapId (uint32_t rapId)
 {
-  m_prachId = prachId;
+  m_rapId = rapId;
 }
 
 uint32_t 
-RachPreambleLteControlMessage::GetPrachId () const
+RachPreambleLteControlMessage::GetRapId () const
 {
-  return m_prachId;
+  return m_rapId;
 }
 
 
-
 // ----------------------------------------------------------------------------------------------------------
 
 
@@ -205,28 +204,34 @@
 
 
 void
-RarLteControlMessage::SetRar (BuildRarListElement_s rar)
+RarLteControlMessage::SetRaRnti (uint16_t raRnti)
 {
-  m_rar = rar;
+  m_raRnti = raRnti;
 }
 
-BuildRarListElement_s 
-RarLteControlMessage::GetRar () const
+uint16_t 
+RarLteControlMessage::GetRaRnti () const
 {
-  return m_rar;
+  return m_raRnti;
 }
 
 
 void
-RarLteControlMessage::SetPrachId (uint32_t prachId)
+RarLteControlMessage::AddRar (Rar rar)
 {
-  m_prachId = prachId;
+  m_rarList.push_back (rar);
 }
 
-uint32_t 
-RarLteControlMessage::GetPrachId () const
+std::list<RarLteControlMessage::Rar>::const_iterator 
+RarLteControlMessage::RarListBegin () const
 {
-  return m_prachId;
+  return m_rarList.begin ();
+}
+
+std::list<RarLteControlMessage::Rar>::const_iterator 
+RarLteControlMessage::RarListEnd () const
+{
+  return m_rarList.end ();
 }
 
 
--- a/src/lte/model/lte-control-messages.h	Wed Nov 14 16:05:54 2012 +0100
+++ b/src/lte/model/lte-control-messages.h	Tue Nov 20 18:18:01 2012 +0100
@@ -279,13 +279,23 @@
 public:
   RachPreambleLteControlMessage (void);
 
-  void SetPrachId (uint32_t prachId);
-
-  uint32_t GetPrachId () const;
+  
+  /** 
+   * Set the Random Access Preamble Identifier (RAPID), see 3GPP TS 36.321 6.2.2
+   *
+   * \param rapid
+   */
+  void SetRapId (uint32_t rapid);
+  
+  /** 
+   * 
+   * \return the RAPID
+   */
+  uint32_t GetRapId () const;
 
 private:
   
-  uint32_t m_prachId;
+  uint32_t m_rapId;
 
 
 };
@@ -315,19 +325,52 @@
 public:
   RarLteControlMessage (void);
 
-  void SetRar (BuildRarListElement_s);
+  /** 
+   * 
+   * \param raRnti the RA-RNTI, see 3GPP TS 36.321 5.1.4
+   */
+  void SetRaRnti (uint16_t raRnti);
+
+  /** 
+   * 
+   * \return  the RA-RNTI, see 3GPP TS 36.321 5.1.4
+   */
+  uint16_t GetRaRnti () const;
 
-  BuildRarListElement_s GetRar () const;
+  /**
+   * a MAC RAR and the corresponding RAPID subheader 
+   * 
+   */
+  struct Rar
+  {
+    uint8_t rapId;
+    BuildRarListElement_s rarPayload;
+  };
+
+  /** 
+   * add a RAR to the MAC PDU, see 3GPP TS 36.321 6.2.3
+   * 
+   * \param rar the rar
+   */
+  void AddRar (Rar rar);
+
+  /** 
+   * 
+   * \return a const iterator to the beginning of the RAR list
+   */
+  std::list<Rar>::const_iterator RarListBegin () const;
   
-  void SetPrachId (uint32_t prachId);
+  /** 
+   * 
+   * \return a const iterator to the end of the RAR list
+   */
+  std::list<Rar>::const_iterator RarListEnd () const;
   
-  uint32_t GetPrachId () const;
-
-
+  
 private:
   
-  BuildRarListElement_s m_rar;
-  uint32_t m_prachId;
+  std::list<Rar> m_rarList;
+  uint16_t m_raRnti;
 
 };
 
--- a/src/lte/model/lte-enb-cmac-sap.h	Wed Nov 14 16:05:54 2012 +0100
+++ b/src/lte/model/lte-enb-cmac-sap.h	Tue Nov 20 18:18:01 2012 +0100
@@ -118,9 +118,49 @@
     uint8_t   m_transmissionMode;
   };
 
+  /** 
+   * update the configuration of the UE
+   * 
+   * \param params 
+   */
   virtual void UeUpdateConfigurationReq (UeConfig params) = 0;
 
 
+  /**
+   * struct defining the RACH configuration of the MAC
+   * 
+   */
+  struct RachConfig
+  {
+    uint8_t numberOfRaPreambles;
+    uint8_t preambleTransMax;
+    uint8_t raResponseWindowSize;
+  };
+
+  /** 
+   * 
+   * \return the current RACH configuration of the MAC
+   */
+  virtual RachConfig GetRachConfig () = 0;
+
+  /**
+   * 
+   * 
+   */
+  struct AllocateNcRaPreambleReturnValue
+  {
+    bool valid; ///< true if a valid RA config was allocated, false otherwise
+    uint8_t raPreambleId; ///< random access preamble id
+    uint8_t raPrachMaskIndex; /// PRACH mask index
+  };
+
+  /** 
+   * Allocate a random access preamble for non-contention based random access (e.g., for handover).
+   * 
+   * \return the newly allocated random access preamble (0 < 
+   */
+  virtual AllocateNcRaPreambleReturnValue AllocateNcRaPreamble () = 0;
+
 };
 
 
--- a/src/lte/model/lte-enb-mac.cc	Wed Nov 14 16:05:54 2012 +0100
+++ b/src/lte/model/lte-enb-mac.cc	Tue Nov 20 18:18:01 2012 +0100
@@ -23,6 +23,7 @@
 #include <ns3/log.h>
 #include <ns3/pointer.h>
 #include <ns3/packet.h>
+#include <ns3/simulator.h>
 
 #include "lte-amc.h"
 #include "lte-control-messages.h"
@@ -64,6 +65,9 @@
   virtual void ReconfigureLc (LcInfo lcinfo);
   virtual void ReleaseLc (uint16_t rnti, uint8_t lcid);
   virtual void UeUpdateConfigurationReq (UeConfig params);
+  virtual RachConfig GetRachConfig ();
+  virtual AllocateNcRaPreambleReturnValue AllocateNcRaPreamble ();
+  
 
 private:
   LteEnbMac* m_mac;
@@ -117,6 +121,17 @@
   m_mac->DoUeUpdateConfigurationReq (params);
 }
 
+LteEnbCmacSapProvider::RachConfig 
+EnbMacMemberLteEnbCmacSapProvider::GetRachConfig ()
+{
+  return m_mac->DoGetRachConfig ();
+}
+ 
+LteEnbCmacSapProvider::AllocateNcRaPreambleReturnValue 
+EnbMacMemberLteEnbCmacSapProvider::AllocateNcRaPreamble ()
+{
+  return m_mac->DoAllocateNcRaPreamble ();
+}
 
 
 class EnbMacMemberFfMacSchedSapUser : public FfMacSchedSapUser
@@ -287,6 +302,21 @@
   static TypeId tid = TypeId ("ns3::LteEnbMac")
     .SetParent<Object> ()
     .AddConstructor<LteEnbMac> ()
+    .AddAttribute ("NumberOfRaPreambles",
+                   "how many random access preambles are available for the contention based RACH process",
+                   UintegerValue (50),
+                   MakeUintegerAccessor (&LteEnbMac::m_numberOfRaPreambles),
+                   MakeUintegerChecker<uint8_t> (4, 64))
+    .AddAttribute ("PreambleTransMax",
+                   "Maximum number of random access preamble transmissions",
+                   UintegerValue (10),
+                   MakeUintegerAccessor (&LteEnbMac::m_preambleTransMax),
+                   MakeUintegerChecker<uint8_t> (3, 200))
+    .AddAttribute ("RaResponseWindowSize",
+                   "length of the window (in TTIs) for the reception of the random access response (RAR); the resulting RAR timeout is this value + 3 ms",
+                   UintegerValue (3),
+                   MakeUintegerAccessor (&LteEnbMac::m_raResponseWindowSize),
+                   MakeUintegerChecker<uint8_t> (2, 10))
     .AddTraceSource ("DlScheduling",
                      "Information regarding DL scheduling.",
                      MakeTraceSourceAccessor (&LteEnbMac::m_dlScheduling))
@@ -419,6 +449,50 @@
       m_schedSapProvider->SchedDlCqiInfoReq (dlcqiInfoReq);
     }
 
+  if (!m_receivedRachPreambleCount.empty ())
+    {
+      // process received RACH preambles and notify the scheduler
+      FfMacSchedSapProvider::SchedDlRachInfoReqParameters rachInfoReqParams;
+      // TODO: we should wait for DL_SCHEDULE_INDICATION to build the RARs
+      // from the RAR_List; this requires proper support from the scheduler.
+      // For now, we take a shortcut and just build the RAR here
+      // as an ideal message and without an UL grant.
+      Ptr<RarLteControlMessage> rarMsg = Create<RarLteControlMessage> ();
+      NS_ASSERT (subframeNo > 0 && subframeNo <= 10); // subframe in 1..10
+      // see TS 36.321 5.1.4;  preambles were sent two frames ago
+      // (plus 3GPP counts subframes from 0, not 1)
+      uint16_t raRnti = subframeNo - 3; 
+      rarMsg->SetRaRnti (raRnti);
+      for (std::map<uint8_t, uint32_t>::const_iterator it = m_receivedRachPreambleCount.begin ();
+           it != m_receivedRachPreambleCount.end ();
+           ++it)
+        {
+          NS_LOG_LOGIC ("preambleId " << (uint32_t) it->first << ": " << it->second << " received");
+          NS_ASSERT (it->second != 0);
+          if (it->second > 1)
+            {
+              NS_LOG_INFO ("preambleId " << (uint32_t) it->first << ": collision");
+              // we assume that no preamble is successfully received, hence no RAR is sent
+            }
+          else
+            {
+              uint16_t rnti = m_cmacSapUser->AllocateTemporaryCellRnti ();
+              NS_LOG_INFO ("preambleId " << (uint32_t) it->first << ": allocated T-C-RNTI " << (uint32_t) rnti << ", sending RAR");
+              RachListElement_s rachLe;
+              rachLe.m_rnti = rnti;
+              rachLe.m_estimatedSize = 144; // to be confirmed
+              rachInfoReqParams.m_rachList.push_back (rachLe);
+              RarLteControlMessage::Rar rar;
+              rar.rapId = it->first;
+              rar.rarPayload.m_rnti = rnti;
+              // no UL grant for now
+              rarMsg->AddRar (rar);
+            }
+        }
+      m_schedSapProvider->SchedDlRachInfoReq (rachInfoReqParams);
+      m_enbPhySapProvider->SendLteControlMessage (rarMsg);  
+      m_receivedRachPreambleCount.clear ();
+    }
 
   // Get downlink transmission opportunities
   uint32_t dlSchedFrameNo = m_frameNo;
@@ -525,28 +599,13 @@
 }
 
 void
-LteEnbMac::DoReceiveRachPreamble  (uint32_t prachId)
+LteEnbMac::DoReceiveRachPreamble  (uint8_t rapId)
 {
-  NS_LOG_FUNCTION (this << prachId);
-  uint16_t rnti = m_cmacSapUser->AllocateTemporaryCellRnti ();
-  
-  // todo: should trigger SCHED_DL_RACH_INFO_REQ here
-  // and then wait for DL_SCHEDULE_INDICATION to build the RARs from the RAR_List
-
-  // for now, we take a shortcut and just build the RAR here as an ideal message and without an UL grant
-
-  BuildRarListElement_s rar;
-  rar.m_rnti = rnti;
-  
-  Ptr<RarLteControlMessage> msg = Create<RarLteControlMessage> ();
-  msg->SetPrachId (prachId);
-  msg->SetRar (rar);
-  m_enbPhySapProvider->SendLteControlMessage (msg);
-  
+  NS_LOG_FUNCTION (this << rapId);
+  // just record that the preamble has been received; it will be processed later
+  ++m_receivedRachPreambleCount[rapId]; // will create entry if not exists
 }
 
-
-
 void
 LteEnbMac::DoUlCqiReport (FfMacSchedSapProvider::SchedUlCqiInfoReqParameters ulcqi)
 { 
@@ -725,6 +784,63 @@
   NS_FATAL_ERROR ("not implemented");
 }
 
+void
+LteEnbMac::DoUeUpdateConfigurationReq (LteEnbCmacSapProvider::UeConfig params)
+{
+  NS_LOG_FUNCTION (this);
+
+  // propagates to scheduler
+  FfMacCschedSapProvider::CschedUeConfigReqParameters req;
+  req.m_rnti = params.m_rnti;
+  req.m_transmissionMode = params.m_transmissionMode;
+  req.m_reconfigureFlag = true;
+  m_cschedSapProvider->CschedUeConfigReq (req);
+}
+
+LteEnbCmacSapProvider::RachConfig 
+LteEnbMac::DoGetRachConfig ()
+{
+  struct LteEnbCmacSapProvider::RachConfig rc;
+  rc.numberOfRaPreambles = m_numberOfRaPreambles;
+  rc.preambleTransMax = m_preambleTransMax;
+  rc.raResponseWindowSize = m_raResponseWindowSize;
+  return rc;
+}
+ 
+LteEnbCmacSapProvider::AllocateNcRaPreambleReturnValue 
+LteEnbMac::DoAllocateNcRaPreamble ()
+{
+  bool found = false;
+  uint8_t preambleId;
+  for (preambleId = m_numberOfRaPreambles; preambleId < 64; ++preambleId)
+    {
+      std::map<uint8_t, Time>::iterator it = m_allocatedNcRaPreambleMap.find (preambleId);
+      if ((it ==  m_allocatedNcRaPreambleMap.end ())
+          || (it->second < Simulator::Now ()))
+        {
+          found = true;
+          uint32_t expiryIntervalMs = (uint32_t) m_preambleTransMax * ((uint32_t) m_raResponseWindowSize + 5); 
+          Time expiryTime = Simulator::Now () + MilliSeconds (expiryIntervalMs);
+          m_allocatedNcRaPreambleMap[preambleId] = expiryTime; // create if not exist, update otherwise
+          break;
+        }
+    }
+  LteEnbCmacSapProvider::AllocateNcRaPreambleReturnValue ret;
+  if (found)
+    {
+      ret.valid = true;
+      ret.raPreambleId = preambleId;
+      ret.raPrachMaskIndex = 0;
+    }
+  else
+    {
+      ret.valid = false;
+      ret.raPreambleId = 0;
+      ret.raPrachMaskIndex = 0;
+    }
+  return ret;
+}
+
 
 
 // ////////////////////////////////////////////
@@ -902,19 +1018,6 @@
 }
 
 void
-LteEnbMac::DoUeUpdateConfigurationReq (LteEnbCmacSapProvider::UeConfig params)
-{
-  NS_LOG_FUNCTION (this);
-
-  // propagates to scheduler
-  FfMacCschedSapProvider::CschedUeConfigReqParameters req;
-  req.m_rnti = params.m_rnti;
-  req.m_transmissionMode = params.m_transmissionMode;
-  req.m_reconfigureFlag = true;
-  m_cschedSapProvider->CschedUeConfigReq (req);
-}
-
-void
 LteEnbMac::DoCschedCellConfigUpdateInd (FfMacCschedSapUser::CschedCellConfigUpdateIndParameters params)
 {
   NS_LOG_FUNCTION (this);
--- a/src/lte/model/lte-enb-mac.h	Wed Nov 14 16:05:54 2012 +0100
+++ b/src/lte/model/lte-enb-mac.h	Tue Nov 20 18:18:01 2012 +0100
@@ -147,6 +147,9 @@
   void DoAddLc (LteEnbCmacSapProvider::LcInfo lcinfo, LteMacSapUser* msu);
   void DoReconfigureLc (LteEnbCmacSapProvider::LcInfo lcinfo);
   void DoReleaseLc (uint16_t  rnti, uint8_t lcid);
+  void DoUeUpdateConfigurationReq (LteEnbCmacSapProvider::UeConfig params);
+  LteEnbCmacSapProvider::RachConfig DoGetRachConfig ();
+  LteEnbCmacSapProvider::AllocateNcRaPreambleReturnValue DoAllocateNcRaPreamble ();
 
   // forwarded from LteMacSapProvider
   void DoTransmitPdu (LteMacSapProvider::TransmitPduParameters);
@@ -165,12 +168,10 @@
   // forwarded from FfMacSchedSapUser
   void DoSchedDlConfigInd (FfMacSchedSapUser::SchedDlConfigIndParameters ind);
   void DoSchedUlConfigInd (FfMacSchedSapUser::SchedUlConfigIndParameters params);
-  
-  void DoUeUpdateConfigurationReq (LteEnbCmacSapProvider::UeConfig params);
 
   // forwarded from LteEnbPhySapUser
   void DoSubframeIndication (uint32_t frameNo, uint32_t subframeNo);
-  void DoReceiveRachPreamble (uint32_t prachId);
+  void DoReceiveRachPreamble (uint8_t prachId);
 
 public:
   // legacy public for use the Phy callback
@@ -222,7 +223,19 @@
   
   uint8_t m_macChTtiDelay; // delay of MAC, PHY and channel in terms of TTIs
   
+  uint8_t m_numberOfRaPreambles;
+  uint8_t m_preambleTransMax;
+  uint8_t m_raResponseWindowSize;
 
+  /**
+   * map storing as key the random acccess preamble IDs allocated for
+   * non-contention based access, and as value the expiration time of
+   * this allocation (so that stale preambles can be reused).
+   * 
+   */
+  std::map<uint8_t, Time> m_allocatedNcRaPreambleMap;
+ 
+  std::map<uint8_t, uint32_t> m_receivedRachPreambleCount;
 };
 
 } // end namespace ns3
--- a/src/lte/model/lte-enb-phy.cc	Wed Nov 14 16:05:54 2012 +0100
+++ b/src/lte/model/lte-enb-phy.cc	Tue Nov 20 18:18:01 2012 +0100
@@ -410,7 +410,7 @@
         case LteControlMessage::RACH_PREAMBLE:
           {
             Ptr<RachPreambleLteControlMessage> rachPreamble = DynamicCast<RachPreambleLteControlMessage> (*it);
-            m_enbPhySapUser->ReceiveRachPreamble (rachPreamble->GetPrachId ());
+            m_enbPhySapUser->ReceiveRachPreamble (rachPreamble->GetRapId ());
           }
           break;
           
--- a/src/lte/model/lte-enb-rrc.cc	Wed Nov 14 16:05:54 2012 +0100
+++ b/src/lte/model/lte-enb-rrc.cc	Tue Nov 20 18:18:01 2012 +0100
@@ -410,7 +410,7 @@
 }
 
 LteRrcSap::RrcConnectionReconfiguration 
-UeManager::GetHandoverCommand ()
+UeManager::GetRrcConnectionReconfigurationForHandover ()
 {
   NS_LOG_FUNCTION (this);
   return BuildRrcConnectionReconfiguration ();
@@ -509,6 +509,10 @@
     case CONNECTION_RECONFIGURATION:      
       SwitchToState (CONNECTED_NORMALLY);
       break;
+
+    case HANDOVER_LEAVING:      
+      NS_LOG_INFO ("ignoring RecvRrcConnectionReconfigurationCompleted in state " << ToString (m_state));
+      break;
       
     case HANDOVER_JOINING:
       NS_LOG_INFO ("Send UE CONTEXT RELEASE from target eNB to source eNB");
@@ -1118,6 +1122,8 @@
   NS_LOG_LOGIC ("oldEnbUeX2apId = " << params.oldEnbUeX2apId);
   NS_LOG_LOGIC ("sourceCellId = " << params.sourceCellId);
   NS_LOG_LOGIC ("targetCellId = " << params.targetCellId);
+
+  NS_ASSERT (params.targetCellId == m_cellId);
   
   uint16_t rnti = AddUe (UeManager::HANDOVER_JOINING);
   Ptr<UeManager> ueManager = GetUeManager (rnti);
@@ -1130,7 +1136,26 @@
       ueManager->SetupDataRadioBearer (it->erabLevelQosParameters, it->gtpTeid, it->transportLayerAddress);
     }
 
-  LteRrcSap::RrcConnectionReconfiguration handoverCommand = ueManager->GetHandoverCommand ();
+  LteRrcSap::RrcConnectionReconfiguration handoverCommand = ueManager->GetRrcConnectionReconfigurationForHandover ();
+  handoverCommand.haveMobilityControlInfo = true;
+  handoverCommand.mobilityControlInfo.targetPhysCellId = m_cellId;
+  handoverCommand.mobilityControlInfo.carrierFreq.dlCarrierFreq = m_dlEarfcn;
+  handoverCommand.mobilityControlInfo.carrierFreq.ulCarrierFreq = m_ulEarfcn;
+  handoverCommand.mobilityControlInfo.haveCarrierBandwidth = true;
+  handoverCommand.mobilityControlInfo.carrierBandwidth.dlBandwidth = m_dlBandwidth;
+  handoverCommand.mobilityControlInfo.carrierBandwidth.ulBandwidth = m_ulBandwidth;
+  handoverCommand.mobilityControlInfo.newUeIdentity = rnti;
+  LteEnbCmacSapProvider::AllocateNcRaPreambleReturnValue anrcrv = m_cmacSapProvider->AllocateNcRaPreamble ();
+  if (anrcrv.valid == true)
+    {
+      handoverCommand.mobilityControlInfo.haveRachConfigDedicated = true;
+      handoverCommand.mobilityControlInfo.rachConfigDedicated.raPreambleIndex = anrcrv.raPreambleId;
+      handoverCommand.mobilityControlInfo.rachConfigDedicated.raPrachMaskIndex = anrcrv.raPrachMaskIndex;
+    }
+  else
+    {
+      handoverCommand.mobilityControlInfo.haveRachConfigDedicated = false;      
+    }
   Ptr<Packet> encodedHandoverCommand = m_rrcSapUser->EncodeHandoverCommand (handoverCommand);
 
   NS_LOG_LOGIC ("Send X2 message: HANDOVER REQUEST ACK");
@@ -1440,6 +1465,14 @@
   si.haveSib2 = true;
   si.sib2.freqInfo.ulCarrierFreq = m_ulEarfcn;
   si.sib2.freqInfo.ulBandwidth = m_ulBandwidth;
+  
+  LteEnbCmacSapProvider::RachConfig rc = m_cmacSapProvider->GetRachConfig ();
+  LteRrcSap::RachConfigCommon rachConfigCommon;
+  rachConfigCommon.preambleInfo.numberOfRaPreambles = rc.numberOfRaPreambles;
+  rachConfigCommon.raSupervisionInfo.preambleTransMax = rc.preambleTransMax;
+  rachConfigCommon.raSupervisionInfo.raResponseWindowSize = rc.raResponseWindowSize;
+  si.sib2.radioResourceConfigCommon.rachConfigCommon = rachConfigCommon;
+
   m_rrcSapUser->SendSystemInformation (si);
   Simulator::Schedule (m_systemInformationPeriodicity, &LteEnbRrc::SendSystemInformation, this);
 }
--- a/src/lte/model/lte-enb-rrc.h	Wed Nov 14 16:05:54 2012 +0100
+++ b/src/lte/model/lte-enb-rrc.h	Tue Nov 20 18:18:01 2012 +0100
@@ -155,8 +155,11 @@
    * \return retrieve the data that the target eNB needs to send to the source
    * eNB as the Handover Command in the X2-based handover
    * procedure.
+   *
+   * \note mobility control info is not expected to be filled in
+   * (shall be filled in by the caller). 
    */
-  LteRrcSap::RrcConnectionReconfiguration GetHandoverCommand ();
+  LteRrcSap::RrcConnectionReconfiguration GetRrcConnectionReconfigurationForHandover ();
 
   /** 
    * Send a data packet over the appropriate Data Radio Bearer
@@ -548,7 +551,7 @@
   void DoRrcConfigurationUpdateInd (LteEnbCmacSapUser::UeConfig params);
   
 
-
+  // Internal methods
 
   /**
    * Allocate a new RNTI for a new UE. This is done in the following cases:
--- a/src/lte/model/lte-rrc-sap.h	Wed Nov 14 16:05:54 2012 +0100
+++ b/src/lte/model/lte-rrc-sap.h	Tue Nov 20 18:18:01 2012 +0100
@@ -136,12 +136,31 @@
     LogicalChannelConfig logicalChannelConfig;
   };
 
+  struct PreambleInfo
+  {
+    uint8_t numberOfRaPreambles;
+  };
+  
+  struct RaSupervisionInfo
+  {
+    uint8_t preambleTransMax;
+    uint8_t raResponseWindowSize;
+  };
+
+  struct RachConfigCommon
+  {
+    PreambleInfo preambleInfo;
+    RaSupervisionInfo raSupervisionInfo;
+  };
+
   struct RadioResourceConfigCommon
   {    
+    RachConfigCommon rachConfigCommon;
   };
 
   struct RadioResourceConfigCommonSib
   {    
+    RachConfigCommon rachConfigCommon;
   };
 
   struct RadioResourceConfigDedicated
--- a/src/lte/model/lte-ue-cmac-sap.h	Wed Nov 14 16:05:54 2012 +0100
+++ b/src/lte/model/lte-ue-cmac-sap.h	Tue Nov 20 18:18:01 2012 +0100
@@ -42,6 +42,15 @@
 public:
   virtual ~LteUeCmacSapProvider ();
 
+  struct RachConfig
+  {
+    uint8_t numberOfRaPreambles;
+    uint8_t preambleTransMax;
+    uint8_t raResponseWindowSize;
+  };
+  
+  virtual void ConfigureRach (RachConfig rc) = 0;
+
   /** 
    * tell the MAC to start a contention-based random access procedure,
    * e.g., to perform RRC connection establishment 
@@ -54,10 +63,10 @@
    * procedure, e.g., as a consequence of handover
    * 
    * \param rnti
-   * \param preambleId 
+   * \param rapId Random Access Preamble Identifier
    * \param prachMask 
    */
-  virtual void StartNonContentionBasedRandomAccessProcedure (uint16_t rnti, uint8_t preambleId, uint8_t prachMask) = 0;
+  virtual void StartNonContentionBasedRandomAccessProcedure (uint16_t rnti, uint8_t rapId, uint8_t prachMask) = 0;
 
 
   struct LogicalChannelConfig
--- a/src/lte/model/lte-ue-mac.cc	Wed Nov 14 16:05:54 2012 +0100
+++ b/src/lte/model/lte-ue-mac.cc	Tue Nov 20 18:18:01 2012 +0100
@@ -53,6 +53,7 @@
   UeMemberLteUeCmacSapProvider (LteUeMac* mac);
 
   // inherited from LteUeCmacSapProvider
+  virtual void ConfigureRach (RachConfig rc);
   virtual void StartContentionBasedRandomAccessProcedure ();
   virtual void StartNonContentionBasedRandomAccessProcedure (uint16_t rnti, uint8_t preambleId, uint8_t prachMask);
   virtual void AddLc (uint8_t lcId, LteUeCmacSapProvider::LogicalChannelConfig lcConfig, LteMacSapUser* msu);
@@ -69,6 +70,12 @@
 {
 }
 
+void 
+UeMemberLteUeCmacSapProvider::ConfigureRach (RachConfig rc)
+{
+  m_mac->DoConfigureRach (rc);
+}
+
   void 
 UeMemberLteUeCmacSapProvider::StartContentionBasedRandomAccessProcedure ()
 {
@@ -195,7 +202,9 @@
   :  m_bsrPeriodicity (MilliSeconds (1)), // ideal behavior
      m_bsrLast (MilliSeconds (0)),
      m_freshUlBsr (false),
-     m_rnti (0)
+     m_rnti (0),
+     m_rachConfigured (false),
+     m_waitingForRaResponse (false)
   
 {
   NS_LOG_FUNCTION (this);
@@ -336,15 +345,22 @@
 }
 
 void 
-LteUeMac::DoStartContentionBasedRandomAccessProcedure ()
+LteUeMac::RandomlySelectAndSendRaPreamble ()
 {
   NS_LOG_FUNCTION (this);
-  static uint32_t prachIdCounter = 256;
-  prachIdCounter += 2;
-  m_prachId = prachIdCounter;
-  NS_LOG_INFO ("sending RACH preamble " << m_prachId);
-
-
+  // 3GPP 36.321 5.1.1  
+  NS_ASSERT_MSG (m_rachConfigured, "RACH not configured");
+  UniformVariable uv;
+  // assume that there is no Random Access Preambles group B
+  m_raPreambleId = uv.GetInteger (0, m_rachConfig.numberOfRaPreambles - 1);
+  bool contention = true;
+  SendRaPreamble (contention);
+}
+   
+void
+LteUeMac::SendRaPreamble (bool contention)
+{
+  NS_LOG_FUNCTION (this << (uint32_t) m_raPreambleId << contention);
   // Since regular UL LteControlMessages need m_ulConfigured = true in
   // order to be sent by the UE, the rach preamble needs to be sent
   // with a dedicated primitive (not
@@ -352,23 +368,101 @@
   // bypass the m_ulConfigured flag. This is reasonable, since In fact
   // the RACH preamble is sent on 6RB bandwidth so the uplink
   // bandwidth does not need to be configured. 
+  m_uePhySapProvider->SendRachPreamble (m_raPreambleId);
+  NS_ASSERT (m_subframeNo > 0); // sanity check for subframe starting at 1
+  m_raRnti = m_subframeNo - 1;
+  NS_LOG_INFO (this << " sent preamble id " << (uint32_t) m_raPreambleId << ", RA-RNTI " << (uint32_t) m_raRnti);
+  // 3GPP 36.321 5.1.4 
+  Time raWindowBegin = MilliSeconds (3); 
+  Time raWindowEnd = MilliSeconds (3 + m_rachConfig.raResponseWindowSize);
+  Simulator::Schedule (raWindowBegin, &LteUeMac::StartWaitingForRaResponse, this);
+  m_noRaResponseReceivedEvent = Simulator::Schedule (raWindowEnd, &LteUeMac::RaResponseTimeout, this, contention);
+}
 
-  Ptr<RachPreambleLteControlMessage> msg = Create<RachPreambleLteControlMessage> ();
-  msg->SetPrachId (m_prachId);
-  m_uePhySapProvider->SendRachPreamble (m_prachId);
+void 
+LteUeMac::StartWaitingForRaResponse ()
+{
+   NS_LOG_FUNCTION (this);
+   m_waitingForRaResponse = true;
+}
+
+void 
+LteUeMac::RecvRaResponse (BuildRarListElement_s raResponse)
+{
+  NS_LOG_FUNCTION (this);
+  m_waitingForRaResponse = false;
+  m_noRaResponseReceivedEvent.Cancel ();
+  NS_LOG_INFO ("got RAR for RAPID " << (uint32_t) m_raPreambleId << ", setting T-C-RNTI = " << raResponse.m_rnti);
+  m_rnti = raResponse.m_rnti;
+  m_cmacSapUser->SetTemporaryCellRnti (m_rnti);
+  // in principle we should wait for contention resolution,
+  // but in the current LTE model when two or more identical
+  // preambles are sent no one is received, so there is no need
+  // for contention resolution
+  m_cmacSapUser->NotifyRandomAccessSuccessful ();
+}
+
+void 
+LteUeMac::RaResponseTimeout (bool contention)
+{
+  NS_LOG_FUNCTION (this << contention);
+  m_waitingForRaResponse = false;
+  // 3GPP 36.321 5.1.4
+  ++m_preambleTransmissionCounter;
+  if (m_preambleTransmissionCounter == m_rachConfig.preambleTransMax + 1)
+    {
+      NS_LOG_INFO ("RAR timeout, preambleTransMax reached => giving up");
+      m_cmacSapUser->NotifyRandomAccessFailed ();
+    }
+  else
+    {
+      NS_LOG_INFO ("RAR timeout, re-send preamble");
+      if (contention)
+        {
+          RandomlySelectAndSendRaPreamble ();
+        }
+      else
+        {
+          SendRaPreamble (contention);
+        }
+    }
+}
+
+void 
+LteUeMac::DoConfigureRach (LteUeCmacSapProvider::RachConfig rc)
+{
+  NS_LOG_FUNCTION (this);
+  m_rachConfig = rc;
+  m_rachConfigured = true;
+}
+
+void 
+LteUeMac::DoStartContentionBasedRandomAccessProcedure ()
+{
+  NS_LOG_FUNCTION (this);
+
+  // 3GPP 36.321 5.1.1
+  NS_ASSERT_MSG (m_rachConfigured, "RACH not configured");
+  m_preambleTransmissionCounter = 0;
+  m_backoffParameter = 0;
+  RandomlySelectAndSendRaPreamble ();
 }
 
 void 
 LteUeMac::DoStartNonContentionBasedRandomAccessProcedure (uint16_t rnti, uint8_t preambleId, uint8_t prachMask)
 {
   NS_LOG_FUNCTION (this << " rnti" << rnti);
+  NS_ASSERT_MSG (prachMask == 0, "requested PRACH MASK = " << (uint32_t) prachMask << ", but only PRACH MASK = 0 is supported");
   m_rnti = rnti;
+  m_raPreambleId = preambleId;
+  bool contention = false;
+  SendRaPreamble (contention);
 }
 
 void
 LteUeMac::DoAddLc (uint8_t lcId,  LteUeCmacSapProvider::LogicalChannelConfig lcConfig, LteMacSapUser* msu)
 {
-  NS_LOG_FUNCTION (this << " lcId" << (uint16_t) lcId);
+  NS_LOG_FUNCTION (this << " lcId" << (uint32_t) lcId);
   NS_ASSERT_MSG (m_lcInfoMap.find (lcId) == m_lcInfoMap.end (), "cannot add channel because LCID " << lcId << " is already present");
   
   LcInfo lcInfo;
@@ -403,6 +497,7 @@
           m_lcInfoMap.erase (it++);
         }
     }
+  m_rachConfigured = false;
 }
 
 void
@@ -450,7 +545,7 @@
           itBsr = m_ulBsrReceived.find ((*it).first);
           if (((itBsr!=m_ulBsrReceived.end ()) && ((*itBsr).second > 0)))
             {
-              NS_LOG_LOGIC (this << "\t" << bytesPerActiveLc << " bytes to LC " << (uint16_t)(*it).first << " queue " << (*itBsr).second);
+              NS_LOG_LOGIC (this << "\t" << bytesPerActiveLc << " bytes to LC " << (uint32_t)(*it).first << " queue " << (*itBsr).second);
               (*it).second.macSapUser->NotifyTxOpportunity (bytesPerActiveLc, 0);
               if ((*itBsr).second >=  static_cast<uint64_t> (bytesPerActiveLc))
                 {
@@ -466,20 +561,24 @@
     }
   else if (msg->GetMessageType () == LteControlMessage::RAR)
     {
-      Ptr<RarLteControlMessage> msg2 = DynamicCast<RarLteControlMessage> (msg);
-      
-      if (msg2->GetPrachId () == m_prachId)
+      if (m_waitingForRaResponse)
         {
-          m_rnti = msg2->GetRar ().m_rnti;
-          NS_LOG_INFO ("got RAR for PRACH ID " << m_prachId << ", setting T-C-RNTI = " << m_rnti);
-          m_cmacSapUser->SetTemporaryCellRnti (m_rnti);
-            
-          // in principle we should wait for contention resolution,
-          // but, since we don't model RACH PREAMBLE collisions, we
-          // just stop here
-          m_cmacSapUser->NotifyRandomAccessSuccessful ();
+          Ptr<RarLteControlMessage> rarMsg = DynamicCast<RarLteControlMessage> (msg);
+          uint16_t raRnti = rarMsg->GetRaRnti ();
+          NS_LOG_LOGIC (this << "got RAR with RA-RNTI " << (uint32_t) raRnti << ", expecting " << (uint32_t) m_raRnti);
+          if (raRnti == m_raRnti) // RAR corresponds to TX subframe of preamble
+            {
+              for (std::list<RarLteControlMessage::Rar>::const_iterator it = rarMsg->RarListBegin ();
+                   it != rarMsg->RarListEnd ();
+                   ++it)
+                {
+                  if (it->rapId == m_raPreambleId) // RAR is for me
+                    {
+                      RecvRaResponse (it->rarPayload);
+                    }
+                }
+            }
         }
-      // else the RAR is not for me
     }
   else
     {
@@ -492,6 +591,8 @@
 LteUeMac::DoSubframeIndication (uint32_t frameNo, uint32_t subframeNo)
 {
   NS_LOG_FUNCTION (this);
+  m_frameNo = frameNo;
+  m_subframeNo = subframeNo;
   if ((Simulator::Now () >= m_bsrLast + m_bsrPeriodicity) && (m_freshUlBsr==true))
     {
       SendReportBufferStatus ();
--- a/src/lte/model/lte-ue-mac.h	Wed Nov 14 16:05:54 2012 +0100
+++ b/src/lte/model/lte-ue-mac.h	Tue Nov 20 18:18:01 2012 +0100
@@ -30,7 +30,7 @@
 #include <ns3/lte-ue-cmac-sap.h>
 #include <ns3/lte-ue-phy-sap.h>
 #include <ns3/nstime.h>
-
+#include <ns3/event-id.h>
 
 namespace ns3 {
 
@@ -78,9 +78,9 @@
   void DoReportBufferStatus (LteMacSapProvider::ReportBufferStatusParameters params);
 
   // forwarded from UE CMAC SAP
-
+  void DoConfigureRach (LteUeCmacSapProvider::RachConfig rc);
   void DoStartContentionBasedRandomAccessProcedure ();
-  void DoStartNonContentionBasedRandomAccessProcedure (uint16_t rnti, uint8_t preambleId, uint8_t prachMask);
+  void DoStartNonContentionBasedRandomAccessProcedure (uint16_t rnti, uint8_t rapId, uint8_t prachMask);
   void DoAddLc (uint8_t lcId, LteUeCmacSapProvider::LogicalChannelConfig lcConfig, LteMacSapUser* msu);
   void DoRemoveLc (uint8_t lcId);
   void DoReset ();
@@ -89,6 +89,12 @@
   void DoReceivePhyPdu (Ptr<Packet> p);
   void DoReceiveLteControlMessage (Ptr<LteControlMessage> msg);
   
+  // internal methods
+  void RandomlySelectAndSendRaPreamble ();
+  void SendRaPreamble (bool contention);
+  void StartWaitingForRaResponse ();
+  void RecvRaResponse (BuildRarListElement_s raResponse);
+  void RaResponseTimeout (bool contention);
   void SendReportBufferStatus (void);
 
 private:
@@ -118,8 +124,17 @@
 
   uint16_t m_rnti;
 
-  uint32_t m_prachId;
+  bool m_rachConfigured;
+  LteUeCmacSapProvider::RachConfig m_rachConfig;
+  uint8_t m_raPreambleId;
+  uint8_t m_preambleTransmissionCounter;
+  uint16_t m_backoffParameter;
+  EventId m_noRaResponseReceivedEvent;
 
+  uint32_t m_frameNo;
+  uint32_t m_subframeNo;
+  uint8_t m_raRnti;
+  bool m_waitingForRaResponse;
 };
 
 } // namespace ns3
--- a/src/lte/model/lte-ue-phy.cc	Wed Nov 14 16:05:54 2012 +0100
+++ b/src/lte/model/lte-ue-phy.cc	Tue Nov 20 18:18:01 2012 +0100
@@ -512,13 +512,13 @@
 }
 
 void 
-LteUePhy::DoSendRachPreamble (uint32_t prachId)
+LteUePhy::DoSendRachPreamble (uint32_t raPreambleId)
 {
-  NS_LOG_FUNCTION (this << prachId);
+  NS_LOG_FUNCTION (this << raPreambleId);
 
   // unlike other control messages, RACH preamble is sent ASAP
   Ptr<RachPreambleLteControlMessage> msg = Create<RachPreambleLteControlMessage> ();
-  msg->SetPrachId (prachId);
+  msg->SetRapId (raPreambleId);
   m_controlMessagesQueue.at (0).push_back (msg);
 }
 
--- a/src/lte/model/lte-ue-rrc.cc	Wed Nov 14 16:05:54 2012 +0100
+++ b/src/lte/model/lte-ue-rrc.cc	Tue Nov 20 18:18:01 2012 +0100
@@ -527,6 +527,11 @@
       m_receivedSib2 = true;
       m_ulBandwidth = msg.sib2.freqInfo.ulBandwidth;
       m_ulEarfcn = msg.sib2.freqInfo.ulCarrierFreq;
+      LteUeCmacSapProvider::RachConfig rc;
+      rc.numberOfRaPreambles = msg.sib2.radioResourceConfigCommon.rachConfigCommon.preambleInfo.numberOfRaPreambles;
+      rc.preambleTransMax = msg.sib2.radioResourceConfigCommon.rachConfigCommon.raSupervisionInfo.preambleTransMax;
+      rc.raResponseWindowSize = msg.sib2.radioResourceConfigCommon.rachConfigCommon.raSupervisionInfo.raResponseWindowSize;
+      m_cmacSapProvider->ConfigureRach (rc);
       m_cphySapProvider->ConfigureUplink (m_ulEarfcn, m_ulBandwidth);
     }
   if (m_state == IDLE_WAIT_SYSTEM_INFO && m_receivedMib && m_receivedSib2)
@@ -572,6 +577,7 @@
         }      
       if (msg.haveMobilityControlInfo)
         {
+          NS_LOG_INFO ("haveMobilityControlInfo == true");
           SwitchToState (CONNECTED_HANDOVER);
           const LteRrcSap::MobilityControlInfo& mci = msg.mobilityControlInfo;
           m_cellId = mci.targetPhysCellId;
@@ -590,6 +596,7 @@
         }
       else
         {
+          NS_LOG_INFO ("haveMobilityControlInfo == false");
           LteRrcSap::RrcConnectionReconfigurationCompleted msg2;
           msg2.rrcTransactionIdentifier = msg.rrcTransactionIdentifier;
           m_rrcSapUser->SendRrcConnectionReconfigurationCompleted (msg2);
@@ -717,7 +724,7 @@
        dtamIt != rrcd.drbToAddModList.end ();
        ++dtamIt)
     {
-      NS_LOG_INFO (this << " IMSI " << m_imsi << " adding/modifying DRBID " << dtamIt->drbIdentity << " LC " << (uint32_t) dtamIt->logicalChannelIdentity);
+      NS_LOG_INFO (this << " IMSI " << m_imsi << " adding/modifying DRBID " << (uint32_t) dtamIt->drbIdentity << " LC " << (uint32_t) dtamIt->logicalChannelIdentity);
       NS_ASSERT_MSG (dtamIt->logicalChannelIdentity > 2, "LCID value " << dtamIt->logicalChannelIdentity << " is reserved for SRBs");
 
       std::map<uint8_t, Ptr<LteDataRadioBearerInfo> >::iterator drbMapIt = m_drbMap.find (dtamIt->drbIdentity);
--- a/src/lte/test/lte-test-pf-ff-mac-scheduler.cc	Wed Nov 14 16:05:54 2012 +0100
+++ b/src/lte/test/lte-test-pf-ff-mac-scheduler.cc	Tue Nov 20 18:18:01 2012 +0100
@@ -268,10 +268,10 @@
     }
 
 
-  double statsStartTime = 0.050; // need to allow for RRC connection establishment + SRS 
-  double statsDuration = 0.4;
+  double statsStartTime = 0.060; // need to allow for RRC connection establishment + SRS 
+  double statsDuration = 0.6;
   double tolerance = 0.1;
-  Simulator::Stop (Seconds (statsStartTime + statsDuration + 0.000001));
+  Simulator::Stop (Seconds (statsStartTime + statsDuration - 0.000001));
 
   lteHelper->EnableMacTraces ();
   Simulator::Schedule (Seconds (statsStartTime), &LteHelper::EnableRlcTraces, lteHelper);