LTE Automatic Neighbour Relation (ANR) function
authorBudiarto Herman <budiarto.herman@magister.fi>
Mon, 12 Aug 2013 11:25:23 +0300
changeset 10320 0fca10d6d044
parent 10319 8ae9c8866c5a
child 10321 5fe362c75d69
LTE Automatic Neighbour Relation (ANR) function
src/lte/helper/lte-helper.cc
src/lte/model/a2-rsrq-handover-algorithm.cc
src/lte/model/handover-management-sap.h
src/lte/model/lte-anr-sap.cc
src/lte/model/lte-anr-sap.h
src/lte/model/lte-anr.cc
src/lte/model/lte-anr.h
src/lte/model/lte-enb-net-device.cc
src/lte/model/lte-enb-net-device.h
src/lte/model/lte-enb-rrc.cc
src/lte/model/lte-enb-rrc.h
src/lte/wscript
--- a/src/lte/helper/lte-helper.cc	Mon Aug 12 09:29:23 2013 +0300
+++ b/src/lte/helper/lte-helper.cc	Mon Aug 12 11:25:23 2013 +0300
@@ -44,6 +44,7 @@
 #include <ns3/lte-ue-net-device.h>
 #include <ns3/ff-mac-scheduler.h>
 #include <ns3/handover-algorithm.h>
+#include <ns3/lte-anr.h>
 #include <ns3/lte-rlc.h>
 #include <ns3/lte-rlc-um.h>
 #include <ns3/lte-rlc-am.h>
@@ -391,6 +392,7 @@
   Ptr<LteEnbMac> mac = CreateObject<LteEnbMac> ();
   Ptr<FfMacScheduler> sched = m_schedulerFactory.Create<FfMacScheduler> ();
   Ptr<HandoverAlgorithm> handoverAlgorithm = m_handoverAlgorithmFactory.Create<HandoverAlgorithm> ();
+  Ptr<LteAnr> anr = CreateObject<LteAnr> ();
   Ptr<LteEnbRrc> rrc = CreateObject<LteEnbRrc> ();
 
   if (m_useIdealRrc)
@@ -428,6 +430,9 @@
   rrc->SetHandoverManagementSapProvider (handoverAlgorithm->GetHandoverManagementSapProvider ());
   handoverAlgorithm->SetHandoverManagementSapUser (rrc->GetHandoverManagementSapUser ());
 
+  rrc->SetLteAnrSapProvider (anr->GetLteAnrSapProvider ());
+  anr->SetLteAnrSapUser (rrc->GetLteAnrSapUser ());
+
   mac->SetFfMacSchedSapProvider (sched->GetFfMacSchedSapProvider ());
   mac->SetFfMacCschedSapProvider (sched->GetFfMacCschedSapProvider ());
 
@@ -437,7 +442,6 @@
   phy->SetLteEnbPhySapUser (mac->GetLteEnbPhySapUser ());
   mac->SetLteEnbPhySapProvider (phy->GetLteEnbPhySapProvider ());
 
-
   phy->SetLteEnbCphySapUser (rrc->GetLteEnbCphySapUser ());
   rrc->SetLteEnbCphySapProvider (phy->GetLteEnbCphySapProvider ());
 
@@ -449,6 +453,7 @@
   dev->SetAttribute ("FfMacScheduler", PointerValue (sched));
   dev->SetAttribute ("LteEnbRrc", PointerValue (rrc)); 
   dev->SetAttribute ("HandoverAlgorithm", PointerValue (handoverAlgorithm));
+  dev->SetAttribute ("LteAnr", PointerValue (anr));
 
   phy->SetDevice (dev);
   dlPhy->SetDevice (dev);
@@ -858,7 +863,7 @@
   uint16_t targetCellId = targetEnbDev->GetObject<LteEnbNetDevice> ()->GetCellId ();
   Ptr<LteEnbRrc> sourceRrc = sourceEnbDev->GetObject<LteEnbNetDevice> ()->GetRrc ();
   uint16_t rnti = ueDev->GetObject<LteUeNetDevice> ()->GetRrc ()->GetRnti ();
-  sourceRrc->SendHandoverRequest (rnti, targetCellId);  
+  sourceRrc->SendHandoverRequest (rnti, targetCellId);
 }
 
 
@@ -869,7 +874,7 @@
 LteHelper::ActivateDataRadioBearer (NetDeviceContainer ueDevices, EpsBearer bearer)
 {
   NS_LOG_FUNCTION (this);
-   for (NetDeviceContainer::Iterator i = ueDevices.Begin (); i != ueDevices.End (); ++i)
+  for (NetDeviceContainer::Iterator i = ueDevices.Begin (); i != ueDevices.End (); ++i)
     {
       ActivateDataRadioBearer (*i, bearer);
     }
--- a/src/lte/model/a2-rsrq-handover-algorithm.cc	Mon Aug 12 09:29:23 2013 +0300
+++ b/src/lte/model/a2-rsrq-handover-algorithm.cc	Mon Aug 12 11:25:23 2013 +0300
@@ -101,10 +101,11 @@
     .SetParent<HandoverAlgorithm> ()
     .AddConstructor<A2RsrqHandoverAlgorithm> ()
     .AddAttribute ("ServingCellThreshold",
-                   "If serving cell is worse than this threshold, neighbour cells are consider for Handover",
+                   "If the RSRQ of the serving cell is worse than this threshold, "
+                   "neighbour cells are consider for handover",
                    UintegerValue (30),
                    MakeUintegerAccessor (&A2RsrqHandoverAlgorithm::m_servingCellThreshold),
-                   MakeUintegerChecker<uint8_t> ())
+                   MakeUintegerChecker<uint8_t> (0, 34)) // RSRQ range is [0..34] as per Section 9.1.7 of 3GPP TS 36.133
     .AddAttribute ("NeighbourCellOffset",
                    "Minimum offset between serving and best neighbour cell to trigger the Handover",
                    UintegerValue (1),
@@ -142,7 +143,7 @@
   reportConfigA2.threshold1.range = m_servingCellThreshold;
   reportConfigA2.triggerQuantity = LteRrcSap::ReportConfigEutra::RSRQ;
   reportConfigA2.reportInterval = LteRrcSap::ReportConfigEutra::MS240;
-  m_a2measId = m_handoverManagementSapUser->AddUeMeasReportConfig (reportConfigA2);
+  m_a2measId = m_handoverManagementSapUser->AddUeMeasReportConfigForHandover (reportConfigA2);
 
   LteRrcSap::ReportConfigEutra reportConfigA4;
   reportConfigA4.eventId = LteRrcSap::ReportConfigEutra::EVENT_A4;
@@ -150,7 +151,7 @@
   reportConfigA4.threshold1.range = 0; // intentionally very low threshold
   reportConfigA4.triggerQuantity = LteRrcSap::ReportConfigEutra::RSRQ;
   reportConfigA4.reportInterval = LteRrcSap::ReportConfigEutra::MS480;
-  m_a4measId = m_handoverManagementSapUser->AddUeMeasReportConfig (reportConfigA4);
+  m_a4measId = m_handoverManagementSapUser->AddUeMeasReportConfigForHandover (reportConfigA4);
 
   HandoverAlgorithm::DoInitialize ();
 }
--- a/src/lte/model/handover-management-sap.h	Mon Aug 12 09:29:23 2013 +0300
+++ b/src/lte/model/handover-management-sap.h	Mon Aug 12 11:25:23 2013 +0300
@@ -42,8 +42,10 @@
    *             where the report originates from
    * \param measResults a single report of one measurement identity
    *
-   * The received measurement report may be stored and utilized for the purpose
-   * of making handover decision.
+   * The received measurement report is a result of the UE measurement
+   * configuration previously configured by calling
+   * HandoverManagementSapUser::AddUeMeasReportConfigForHandover. The report
+   * may be stored and utilized for the purpose of making handover decision.
    */
   virtual void ReportUeMeas (uint16_t rnti,
                              LteRrcSap::MeasResults measResults) = 0;
@@ -76,7 +78,7 @@
    *
    * This function is only valid before the simulation begins.
    */
-  virtual uint8_t AddUeMeasReportConfig (LteRrcSap::ReportConfigEutra reportConfig) = 0;
+  virtual uint8_t AddUeMeasReportConfigForHandover (LteRrcSap::ReportConfigEutra reportConfig) = 0;
 
   /**
    * \brief Instruct the eNodeB RRC entity to prepare a handover.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lte/model/lte-anr-sap.cc	Mon Aug 12 11:25:23 2013 +0300
@@ -0,0 +1,38 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013 University of Jyvaskyla
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Budiarto Herman <buherman@student.jyu.fi>
+ *
+ */
+
+#include "lte-anr-sap.h"
+
+
+namespace ns3 {
+
+
+LteAnrSapProvider::~LteAnrSapProvider ()
+{
+}
+
+
+LteAnrSapUser::~LteAnrSapUser ()
+{
+}
+
+
+} // end of namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lte/model/lte-anr-sap.h	Mon Aug 12 11:25:23 2013 +0300
@@ -0,0 +1,233 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013 University of Jyvaskyla
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Budiarto Herman <buherman@student.jyu.fi>
+ *
+ */
+
+#ifndef LTE_ANR_SAP_H
+#define LTE_ANR_SAP_H
+
+#include <ns3/lte-rrc-sap.h>
+
+namespace ns3 {
+
+
+/**
+ * \brief Service Access Point (SAP) offered by the Automatic Neighbour Relation
+ *        (ANR) function to the eNodeB RRC instance.
+ *
+ * This is the ANR SAP Provider, i.e., the part of the SAP that contains the ANR
+ * methods called by the eNodeB RRC.
+ */
+class LteAnrSapProvider
+{
+public:
+  virtual ~LteAnrSapProvider ();
+
+  /**
+   * \brief Send a UE measurement report to the ANC instance.
+   * \param measResults a single report of one measurement identity
+   *
+   * The received measurement report is a result of the UE measurement
+   * configuration previously configured by calling
+   * LteAnrSapUser::AddUeMeasReportConfigForAnr. The report may be stored and
+   * utilized for the purpose of maintaining Neighbour Relation Table (NRT).
+   */
+  virtual void ReportUeMeas (LteRrcSap::MeasResults measResults) = 0;
+
+  /**
+   * \brief Add a new Neighbour Relation entry.
+   * \param cellId the Physical Cell ID of the new neighbouring cell
+   */
+  virtual void AddNeighbourRelation (uint16_t cellId) = 0;
+
+  /**
+   * \brief Get the value of *No Remove* field of a neighbouring cell from the
+   *        Neighbour Relation Table (NRT).
+   * \param cellId the Physical Cell ID of the neighbouring cell of interest
+   * \return if true, the Neighbour Relation shall *not* be removed from the NRT
+   */
+  virtual bool GetNoRemove (uint16_t cellId) = 0;
+
+  /**
+   * \brief Get the value of *No HO* field of a neighbouring cell from the
+   *        Neighbour Relation Table (NRT).
+   * \param cellId the Physical Cell ID of the neighbouring cell of interest
+   * \return if true, the Neighbour Relation shall *not* be used by the eNodeB
+   *         for handover reasons
+   */
+  virtual bool GetNoHo (uint16_t cellId) = 0;
+
+  /**
+   * \brief Get the value of *No X2* field of a neighbouring cell from the
+   *        Neighbour Relation Table (NRT).
+   * \param cellId the Physical Cell ID of the neighbouring cell of interest
+   * \return if true, the Neighbour Relation shall *not* use an X2 interface in
+   *         order to initiate procedures towards the eNodeB parenting the
+   *         target cell
+   */
+  virtual bool GetNoX2 (uint16_t cellId) = 0;
+
+}; // end of class LteAnrSapProvider
+
+
+
+/**
+ * \brief Service Access Point (SAP) offered by the eNodeB RRC instance to the
+ *        Automatic Neighbour Relation (ANR) function.
+ *
+ * This is the ANR SAP User, i.e., the part of the SAP that contains the eNodeB
+ * RRC methods called by the ANR.
+ */
+class LteAnrSapUser
+{
+public:
+  virtual ~LteAnrSapUser ();
+
+  /**
+   * \brief Request a certain reporting configuration to be fulfilled by the UEs
+   *        attached to the eNodeB entity.
+   * \param reportConfig the UE measurement reporting configuration
+   * \return the measurement identity associated with this newly added
+   *         reporting configuration
+   *
+   * The eNodeB RRC entity is expected to configure the same reporting
+   * configuration in each of the attached UEs. When later in the simulation a
+   * UE measurement report is received from a UE as a result of this
+   * configuration, the eNodeB RRC entity shall forward this report to the ANC
+   * instance through the LteAnrSapProvider::ReportUeMeas SAP function.
+   *
+   * This function is only valid before the simulation begins.
+   */
+  virtual uint8_t AddUeMeasReportConfigForAnr (LteRrcSap::ReportConfigEutra reportConfig) = 0;
+
+}; // end of class LteAnrSapUser
+
+
+
+/**
+ * \brief Template for the implementation of the LteAnrSapProvider as a member
+ *        of an owner class of type C to which all methods are forwarded.
+ */
+template <class C>
+class MemberLteAnrSapProvider : public LteAnrSapProvider
+{
+public:
+  MemberLteAnrSapProvider (C* owner);
+
+  // inherited from LteAnrSapProvider
+  virtual void ReportUeMeas (LteRrcSap::MeasResults measResults);
+  virtual void AddNeighbourRelation (uint16_t cellId);
+  virtual bool GetNoRemove (uint16_t cellId);
+  virtual bool GetNoHo (uint16_t cellId);
+  virtual bool GetNoX2 (uint16_t cellId);
+
+private:
+  MemberLteAnrSapProvider ();
+  C* m_owner;
+
+}; // end of class MemberLteAnrSapProvider
+
+
+template <class C>
+MemberLteAnrSapProvider<C>::MemberLteAnrSapProvider (C* owner)
+  : m_owner (owner)
+{
+}
+
+
+template <class C>
+void
+MemberLteAnrSapProvider<C>::ReportUeMeas (LteRrcSap::MeasResults measResults)
+{
+  m_owner->DoReportUeMeas (measResults);
+}
+
+
+template <class C>
+void
+MemberLteAnrSapProvider<C>::AddNeighbourRelation (uint16_t cellId)
+{
+  m_owner->DoAddNeighbourRelation (cellId);
+}
+
+
+template <class C>
+bool
+MemberLteAnrSapProvider<C>::GetNoRemove (uint16_t cellId)
+{
+  return m_owner->DoGetNoRemove (cellId);
+}
+
+
+template <class C>
+bool
+MemberLteAnrSapProvider<C>::GetNoHo (uint16_t cellId)
+{
+  return m_owner->DoGetNoHo (cellId);
+}
+
+
+template <class C>
+bool
+MemberLteAnrSapProvider<C>::GetNoX2 (uint16_t cellId)
+{
+  return m_owner->DoGetNoX2 (cellId);
+}
+
+
+
+/**
+ * \brief Template for the implementation of the LteAnrSapUser as a member of an
+ *        owner class of type C to which all methods are forwarded.
+ */
+template <class C>
+class MemberLteAnrSapUser : public LteAnrSapUser
+{
+public:
+  MemberLteAnrSapUser (C* owner);
+
+  // inherited from LteAnrSapUser
+  virtual uint8_t AddUeMeasReportConfigForAnr (LteRrcSap::ReportConfigEutra reportConfig);
+
+private:
+  MemberLteAnrSapUser ();
+  C* m_owner;
+
+}; // end of class MemberLteAnrSapUser
+
+
+template <class C>
+MemberLteAnrSapUser<C>::MemberLteAnrSapUser (C* owner)
+  : m_owner (owner)
+{
+}
+
+
+template <class C>
+uint8_t
+MemberLteAnrSapUser<C>::AddUeMeasReportConfigForAnr (LteRrcSap::ReportConfigEutra reportConfig)
+{
+  return m_owner->DoAddUeMeasReportConfigForAnr (reportConfig);
+}
+
+
+} // end of namespace ns3
+
+
+#endif /* LTE_ANR_SAP_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lte/model/lte-anr.cc	Mon Aug 12 11:25:23 2013 +0300
@@ -0,0 +1,236 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013 University of Jyvaskyla
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Budiarto Herman <buherman@student.jyu.fi>
+ *
+ */
+
+#include "lte-anr.h"
+#include <ns3/log.h>
+#include <ns3/uinteger.h>
+
+NS_LOG_COMPONENT_DEFINE ("LteAnr");
+
+namespace ns3 {
+
+NS_OBJECT_ENSURE_REGISTERED (LteAnr);
+
+
+LteAnr::LteAnr ()
+  : m_anrSapUser (0),
+    m_threshold (0),
+    m_measId (0)
+{
+  m_anrSapProvider = new MemberLteAnrSapProvider<LteAnr> (this);
+}
+
+
+LteAnr::~LteAnr ()
+{
+}
+
+
+void
+LteAnr::DoDispose ()
+{
+  delete m_anrSapProvider;
+  m_neighbourRelationTable.clear ();
+}
+
+
+TypeId
+LteAnr::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::LteAnr")
+    .SetParent<Object> ()
+    .AddConstructor<LteAnr> ()
+    .AddAttribute ("Threshold",
+                   "Minimum RSRQ range value required for detecting a neighbour cell",
+                   UintegerValue (0),
+                   MakeUintegerAccessor (&LteAnr::m_threshold),
+                   MakeUintegerChecker<uint8_t> (0, 34)) // RSRQ range is [0..34] as per Section 9.1.7 of 3GPP TS 36.133
+  ;
+  return tid;
+}
+
+
+void
+LteAnr::AddNeighbourRelation (uint16_t cellId)
+{
+  NS_LOG_FUNCTION (this << cellId);
+
+  if (m_neighbourRelationTable.find (cellId) != m_neighbourRelationTable.end ())
+    {
+      NS_FATAL_ERROR ("There is already an entry in the NRT for cell ID " << cellId);
+    }
+
+  NeighbourRelation_t neighbourRelation;
+  neighbourRelation.noRemove = true;
+  neighbourRelation.noHo = true;
+  neighbourRelation.noX2 = false;
+  neighbourRelation.detectedAsNeighbour = false;
+  m_neighbourRelationTable[cellId] = neighbourRelation;
+}
+
+
+void
+LteAnr::RemoveNeighbourRelation (uint16_t cellId)
+{
+  NS_LOG_FUNCTION (this << cellId);
+
+  NeighbourRelationTable_t::iterator it = m_neighbourRelationTable.find (cellId);
+  if (it != m_neighbourRelationTable.end ())
+    {
+      NS_FATAL_ERROR ("Cell ID " << cellId << " cannot be found in NRT");
+    }
+
+  m_neighbourRelationTable.erase (it);
+}
+
+
+void
+LteAnr::SetLteAnrSapUser (LteAnrSapUser* s)
+{
+  m_anrSapUser = s;
+}
+
+
+LteAnrSapProvider*
+LteAnr::GetLteAnrSapProvider ()
+{
+  return m_anrSapProvider;
+}
+
+
+void
+LteAnr::DoInitialize ()
+{
+  LteRrcSap::ReportConfigEutra reportConfig;
+  reportConfig.eventId = LteRrcSap::ReportConfigEutra::EVENT_A4;
+  reportConfig.threshold1.choice = LteRrcSap::ThresholdEutra::THRESHOLD_RSRQ;
+  reportConfig.threshold1.range = m_threshold;
+  reportConfig.triggerQuantity = LteRrcSap::ReportConfigEutra::RSRQ;
+  reportConfig.reportInterval = LteRrcSap::ReportConfigEutra::MS480;
+  m_measId = m_anrSapUser->AddUeMeasReportConfigForAnr (reportConfig);
+}
+
+
+void
+LteAnr::DoReportUeMeas (LteRrcSap::MeasResults measResults)
+{
+  uint8_t measId = measResults.measId;
+  NS_LOG_FUNCTION (this << (uint16_t) measId);
+
+  if (measId != m_measId)
+    {
+      NS_LOG_WARN (this << " Skipping unexpected measurement identity " << (uint16_t) measId);
+    }
+  else
+    {
+      if (measResults.haveMeasResultNeighCells
+          && !(measResults.measResultListEutra.empty ()))
+        {
+          for (std::list <LteRrcSap::MeasResultEutra>::iterator it = measResults.measResultListEutra.begin ();
+               it != measResults.measResultListEutra.end ();
+               ++it)
+            {
+              // Keep new RSRQ value reported for the neighbour cell
+              NS_ASSERT_MSG (it->haveRsrqResult == true,
+                             "RSRQ measure missing for cellId " << it->physCellId);
+
+              // Update Neighbour Relation Table
+              if (m_neighbourRelationTable.find (it->physCellId) != m_neighbourRelationTable.end ())
+                {
+                  // Update neighbour info
+                  NeighbourRelation_t neighbourRelation = m_neighbourRelationTable[it->physCellId];
+
+                  if (neighbourRelation.noX2 == false)
+                    {
+                      neighbourRelation.noHo = false;
+                    }
+                  neighbourRelation.detectedAsNeighbour = true;
+                }
+              else // new neighbour
+                {
+                  NeighbourRelation_t neighbourRelation;
+                  neighbourRelation.noRemove = false;
+                  neighbourRelation.noHo = true;
+                  neighbourRelation.noX2 = true;
+                  neighbourRelation.detectedAsNeighbour = true;
+                  m_neighbourRelationTable[it->physCellId] = neighbourRelation;
+                }
+
+            } // end of for (it = measResults.measResultListEutra.begin ())
+
+        } // end of if (measResults.haveMeasResultNeighCells && !(measResults.measResultListEutra.empty ()))
+      else
+        {
+          NS_LOG_LOGIC ("WARNING");
+          // NS_ASSERT_MSG ("Event A4 received without measure results for neighbour cells");
+          // TODO Remove neighbours in the neighbourCellMeasures table
+        }
+
+    } // end of else of if (measId != m_measId)
+
+} // end of DoReportUeMeas
+
+
+void
+LteAnr::DoAddNeighbourRelation (uint16_t cellId)
+{
+  AddNeighbourRelation (cellId);
+}
+
+
+bool
+LteAnr::DoGetNoRemove (uint16_t cellId)
+{
+  NS_LOG_FUNCTION (this << cellId);
+  return Find (cellId)->noRemove;
+}
+
+
+bool
+LteAnr::DoGetNoHo (uint16_t cellId)
+{
+  NS_LOG_FUNCTION (this << cellId);
+  return Find (cellId)->noHo;
+}
+
+
+bool
+LteAnr::DoGetNoX2 (uint16_t cellId)
+{
+  NS_LOG_FUNCTION (this << cellId);
+  return Find (cellId)->noX2;
+}
+
+
+LteAnr::NeighbourRelation_t *
+LteAnr::Find (uint16_t cellId)
+{
+  NeighbourRelationTable_t::iterator it = m_neighbourRelationTable.find (cellId);
+  if (it == m_neighbourRelationTable.end ())
+    {
+      NS_FATAL_ERROR ("Cell ID " << cellId << " cannot be found in NRT");
+    }
+  return &(it->second);
+}
+
+
+} // end of namespace ns3
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lte/model/lte-anr.h	Mon Aug 12 11:25:23 2013 +0300
@@ -0,0 +1,140 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013 University of Jyvaskyla
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Budiarto Herman <buherman@student.jyu.fi>
+ *
+ */
+
+#ifndef LTE_ANR_H
+#define LTE_ANR_H
+
+#include <ns3/object.h>
+#include <ns3/lte-rrc-sap.h>
+#include <ns3/lte-anr-sap.h>
+#include <map>
+
+namespace ns3 {
+
+
+class LteAnrSapProvider;
+class LteAnrSapUser;
+class LteNeighbourRelation;
+
+/**
+ * \brief Automatic Neighbour Relation function.
+ *
+ * Based on Section 22.3.2a and 22.3.3 of 3GPP TS 36.300.
+ */
+class LteAnr : public Object
+{
+public:
+  LteAnr ();
+  virtual ~LteAnr ();
+
+  // inherited from Object
+  virtual void DoDispose (void);
+  static TypeId GetTypeId (void);
+
+  /**
+   * \brief Provide an advance information about a related neighbouring cell
+   *        and add it as a new Neighbour Relation entry.
+   *
+   * This function simulates the Neighbour Relation addition operation by
+   * network operations and maintenance, as depicted in Section 22.3.2a of
+   * 3GPP TS 36.300.
+   *
+   * An entry added by this function will have NoRemove flag set to TRUE and
+   * NoHo flag set to TRUE. Hence, the cell may not act as the targel cell of a
+   * handover, unless a measurement report of the cell is received, which will
+   * update the NoHo flag to FALSE.
+   */
+  void AddNeighbourRelation (uint16_t cellId);
+
+  /**
+   * \brief Remove an existing Neighbour Relation entry.
+   *
+   * This function simulates the Neighbour Relation removal operation by
+   * network operations and maintenance, as depicted in Section 22.3.2a of
+   * 3GPP TS 36.300.
+   */
+  void RemoveNeighbourRelation (uint16_t cellId);
+
+  /**
+   * \brief Set the user part of the LteAnrSap that this ANR instance will
+   *        interact with. Normally this part of the SAP is exported by the
+   *        eNodeB RRC.
+   * \param s
+   */
+  virtual void SetLteAnrSapUser (LteAnrSapUser* s);
+
+  /**
+   *
+   * \return the Provider part of the LteAnrSap provided by the ANR instance
+   */
+  virtual LteAnrSapProvider* GetLteAnrSapProvider ();
+
+  friend class MemberLteAnrSapProvider<LteAnr>;
+
+protected:
+  // inherited from Object
+  virtual void DoInitialize ();
+
+private:
+  // ANR SAP provider implementation
+  void DoReportUeMeas (LteRrcSap::MeasResults measResults);
+  void DoAddNeighbourRelation (uint16_t cellId);
+  bool DoGetNoRemove (uint16_t cellId);
+  bool DoGetNoHo (uint16_t cellId);
+  bool DoGetNoX2 (uint16_t cellId);
+
+  // ANR SAPs
+  LteAnrSapUser* m_anrSapUser;
+  LteAnrSapProvider* m_anrSapProvider;
+
+  // Class Attributes
+  uint8_t m_threshold;
+
+  /**
+   * \brief Neighbour Relation between two eNodeBs (serving eNodeB and neighbour
+   *        eNodeB).
+   */
+  struct NeighbourRelation_t
+  {
+    bool noRemove;
+    bool noHo;
+    bool noX2;
+    bool detectedAsNeighbour;
+  };
+
+  //               cellId
+  typedef std::map<uint16_t, NeighbourRelation_t> NeighbourRelationTable_t;
+
+  NeighbourRelationTable_t m_neighbourRelationTable;
+
+  // internal methods
+  NeighbourRelation_t* Find (uint16_t cellId);
+
+  // The expected measurement identity
+  uint8_t m_measId;
+
+}; // end of class LteAnr
+
+
+} // end of namespace ns3
+
+
+#endif /* LTE_ANR_H */
--- a/src/lte/model/lte-enb-net-device.cc	Mon Aug 12 09:29:23 2013 +0300
+++ b/src/lte/model/lte-enb-net-device.cc	Mon Aug 12 11:25:23 2013 +0300
@@ -39,6 +39,7 @@
 #include <ns3/lte-enb-phy.h>
 #include <ns3/ff-mac-scheduler.h>
 #include <ns3/handover-algorithm.h>
+#include <ns3/lte-anr.h>
 #include <ns3/ipv4-l3-protocol.h>
 #include <ns3/abort.h>
 #include <ns3/log.h>
@@ -66,6 +67,11 @@
                    PointerValue (),
                    MakePointerAccessor (&LteEnbNetDevice::m_handoverAlgorithm),
                    MakePointerChecker <HandoverAlgorithm> ())
+    .AddAttribute ("LteAnr",
+                   "The automatic neighbour relation function associated to this EnbNetDevice",
+                   PointerValue (),
+                   MakePointerAccessor (&LteEnbNetDevice::m_anr),
+                   MakePointerChecker <LteAnr> ())
     .AddAttribute ("LteEnbMac",
                    "The MAC associated to this EnbNetDevice",
                    PointerValue (),
--- a/src/lte/model/lte-enb-net-device.h	Mon Aug 12 09:29:23 2013 +0300
+++ b/src/lte/model/lte-enb-net-device.h	Mon Aug 12 11:25:23 2013 +0300
@@ -41,6 +41,7 @@
 class LteEnbRrc;
 class FfMacScheduler;
 class HandoverAlgorithm;
+class LteAnr;
 
 
 /**
@@ -149,6 +150,8 @@
 
   Ptr<HandoverAlgorithm> m_handoverAlgorithm;
 
+  Ptr<LteAnr> m_anr;
+
   uint16_t m_cellId; /**< Cell Identifer. Part of the CGI, see TS 29.274, section 8.21.1  */
 
   uint8_t m_dlBandwidth; /**< downlink bandwidth in RBs */
--- a/src/lte/model/lte-enb-rrc.cc	Mon Aug 12 09:29:23 2013 +0300
+++ b/src/lte/model/lte-enb-rrc.cc	Mon Aug 12 11:25:23 2013 +0300
@@ -113,7 +113,7 @@
   EnbRrcMemberHandoverManagementSapUser (LteEnbRrc* rrc);
 
   // methods inherited from HandoverManagementSapUser go here
-  virtual uint8_t AddUeMeasReportConfig (LteRrcSap::ReportConfigEutra reportConfig);
+  virtual uint8_t AddUeMeasReportConfigForHandover (LteRrcSap::ReportConfigEutra reportConfig);
   virtual void TriggerHandover (uint16_t rnti, uint16_t targetCellId);
 
 private:
@@ -126,9 +126,9 @@
 }
 
 uint8_t
-EnbRrcMemberHandoverManagementSapUser::AddUeMeasReportConfig (LteRrcSap::ReportConfigEutra reportConfig)
+EnbRrcMemberHandoverManagementSapUser::AddUeMeasReportConfigForHandover (LteRrcSap::ReportConfigEutra reportConfig)
 {
-  return m_rrc->DoAddUeMeasReportConfig (reportConfig);
+  return m_rrc->DoAddUeMeasReportConfigForHandover (reportConfig);
 }
 
 void
@@ -140,6 +140,11 @@
 
 
 
+///////////////////////////////////////////
+// UeManager
+///////////////////////////////////////////
+
+
 const char* g_ueManagerStateName[UeManager::NUM_STATES] = 
 {
   "INITIAL_RANDOM_ACCESS",
@@ -160,12 +165,6 @@
 }
 
 
-
-///////////////////////////////////////////
-// UeManager 
-///////////////////////////////////////////
-
-
 NS_OBJECT_ENSURE_REGISTERED (UeManager);
 
 
@@ -971,8 +970,9 @@
 void 
 UeManager::RecvMeasurementReport (LteRrcSap::MeasurementReport msg)
 {
-  NS_LOG_FUNCTION (this);
-  NS_LOG_LOGIC ("measId " << (uint16_t) msg.measResults.measId
+  uint8_t measId = msg.measResults.measId;
+  NS_LOG_FUNCTION (this << (uint16_t) measId);
+  NS_LOG_LOGIC ("measId " << (uint16_t) measId
                 << " haveMeasResultNeighCells " << msg.measResults.haveMeasResultNeighCells
                 << " measResultListEutra " << msg.measResults.measResultListEutra.size ());
   NS_LOG_LOGIC ("serving cellId " << m_rrc->m_cellId
@@ -988,57 +988,18 @@
                     << " RSRQ " << (it->haveRsrqResult ? (uint16_t) it->rsrqResult : 255));
     }
 
-  /// Event A4 (Neighbour becomes better than threshold)
-  if (msg.measResults.measId == 2) // TODO remove this hardcode
+  if (m_rrc->m_handoverMeasIds.find (measId) != m_rrc->m_handoverMeasIds.end ())
     {
-      // Update the NRT
-      if (msg.measResults.haveMeasResultNeighCells
-          && !(msg.measResults.measResultListEutra.empty ()))
-        {
-          for (std::list <LteRrcSap::MeasResultEutra>::iterator it = msg.measResults.measResultListEutra.begin ();
-               it != msg.measResults.measResultListEutra.end ();
-               ++it)
-            {
-              // Keep new RSRQ value reported for the neighbour cell
-              NS_ASSERT_MSG (it->haveRsrqResult == true, "RSRQ measure missing for cellId " << it->physCellId);
-
-              // Update Neighbour Relation Table
-              if (m_rrc->m_neighbourRelationTable.find (it->physCellId) != m_rrc->m_neighbourRelationTable.end ())
-                {
-                  // Update neighbour info
-                  Ptr<NeighbourRelation> neighbourRelation = m_rrc->m_neighbourRelationTable[it->physCellId];
-                  NS_ASSERT_MSG (neighbourRelation->m_physCellId == it->physCellId,
-                                 "Wrong cellId " << neighbourRelation->m_physCellId);
-
-                  if (neighbourRelation->m_noX2 == false)
-                    {
-                      neighbourRelation->m_noHo = false;
-                    }
-                  neighbourRelation->m_detectedAsNeighbour = true;
-                }
-              else // new neighbour
-                {
-                  Ptr<NeighbourRelation> neighbourRelation = CreateObject <NeighbourRelation> ();
-                  neighbourRelation->m_physCellId = it->physCellId;
-                  neighbourRelation->m_noRemove = false;
-                  neighbourRelation->m_noHo = true;
-                  neighbourRelation->m_noX2 = true;
-                  neighbourRelation->m_detectedAsNeighbour = true;
-                  m_rrc->m_neighbourRelationTable[it->physCellId] = neighbourRelation;
-                }
-            }
-        }
-      else
-        {
-          NS_LOG_LOGIC ("WARNING");
-          // NS_ASSERT_MSG ("Event A4 received without measure results for neighbour cells");
-          // TODO Remove neighbours in the neighbourCellMeasures table
-        }
+      // this measurement was requested by the handover algorithm
+      m_rrc->m_handoverManagementSapProvider->ReportUeMeas (m_rnti,
+                                                            msg.measResults);
     }
 
-  // forward the UE measurements report to the active handover algorithm
-  m_rrc->m_handoverManagementSapProvider->ReportUeMeas (m_rnti,
-                                                        msg.measResults);
+  if (m_rrc->m_anrMeasIds.find (measId) != m_rrc->m_anrMeasIds.end ())
+    {
+      // this measurement was requested by the ANR function
+      m_rrc->m_anrSapProvider->ReportUeMeas (msg.measResults);
+    }
 
   // fire a trace source
   m_rrc->m_recvMeasurementReportTrace (m_imsi, m_rrc->m_cellId, m_rnti, msg);
@@ -1312,6 +1273,7 @@
   : m_x2SapProvider (0),
     m_cmacSapProvider (0),
     m_handoverManagementSapProvider (0),
+    m_anrSapProvider (0),
     m_rrcSapUser (0),
     m_macSapProvider (0),
     m_s1SapProvider (0),
@@ -1325,6 +1287,7 @@
   NS_LOG_FUNCTION (this);
   m_cmacSapUser = new EnbRrcMemberLteEnbCmacSapUser (this);
   m_handoverManagementSapUser = new EnbRrcMemberHandoverManagementSapUser (this);
+  m_anrSapUser = new MemberLteAnrSapUser<LteEnbRrc> (this);
   m_rrcSapProvider = new MemberLteEnbRrcSapProvider<LteEnbRrc> (this);
   m_x2SapUser = new EpcX2SpecificEpcX2SapUser<LteEnbRrc> (this);
   m_s1SapUser = new MemberEpcEnbS1SapUser<LteEnbRrc> (this);
@@ -1345,6 +1308,7 @@
   m_ueMap.clear ();
   delete m_cmacSapUser;
   delete m_handoverManagementSapUser;
+  delete m_anrSapUser;
   delete m_rrcSapProvider;
   delete m_x2SapUser;
   delete m_s1SapUser;
@@ -1507,6 +1471,20 @@
 }
 
 void
+LteEnbRrc::SetLteAnrSapProvider (LteAnrSapProvider * s)
+{
+  NS_LOG_FUNCTION (this << s);
+  m_anrSapProvider = s;
+}
+
+LteAnrSapUser*
+LteEnbRrc::GetLteAnrSapUser ()
+{
+  NS_LOG_FUNCTION (this);
+  return m_anrSapUser;
+}
+
+void
 LteEnbRrc::SetLteEnbRrcSapUser (LteEnbRrcSapUser * s)
 {
   NS_LOG_FUNCTION (this << s);
@@ -2033,10 +2011,12 @@
 
 
 uint8_t
-LteEnbRrc::DoAddUeMeasReportConfig (LteRrcSap::ReportConfigEutra reportConfig)
+LteEnbRrc::DoAddUeMeasReportConfigForHandover (LteRrcSap::ReportConfigEutra reportConfig)
 {
   NS_LOG_FUNCTION (this);
-  return AddUeMeasReportConfig (reportConfig);
+  uint8_t measId = AddUeMeasReportConfig (reportConfig);
+  m_handoverMeasIds.insert (measId);
+  return measId;
 }
 
 void
@@ -2044,18 +2024,23 @@
 {
   NS_LOG_FUNCTION (this << rnti << targetCellId);
 
-  std::map<uint16_t, Ptr<NeighbourRelation> >::iterator it;
-  it = m_neighbourRelationTable.find (targetCellId);
-  NS_ASSERT_MSG (it != m_neighbourRelationTable.end (),
-                 "Unable to find neighbouring cell with cell ID " << targetCellId);
-
   // ensure that proper neighbour relationship exists between source and target cells
-  if ((it->second->m_noHo == false) && (it->second->m_noX2 == false))
-   {
+  if ((m_anrSapProvider->GetNoHo (targetCellId) == false)
+      && (m_anrSapProvider->GetNoX2 (targetCellId) == false))
+    {
       Ptr<UeManager> ueManager = GetUeManager (rnti);
       NS_ASSERT_MSG (ueManager != 0, "Cannot find UE context with RNTI " << rnti);
       ueManager->PrepareHandover (targetCellId);
-   }
+    }
+}
+
+uint8_t
+LteEnbRrc::DoAddUeMeasReportConfigForAnr (LteRrcSap::ReportConfigEutra reportConfig)
+{
+  NS_LOG_FUNCTION (this);
+  uint8_t measId = AddUeMeasReportConfig (reportConfig);
+  m_anrMeasIds.insert (measId);
+  return measId;
 }
 
 
@@ -2073,7 +2058,7 @@
       if ((rnti != 0) && (m_ueMap.find (rnti) == m_ueMap.end ()))
         {
           found = true;
-          break;        
+          break;
         }
     }
 
@@ -2103,7 +2088,7 @@
     }
   // need to do this after UeManager has been deleted
   RemoveSrsConfigurationIndex (srsCi); 
- }
+}
 
 TypeId
 LteEnbRrc::GetRlcType (EpsBearer bearer)
@@ -2143,17 +2128,8 @@
 void
 LteEnbRrc::AddX2Neighbour (uint16_t cellId)
 {
-  NS_LOG_FUNCTION (cellId);
-  NS_ASSERT_MSG (m_neighbourRelationTable.find (cellId) == m_neighbourRelationTable.end (),
-                 "There is already an entry in the Neighbour Relation Table for cellId " << cellId);
-
-  Ptr<NeighbourRelation> neighbourRelation = CreateObject <NeighbourRelation> ();
-  neighbourRelation->m_physCellId = cellId;
-  neighbourRelation->m_noRemove = true;
-  neighbourRelation->m_noHo = true;
-  neighbourRelation->m_noX2 = false;
-  neighbourRelation->m_detectedAsNeighbour = false;
-  m_neighbourRelationTable[cellId] = neighbourRelation;
+  NS_LOG_FUNCTION (this << cellId);
+  m_anrSapProvider->AddNeighbourRelation (cellId);
 }
 
 LteRrcSap::SystemInformationBlockType1
--- a/src/lte/model/lte-enb-rrc.h	Mon Aug 12 09:29:23 2013 +0300
+++ b/src/lte/model/lte-enb-rrc.h	Mon Aug 12 11:25:23 2013 +0300
@@ -34,6 +34,7 @@
 #include <ns3/epc-enb-s1-sap.h>
 #include <ns3/lte-enb-cphy-sap.h>
 #include <ns3/lte-rrc-sap.h>
+#include <ns3/lte-anr-sap.h>
 #include <ns3/traced-callback.h>
 #include <ns3/event-id.h>
 
@@ -51,19 +52,6 @@
 class LteEnbRrc;
 
 
-/**
- * Neighbour Relation between two eNBs (serving eNB and neighbour eNB)
- * See XXXXX for more info
- */
-class NeighbourRelation : public Object
-{
-public:
-  uint16_t  m_physCellId;
-  bool      m_noRemove;
-  bool      m_noHo;
-  bool      m_noX2;
-  bool      m_detectedAsNeighbour;
-};
 
 /**
  * Measurements reported by a UE for a cellId
@@ -440,6 +428,8 @@
 
 class HandoverManagementSapProvider;
 class HandoverManagementSapUser;
+class LteAnrSapProvider;
+class LteAnrSapUser;
 
 
 /**
@@ -452,6 +442,7 @@
 
   friend class EnbRrcMemberLteEnbCmacSapUser;
   friend class EnbRrcMemberHandoverManagementSapUser;
+  friend class MemberLteAnrSapUser<LteEnbRrc>;
   friend class MemberLteEnbRrcSapProvider<LteEnbRrc>;
   friend class MemberEpcEnbS1SapUser<LteEnbRrc>;
   friend class EpcX2SpecificEpcX2SapUser<LteEnbRrc>;
@@ -520,6 +511,21 @@
 
 
   /**
+   * set the ANR SAP this RRC should interact with
+   *
+   * \param s the ANR SAP Provider to be used by this RRC
+   */
+  void SetLteAnrSapProvider (LteAnrSapProvider * s);
+
+  /**
+   * Get the ANR SAP offered by this RRC
+   * \return s the ANR SAP User interface offered to the ANR instance by this
+   *           RRC
+   */
+  LteAnrSapUser* GetLteAnrSapUser ();
+
+
+  /**
    * set the RRC SAP this RRC should interact with
    *
    * \param s the RRC SAP User to be used by this RRC
@@ -705,7 +711,7 @@
 
 
   // RRC SAP methods
-  
+
   void DoCompleteSetupUe (uint16_t rnti, LteEnbRrcSapProvider::CompleteSetupUeParameters params);
   void DoRecvRrcConnectionRequest (uint16_t rnti, LteRrcSap::RrcConnectionRequest msg);
   void DoRecvRrcConnectionSetupCompleted (uint16_t rnti, LteRrcSap::RrcConnectionSetupCompleted msg);
@@ -735,12 +741,16 @@
   uint16_t DoAllocateTemporaryCellRnti ();
   void DoNotifyLcConfigResult (uint16_t rnti, uint8_t lcid, bool success);
   void DoRrcConfigurationUpdateInd (LteEnbCmacSapUser::UeConfig params);
-  
+
   // Handover Management SAP methods
 
-  uint8_t DoAddUeMeasReportConfig (LteRrcSap::ReportConfigEutra reportConfig);
+  uint8_t DoAddUeMeasReportConfigForHandover (LteRrcSap::ReportConfigEutra reportConfig);
   void DoTriggerHandover (uint16_t rnti, uint16_t targetCellId);
 
+  // ANR SAP methods
+
+  uint8_t DoAddUeMeasReportConfigForAnr (LteRrcSap::ReportConfigEutra reportConfig);
+
 
   // Internal methods
 
@@ -867,6 +877,9 @@
   HandoverManagementSapUser* m_handoverManagementSapUser;
   HandoverManagementSapProvider* m_handoverManagementSapProvider;
 
+  LteAnrSapUser* m_anrSapUser;
+  LteAnrSapProvider* m_anrSapProvider;
+
   LteEnbRrcSapUser* m_rrcSapUser;
   LteEnbRrcSapProvider* m_rrcSapProvider;
 
@@ -897,6 +910,9 @@
    */
   LteRrcSap::MeasConfig m_ueMeasConfig;
 
+  std::set<uint8_t> m_handoverMeasIds;
+  std::set<uint8_t> m_anrMeasIds;
+
   struct X2uTeidInfo
   {
     uint16_t rnti;
@@ -932,10 +948,6 @@
   Time m_handoverJoiningTimeoutDuration;
   Time m_handoverLeavingTimeoutDuration;
 
-  //       cellid
-  std::map<uint16_t, Ptr<NeighbourRelation> > m_neighbourRelationTable;
-
-
   //             cellid    rnti   
   TracedCallback<uint16_t, uint16_t> m_newUeContextTrace;
   //             imsi      cellid    rnti   
--- a/src/lte/wscript	Mon Aug 12 09:29:23 2013 +0300
+++ b/src/lte/wscript	Mon Aug 12 11:25:23 2013 +0300
@@ -101,6 +101,8 @@
         'model/handover-management-sap.cc',
         'model/handover-algorithm.cc',
         'model/a2-rsrq-handover-algorithm.cc',
+        'model/lte-anr-sap.cc',
+        'model/lte-anr.cc',
         ]
 
     module_test = bld.create_ns3_module_test_library('lte')
@@ -249,6 +251,8 @@
         'model/handover-management-sap.h',
         'model/handover-algorithm.h',
         'model/a2-rsrq-handover-algorithm.h',
+        'model/lte-anr-sap.h',
+        'model/lte-anr.h',
         ]
 
     if (bld.env['ENABLE_EXAMPLES']):