text: /* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
  /*
   * Copyright (c) 2011, 2012 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
   *
   * 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
   *
   * Authors: Nicola Baldo <nbaldo@cttc.es>
   *          Marco Miozzo <mmiozzo@cttc.es>
   *          Manuel Requena <manuel.requena@cttc.es> 
   */
  
  #ifndef LTE_ENB_RRC_H
  #define LTE_ENB_RRC_H
  
  #include <ns3/nstime.h>
  #include <ns3/object.h>
  #include <ns3/traced-callback.h>
  #include <ns3/event-id.h>
  #include <ns3/lte-enb-mac.h>
  #include <ns3/lte-enb-cmac-sap.h>
  #include <ns3/lte-mac-sap.h>
  #include <ns3/ff-mac-sched-sap.h>
  #include <ns3/ff-mac-csched-sap.h>
  #include <ns3/lte-pdcp-sap.h>
  #include <ns3/epc-x2-sap.h>
  #include <ns3/epc-enb-s1-sap.h>
  #include <ns3/lte-handover-management-sap.h>
  #include <ns3/lte-enb-cphy-sap.h>
  #include <ns3/lte-rrc-sap.h>
  #include <ns3/lte-anr-sap.h>
  #include <ns3/lte-ffr-rrc-sap.h>
  
  #include <map>
  #include <set>
  
  namespace ns3 {
  
  class LteRadioBearerInfo;
  class LteSignalingRadioBearerInfo;
  class LteDataRadioBearerInfo;
  class LteEnbRrc;
  class Packet;
  class LteEnbMac;
  
  /**
   * \ingroup lte
   * Manages all the radio bearer information possessed by the ENB RRC for a
   * single UE.
   */
  class UeManager : public Object
  {
    friend class LtePdcpSpecificLtePdcpSapUser<UeManager>;
  
  public:
  
    /**
     * The state of the UeManager at the eNB RRC
     * 
     */
    enum State
    {
      INITIAL_RANDOM_ACCESS = 0,
      CONNECTION_SETUP,
      CONNECTION_REJECTED,
      CONNECTED_NORMALLY,
      CONNECTION_RECONFIGURATION,
      CONNECTION_REESTABLISHMENT,
      HANDOVER_PREPARATION,
      HANDOVER_JOINING,
      HANDOVER_PATH_SWITCH,
      HANDOVER_LEAVING,
      NUM_STATES
    };
  
    UeManager ();
   
    /** 
     * UeManager constructor
     * 
     * \param rrc pointer to the LteEnbRrc holding this UeManager
     * \param rnti RNTI of the UE
     * \param s initial state of the UeManager
     * 
     * \return 
     */
    UeManager (Ptr<LteEnbRrc> rrc, uint16_t rnti, State s);
  
    virtual ~UeManager (void);
  
    // inherited from Object
  protected:
    virtual void DoInitialize ();
    virtual void DoDispose ();
  public: 
    static TypeId GetTypeId (void);
  
    /** 
     * Set the identifiers of the source eNB for the case where a UE
     * joins the current eNB as part of a handover procedure 
     * 
     * \param sourceCellId 
     * \param sourceX2apId 
     */
    void SetSource (uint16_t sourceCellId, uint16_t sourceX2apId);
  
    /** 
     * Set the IMSI
     * 
     * \param imsi the IMSI
     */
    void SetImsi (uint64_t imsi);
  
    /** 
     * Setup a new data radio bearer, including both the configuration
     * within the eNB and the necessary RRC signaling with the UE
     * 
     * \param bearer the QoS characteristics of the bearer
     * \param bearerId the EPS bearer identifier
     * \param gtpTeid S1-bearer GTP tunnel endpoint identifier, see 36.423 9.2.1
     * \param transportLayerAddress  IP Address of the SGW, see 36.423 9.2.1
     * 
     */
    void SetupDataRadioBearer (EpsBearer bearer, uint8_t bearerId, uint32_t gtpTeid, Ipv4Address transportLayerAddress);
  
    /** 
     * Start all configured data radio bearers. It is safe to call this
     * method if any bearer had been already started previously.
     * 
     */
    void RecordDataRadioBearersToBeStarted ();
  
    /** 
     * Start the data radio bearers that have been previously recorded
     * to be started using RecordDataRadioBearersToBeStarted() 
     * 
     */
    void StartDataRadioBearers ();
  
    /**
     *
     * Release a given radio bearer
     *
     * \param drbid the data radio bearer id of the bearer to be released
     */
    void ReleaseDataRadioBearer (uint8_t drbid);
  
    /** 
     * schedule an RRC Connection Reconfiguration procedure with the UE
     * 
     */
    void ScheduleRrcConnectionReconfiguration ();
  
    /** 
     * Start the handover preparation and send the handover request
     * 
     * \param cellId id of the target cell
     */
    void PrepareHandover (uint16_t cellId);
  
    /** 
     * take the necessary actions in response to the reception of an X2 HANDOVER REQUEST ACK message
     * 
     * \param params 
     */
    void RecvHandoverRequestAck (EpcX2SapUser::HandoverRequestAckParams params);
  
    /** 
     * 
     * \return the HandoverPreparationInfo sent by the source eNB to the
     * target eNB in the X2-based handover procedure
     */
    LteRrcSap::RadioResourceConfigDedicated GetRadioResourceConfigForHandoverPreparationInfo ();
  
    /** 
     * 
     * \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 GetRrcConnectionReconfigurationForHandover ();
  
    /** 
     * Send a data packet over the appropriate Data Radio Bearer
     * 
     * \param bid the corresponding EPS Bearer ID
     * \param p the packet
     */
    void SendData (uint8_t bid, Ptr<Packet> p);
  
    /** 
     * 
     * \return a list of ERAB-to-be-setup items to be put in a X2 HO REQ message
     */
    std::vector<EpcX2Sap::ErabToBeSetupItem> GetErabList ();
  
    /** 
     * send the UE CONTEXT RELEASE X2 message to the source eNB, thus
     * successfully terminating an X2 handover procedure 
     * 
     */
    void SendUeContextRelease ();
  
    /** 
     * Take the necessary actions in response to the reception of an X2 HO preparation failure message
     * 
     * \param cellId id of the target cell
     */
    void RecvHandoverPreparationFailure (uint16_t cellId);
  
    /** 
     * Take the necessary actions in response to the reception of an X2 SN STATUS TRANSFER message
     * 
     * \param params the SN STATUS
     */
    void RecvSnStatusTransfer (EpcX2SapUser::SnStatusTransferParams params);
   
    /** 
     * Take the necessary actions in response to the reception of an X2 UE CONTEXT RELEASE message
     * 
     * \param params the SN STATUS
     */
    void RecvUeContextRelease (EpcX2SapUser::UeContextReleaseParams params); 
  
  
    // METHODS FORWARDED FROM ENB RRC SAP ///////////////////////////////////////
  
    /// Part of the RRC protocol. Implement the LteEnbRrcSapProvider::CompleteSetupUe interface.
    void CompleteSetupUe (LteEnbRrcSapProvider::CompleteSetupUeParameters params);
    /// Part of the RRC protocol. Implement the LteEnbRrcSapProvider::RecvRrcConnectionRequest interface.
    void RecvRrcConnectionRequest (LteRrcSap::RrcConnectionRequest msg);
    /// Part of the RRC protocol. Implement the LteEnbRrcSapProvider::RecvRrcConnectionSetupCompleted interface.
    void RecvRrcConnectionSetupCompleted (LteRrcSap::RrcConnectionSetupCompleted msg);
    /// Part of the RRC protocol. Implement the LteEnbRrcSapProvider::RecvRrcConnectionReconfigurationCompleted interface.
    void RecvRrcConnectionReconfigurationCompleted (LteRrcSap::RrcConnectionReconfigurationCompleted msg);
    /// Part of the RRC protocol. Implement the LteEnbRrcSapProvider::RecvRrcConnectionReestablishmentRequest interface.
    void RecvRrcConnectionReestablishmentRequest (LteRrcSap::RrcConnectionReestablishmentRequest msg);
    /// Part of the RRC protocol. Implement the LteEnbRrcSapProvider::RecvRrcConnectionReestablishmentComplete interface.
    void RecvRrcConnectionReestablishmentComplete (LteRrcSap::RrcConnectionReestablishmentComplete msg);
    /// Part of the RRC protocol. Implement the LteEnbRrcSapProvider::RecvMeasurementReport interface.
    void RecvMeasurementReport (LteRrcSap::MeasurementReport msg);
  
  
    // METHODS FORWARDED FROM ENB CMAC SAP //////////////////////////////////////
  
    void CmacUeConfigUpdateInd (LteEnbCmacSapUser::UeConfig cmacParams);
  
    // METHODS FORWARDED FROM ENB PDCP SAP //////////////////////////////////////
  
    void DoReceivePdcpSdu (LtePdcpSapUser::ReceivePdcpSduParameters params);
  
    /** 
     * 
     * \return the RNTI, i.e., an UE identifier that is unique within
     * the cell
     */
    uint16_t GetRnti (void) const;
  
    /** 
     *
     * \return the IMSI, i.e., a globally unique UE identifier
     */
    uint64_t GetImsi (void) const;
  
    /** 
     * 
     * \return the SRS Configuration Index
     */
    uint16_t GetSrsConfigurationIndex (void) const;
  
    /** 
     * Set the SRS configuration index and do the necessary reconfiguration
     * 
     * \param srsConfIndex 
     */
    void SetSrsConfigurationIndex (uint16_t srsConfIndex);
  
    /** 
     * 
     * \return the current state
     */
    State GetState () const;
  
    /**
     * Configure PdschConfigDedicated (i.e. P_A value) for UE and start RrcConnectionReconfiguration
     * to inform UE about new PdschConfigDedicated
     *
     * \param pdschConfigDedicated new pdschConfigDedicated (i.e. P_A value) to be set
     */
    void SetPdschConfigDedicated (LteRrcSap::PdschConfigDedicated pdschConfigDedicated);
  
    /**
     * TracedCallback signature for state transition events.
     *
     * \param [in] imsi
     * \param [in] cellId
     * \param [in] rnti
     * \param [in] oldState
     * \param [in] newState
     */
    typedef void (* StateTracedCallback)
      (uint64_t imsi, uint16_t cellId, uint16_t rnti,
       State oldState, State newState);
  
  private:
  
    /** 
     * Add a new LteDataRadioBearerInfo structure to the UeManager
     * 
     * \param radioBearerInfo 
     * 
     * \return the id of the newly added data radio bearer structure
     */
    uint8_t AddDataRadioBearerInfo (Ptr<LteDataRadioBearerInfo> radioBearerInfo);
  
    /** 
     * \param drbid the Data Radio Bearer id
     * 
     * \return the corresponding LteDataRadioBearerInfo
     */
    Ptr<LteDataRadioBearerInfo> GetDataRadioBearerInfo (uint8_t drbid);
  
    /** 
     * remove the LteDataRadioBearerInfo corresponding to a bearer being released
     *
     * \param drbid the Data Radio Bearer id
     */
    void RemoveDataRadioBearerInfo (uint8_t drbid);
  
    /** 
     * 
     * \return an RrcConnectionReconfiguration struct built based on the
     * current configuration
     */
    LteRrcSap::RrcConnectionReconfiguration BuildRrcConnectionReconfiguration ();
  
    /** 
     * 
     * \return a RadioResourceConfigDedicated struct built based on the
     * current configuration
     */
    LteRrcSap::RadioResourceConfigDedicated BuildRadioResourceConfigDedicated ();
  
    /** 
     * 
     * \return a newly allocated identifier for a new RRC transaction
     */
    uint8_t GetNewRrcTransactionIdentifier ();
  
    /** 
     * \param lcid a Logical Channel Identifier
     * 
     * \return the corresponding Data Radio Bearer Id
     */
    uint8_t Lcid2Drbid (uint8_t lcid);
  
    /** 
     * \param drbid a Data Radio Bearer Id
     * 
     * \return the corresponding  Logical Channel Identifier
     */
    uint8_t Drbid2Lcid (uint8_t drbid);
  
    /** 
     * \param lcid a  Logical Channel Identifier
     * 
     * \return the corresponding EPS Bearer Identifier
     */
    uint8_t Lcid2Bid (uint8_t lcid);
  
    /** 
     * \param bid  an EPS Bearer Identifier
     * 
     * \return the corresponding Logical Channel Identifier
     */
    uint8_t Bid2Lcid (uint8_t bid);
  
    /** 
     * \param drbid Data Radio Bearer Id
     * 
     * \return the corresponding EPS Bearer Identifier
     */
    uint8_t Drbid2Bid (uint8_t drbid);
  
    /** 
     * \param bid an EPS Bearer Identifier
     * 
     * \return the corresponding Data Radio Bearer Id
     */
    uint8_t Bid2Drbid (uint8_t bid);
  
    /** 
     * Switch the UeManager to the given state
     * 
     * \param s the given state
     */
    void SwitchToState (State s);
  
    uint8_t m_lastAllocatedDrbid;
  
    /**
     * The `DataRadioBearerMap` attribute. List of UE DataRadioBearerInfo by
     * DRBID.
     */
    std::map <uint8_t, Ptr<LteDataRadioBearerInfo> > m_drbMap;
  
    /**
     * The `Srb0` attribute. SignalingRadioBearerInfo for SRB0.
     */
    Ptr<LteSignalingRadioBearerInfo> m_srb0;
    /**
     * The `Srb1` attribute. SignalingRadioBearerInfo for SRB1.
     */
    Ptr<LteSignalingRadioBearerInfo> m_srb1;
  
    /**
     * The `C-RNTI` attribute. Cell Radio Network Temporary Identifier.
     */
    uint16_t m_rnti;
    /**
     * International Mobile Subscriber Identity assigned to this UE. A globally
     * unique UE identifier.
     */
    uint64_t m_imsi;
    ///
    uint8_t m_lastRrcTransactionIdentifier;
    ///
    LteRrcSap::PhysicalConfigDedicated m_physicalConfigDedicated;
    /// Pointer to the parent eNodeB RRC.
    Ptr<LteEnbRrc> m_rrc;
    /// The current UeManager state.
    State m_state;
    ///
    LtePdcpSapUser* m_drbPdcpSapUser;
    //for nb-iot
    LteEnbMac* enb_mac;
    ///
    bool m_pendingRrcConnectionReconfiguration;
  
    /**
     * The `StateTransition` trace source. Fired upon every UE state transition
     * seen by the UeManager at the eNB RRC. Exporting IMSI, cell ID, RNTI, old
     * state, and new state.
     */
    TracedCallback<uint64_t, uint16_t, uint16_t, State, State> m_stateTransitionTrace;
  
    uint16_t m_sourceX2apId;
    uint16_t m_sourceCellId;
    uint16_t m_targetCellId;
    std::list<uint8_t> m_drbsToBeStarted;
    bool m_needPhyMacConfiguration;
  
    /**
     * Time limit before a _connection request timeout_ occurs. Set after a new
     * UE context is added after a successful Random Access. Calling
     * LteEnbRrc::ConnectionRequestTimeout() when it expires. Cancelled when RRC
     * CONNECTION REQUEST is received.
     */
    EventId m_connectionRequestTimeout;
    /**
     * Time limit before a _connection setup timeout_ occurs. Set after an RRC
     * CONNECTION SETUP is sent. Calling LteEnbRrc::ConnectionSetupTimeout() when
     * it expires. Cancelled when RRC CONNECTION SETUP COMPLETE is received.
     */
    EventId m_connectionSetupTimeout;
    /**
     * The delay before a _connection rejected timeout_ occurs. Set after an RRC
     * CONNECTION REJECT is sent. Calling LteEnbRrc::ConnectionRejectedTimeout()
     * when it expires.
     */
    EventId m_connectionRejectedTimeout;
    /**
     * Time limit before a _handover joining timeout_ occurs. Set after a new UE
     * context is added after receiving a handover request. Calling
     * LteEnbRrc::HandoverJoiningTimeout() when it expires. Cancelled when
     * RRC CONNECTION RECONFIGURATION COMPLETE is received.
     */
    EventId m_handoverJoiningTimeout;
    /**
     * Time limit before a _handover leaving timeout_ occurs. Set after a
     * handover command is sent. Calling LteEnbRrc::HandoverLeavingTimeout()
     * when it expires. Cancelled when RRC CONNECTION RE-ESTABLISHMENT or X2
     * UE CONTEXT RELEASE is received.
     */
    EventId m_handoverLeavingTimeout;
  
  }; // end of `class UeManager`
  
  
  
  /**
   * \ingroup lte
   * 
   * The LTE Radio Resource Control entity at the eNB
   */
  class LteEnbRrc : public Object
  {
  
    friend class EnbRrcMemberLteEnbCmacSapUser;
    friend class MemberLteHandoverManagementSapUser<LteEnbRrc>;
    friend class MemberLteAnrSapUser<LteEnbRrc>;
    friend class MemberLteFfrRrcSapUser<LteEnbRrc>;
    friend class MemberLteEnbRrcSapProvider<LteEnbRrc>;
    friend class MemberEpcEnbS1SapUser<LteEnbRrc>;
    friend class EpcX2SpecificEpcX2SapUser<LteEnbRrc>;
    friend class UeManager;
  
  public:
    /**
     * create an RRC instance for use within an eNB
     *
     */
    LteEnbRrc ();
  
    /**
     * Destructor
     */
    virtual ~LteEnbRrc ();
  
  
    // inherited from Object
  protected:
    virtual void DoDispose (void);
  public:
    static TypeId GetTypeId (void);
  
    //for nb-iot
    void RecvUePara(uint16_t rnti, int rep, int startsf, double offset);
  
    // msg4 scheduling
    void msg4SchedulingInfo(LteRrcSap::NPRACH_Parameters_NB_r13 np);
  
    //for nb-iot
    void SendRrcConnectionSetup_NB();
  
    /**
     * Set the X2 SAP this RRC should interact with
     * \param s the X2 SAP Provider to be used by this RRC entity
     */
    void SetEpcX2SapProvider (EpcX2SapProvider* s);
  
    /** 
     * Get the X2 SAP offered by this RRC
     * \return s the X2 SAP User interface offered to the X2 entity by this RRC entity
     */
    EpcX2SapUser* GetEpcX2SapUser ();
  
  
    /**
     * set the CMAC SAP this RRC should interact with
     *
     * \param s the CMAC SAP Provider to be used by this RRC
     */
    void SetLteEnbCmacSapProvider (LteEnbCmacSapProvider * s);
  
    /** 
     * Get the CMAC SAP offered by this RRC
     * \return s the CMAC SAP User interface offered to the MAC by this RRC
     */
    LteEnbCmacSapUser* GetLteEnbCmacSapUser ();
  
  
    /**
     * set the Handover Management SAP this RRC should interact with
     *
     * \param s the Handover Management SAP Provider to be used by this RRC
     */
    void SetLteHandoverManagementSapProvider (LteHandoverManagementSapProvider * s);
  
    /**
     * Get the Handover Management SAP offered by this RRC
     * \return s the Handover Management SAP User interface offered to the
     *           handover algorithm by this RRC
     */
    LteHandoverManagementSapUser* GetLteHandoverManagementSapUser ();
  
  
    /**
     * 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 FFR SAP this RRC should interact with
     *
     * \param s the FFR SAP Provider to be used by this RRC
     */
    void SetLteFfrRrcSapProvider (LteFfrRrcSapProvider * s);
  
    /**
     * Get the FFR SAP offered by this RRC
     * \return s the FFR SAP User interface offered to the ANR instance by this
     *           RRC
     */
    LteFfrRrcSapUser* GetLteFfrRrcSapUser ();
  
    /**
     * set the RRC SAP this RRC should interact with
     *
     * \param s the RRC SAP User to be used by this RRC
     */
    void SetLteEnbRrcSapUser (LteEnbRrcSapUser * s);
  
    /**
     *
     *
     * \return s the RRC SAP Provider interface offered to the MAC by this RRC
     */
    LteEnbRrcSapProvider* GetLteEnbRrcSapProvider ();
  
    /**
     * set the MAC SAP provider. The eNB RRC does not use this
     * directly, but it needs to provide it to newly created RLC instances.
     *
     * \param s the MAC SAP provider that will be used by all
     * newly created RLC instances
     */
    void SetLteMacSapProvider (LteMacSapProvider* s);
  
  
    /** 
     * Set the S1 SAP Provider
     * 
     * \param s the S1 SAP Provider
     */
    void SetS1SapProvider (EpcEnbS1SapProvider * s);
  
    /** 
     * 
     * \return the S1 SAP user
     */
    EpcEnbS1SapUser* GetS1SapUser ();
  
  
    /**
     * set the CPHY SAP this RRC should use to interact with the PHY
     *
     * \param s the CPHY SAP Provider
     */
    void SetLteEnbCphySapProvider (LteEnbCphySapProvider * s);
  
    /**
     *
     *
     * \return s the CPHY SAP User interface offered to the PHY by this RRC
     */
    LteEnbCphySapUser* GetLteEnbCphySapUser ();
  
    /** 
     * 
     * 
     * \param rnti the identifier of an UE
     * 
     * \return true if the corresponding UeManager instance exists
     */
    bool HasUeManager (uint16_t rnti) const;
  
    /**
     *
     *
     * \param rnti the identifier of an UE
     *
     * \return the corresponding UeManager instance
     */
    Ptr<UeManager> GetUeManager (uint16_t rnti);
  
    /**
     * \brief Add a new UE measurement reporting configuration
     * \param config the new reporting configuration
     * \return the measurement ID (measId) referring to the newly added
     *         reporting configuration
     *
     * Assuming intra-frequency environment, the new measurement reporting
     * configuration will be automatically associated to the only measurement
     * object (i.e., a new measurement identity will be automatically created).
     *
     * Can only be called before the start of simulation.
     */
    uint8_t AddUeMeasReportConfig (LteRrcSap::ReportConfigEutra config);
  
    /**
     * \brief Configure cell-specific parameters.
     * \param ulBandwidth the uplink bandwidth in number of RB
     * \param dlBandwidth the downlink bandwidth in number of RB
     * \param ulEarfcn the UL EARFCN
     * \param dlEarfcn the DL EARFCN
     * \param cellId the ID of the cell
     *
     * Configure cell-specific parameters and propagate them to lower layers.
     * The parameters include bandwidth, EARFCN (E-UTRA Absolute Radio Frequency
     * Channel Number), and cell ID.
     *
     * In addition to parameter configuration, this function also performs several
     * other tasks:
     *  - Initializing UE measurement (i.e. measurement object and quantity
     *    configuration), which is expected to be further configured through
     *    `LteEnbRrc::AddUeMeasReportConfig`;
     *  - Enabling MIB (Master Information Block) broadcast transmission
     *  - Enabling SIB (System Information Block) broadcast transmission
     *
     * Typically runs when the eNodeB NetDevice is installed, for instance by
     * `LteHelper::InstallEnbDevice` (i.e. before the simulation starts).
     *
     * \warning Raises an error when executed more than once.
     */
    void ConfigureCell (uint8_t ulBandwidth,
                        uint8_t dlBandwidth,
                        uint16_t ulEarfcn, 
                        uint16_t dlEarfcn,
                        uint16_t cellId);
  
  
    /** 
     * set the cell id of this eNB
     * 
     * \param m_cellId 
     */
    void SetCellId (uint16_t m_cellId);
  
    /** 
     * Enqueue an IP data packet on the proper bearer for downlink
     * transmission. Normally expected to be called by the NetDevice
     * forwarding a packet coming from the EpcEnbApplication 
     * 
     * \param p the packet
     * 
     * \return true if successful, false if an error occurred
     */
    bool SendData (Ptr<Packet> p);
  
    /** 
     * set the callback used to forward data packets up the stack
     * 
     * \param cb 
     */
    void SetForwardUpCallback (Callback <void, Ptr<Packet> > cb);
  
    /** 
     * Method triggered when a UE is expected to request for connection but does
     * not do so in a reasonable time. The method will remove the UE context.
     * 
     * \param rnti the T-C-RNTI whose timeout expired
     */
    void ConnectionRequestTimeout (uint16_t rnti);
  
    /** 
     * Method triggered when a UE is expected to complete a connection setup
     * procedure but does not do so in a reasonable time. The method will remove
     * the UE context.
     *
     * \param rnti the T-C-RNTI whose timeout expired
     */
    void ConnectionSetupTimeout (uint16_t rnti);
  
    /**
     * Method triggered a while after sending RRC Connection Rejected. The method
     * will remove the UE context.
     * 
     * \param rnti the T-C-RNTI whose timeout expired
     */
    void ConnectionRejectedTimeout (uint16_t rnti);
  
    /** 
     * Method triggered when a UE is expected to join the cell for a handover 
     * but does not do so in a reasonable time. The method will remove the UE
     * context.
     * 
     * \param rnti the C-RNTI whose timeout expired
     */
    void HandoverJoiningTimeout (uint16_t rnti);
  
    /** 
     * Method triggered when a UE is expected to leave a cell for a handover
     * but no feedback is received in a reasonable time. The method will remove
     * the UE context.
     * 
     * \param rnti the C-RNTI whose timeout expired
     */
    void HandoverLeavingTimeout (uint16_t rnti);
  
    /** 
     * Send a HandoverRequest through the X2 SAP interface. This method will
     * trigger a handover which is started by the RRC by sending a handover
     * request to the target eNB over the X2 interface
     *
     * \param rnti the ID of the UE to be handed over
     * \param cellId the ID of the target eNB
     */
    void SendHandoverRequest (uint16_t rnti, uint16_t cellId);
  
    /**
     *  \brief This function acts as an interface to trigger Release indication messages towards eNB and EPC
     *  \param imsi the IMSI
     *  \param rnti the RNTI
     *  \param bearerId Bearer Identity which is to be de-activated
     */
    void DoSendReleaseDataRadioBearer (uint64_t imsi, uint16_t rnti, uint8_t bearerId);
  
    /**
     * Identifies how EPS Bearer parameters are mapped to different RLC types
     * 
     */
    enum LteEpsBearerToRlcMapping_t {RLC_SM_ALWAYS = 1,
                                     RLC_UM_ALWAYS = 2,
                                     RLC_AM_ALWAYS = 3,
                                     PER_BASED = 4};
  
    /**
     * TracedCallback signature for new Ue Context events.
     *
     * \param [in] cellId
     * \param [in] rnti
     */
    typedef void (* NewUeContextTracedCallback)
      (uint16_t cellId, uint16_t rnti);
  
    /**
     * TracedCallback signature for connection and handover end events.
     *
     * \param [in] imsi
     * \param [in] cellId
     * \param [in] rnti
     */
    typedef void (* ConnectionHandoverTracedCallback)
      (uint64_t imsi, uint16_t cellId, uint16_t rnti);
    
    /**
     * TracedCallback signature for handover start events.
     *
     * \param [in] imsi
     * \param [in] cellId
     * \param [in] rnti
     * \param [in] targetCid
     */
    typedef void (* HandoverStartTracedCallback)
      (uint64_t imsi, uint16_t cellId, uint16_t rnti, uint16_t targetCid);
  
    /**
     * TracedCallback signature for receive measurement report events.
     *
     * \param [in] imsi
     * \param [in] cellId
     * \param [in] rnti
     * \param [in] report
     * \todo The \c LteRrcSap::MeasurementReport argument should be
     * changed to a const reference since the argument is large.
     */
    typedef void (* ReceiveReportTracedCallback)
      (uint64_t imsi, uint16_t cellId, uint16_t rnti,
       LteRrcSap::MeasurementReport report);
    
  private:
  
  
    // RRC SAP methods
  
    /// Part of the RRC protocol. Forwarding LteEnbRrcSapProvider::CompleteSetupUe interface to UeManager::CompleteSetupUe
    void DoCompleteSetupUe (uint16_t rnti, LteEnbRrcSapProvider::CompleteSetupUeParameters params);
    /// Part of the RRC protocol. Forwarding LteEnbRrcSapProvider::RecvRrcConnectionRequest interface to UeManager::RecvRrcConnectionRequest
    void DoRecvRrcConnectionRequest (uint16_t rnti, LteRrcSap::RrcConnectionRequest msg);
    /// Part of the RRC protocol. Forwarding LteEnbRrcSapProvider::RecvRrcConnectionSetupCompleted interface to UeManager::RecvRrcConnectionSetupCompleted
    void DoRecvRrcConnectionSetupCompleted (uint16_t rnti, LteRrcSap::RrcConnectionSetupCompleted msg);
    /// Part of the RRC protocol. Forwarding LteEnbRrcSapProvider::RecvRrcConnectionReconfigurationCompleted interface to UeManager::RecvRrcConnectionReconfigurationCompleted
    void DoRecvRrcConnectionReconfigurationCompleted (uint16_t rnti, LteRrcSap::RrcConnectionReconfigurationCompleted msg);
    /// Part of the RRC protocol. Forwarding LteEnbRrcSapProvider::RecvRrcConnectionReestablishmentRequest interface to UeManager::RecvRrcConnectionReestablishmentRequest
    void DoRecvRrcConnectionReestablishmentRequest (uint16_t rnti, LteRrcSap::RrcConnectionReestablishmentRequest msg);
    /// Part of the RRC protocol. Forwarding LteEnbRrcSapProvider::RecvRrcConnectionReestablishmentComplete interface to UeManager::RecvRrcConnectionReestablishmentComplete
    void DoRecvRrcConnectionReestablishmentComplete (uint16_t rnti, LteRrcSap::RrcConnectionReestablishmentComplete msg);
    /// Part of the RRC protocol. Forwarding LteEnbRrcSapProvider::RecvMeasurementReport interface to UeManager::RecvMeasurementReport
    void DoRecvMeasurementReport (uint16_t rnti, LteRrcSap::MeasurementReport msg);
    //for nb-iot
    //void DoRecvCE (uint64_t imsi, uint16_t rnti, int judge_ce_level);
  
  
    // S1 SAP methods
  
    void DoDataRadioBearerSetupRequest (EpcEnbS1SapUser::DataRadioBearerSetupRequestParameters params);
    void DoPathSwitchRequestAcknowledge (EpcEnbS1SapUser::PathSwitchRequestAcknowledgeParameters params);
  
    // X2 SAP methods
  
    void DoRecvHandoverRequest (EpcX2SapUser::HandoverRequestParams params);
    void DoRecvHandoverRequestAck (EpcX2SapUser::HandoverRequestAckParams params);
    void DoRecvHandoverPreparationFailure (EpcX2SapUser::HandoverPreparationFailureParams params);
    void DoRecvSnStatusTransfer (EpcX2SapUser::SnStatusTransferParams params);
    void DoRecvUeContextRelease (EpcX2SapUser::UeContextReleaseParams params);
    void DoRecvLoadInformation (EpcX2SapUser::LoadInformationParams params);
    void DoRecvResourceStatusUpdate (EpcX2SapUser::ResourceStatusUpdateParams params);
    void DoRecvUeData (EpcX2SapUser::UeDataParams params);
  
    // CMAC SAP methods
  
    uint16_t DoAllocateTemporaryCellRnti ();
    void DoNotifyLcConfigResult (uint16_t rnti, uint8_t lcid, bool success);
    void DoRrcConfigurationUpdateInd (LteEnbCmacSapUser::UeConfig params);
  
    // Handover Management SAP methods
  
    uint8_t DoAddUeMeasReportConfigForHandover (LteRrcSap::ReportConfigEutra reportConfig);
    void DoTriggerHandover (uint16_t rnti, uint16_t targetCellId);
  
    // ANR SAP methods
  
    uint8_t DoAddUeMeasReportConfigForAnr (LteRrcSap::ReportConfigEutra reportConfig);
  
    // FFR RRC SAP methods
    uint8_t DoAddUeMeasReportConfigForFfr (LteRrcSap::ReportConfigEutra reportConfig);
    void DoSetPdschConfigDedicated (uint16_t rnti, LteRrcSap::PdschConfigDedicated pa);
    void DoSendLoadInformation (EpcX2Sap::LoadInformationParams params);
  
    // Internal methods
  
    /**
     * Allocate a new RNTI for a new UE. This is done in the following cases:
     *   * T-C-RNTI allocation upon contention-based MAC Random Access procedure
     *   * target cell RNTI allocation upon handover
     *
     * \param state the initial state of the UeManager
     *
     * \return the newly allocated RNTI
     */
    uint16_t AddUe (UeManager::State state);
  
    /**
     * remove a UE from the cell
     *
     * \param rnti the C-RNTI identiftying the user
     */
    void RemoveUe (uint16_t rnti);
  
  
    /** 
     * 
     * \param bearer the specification of an EPS bearer
     * 
     * \return the type of RLC that is to be created for the given EPS bearer
     */
    TypeId GetRlcType (EpsBearer bearer);
  
  
  
  public:
  
    /** 
     * Add a neighbour with an X2 interface
     *
     * \param cellId neighbouring cell id
     */
    void AddX2Neighbour (uint16_t cellId);
  
    /** 
     * 
     * \param p the SRS periodicity in num TTIs
     */
    void SetSrsPeriodicity (uint32_t p);
  
    /** 
     *
     * \return the current SRS periodicity
     */
    uint32_t GetSrsPeriodicity () const;
  
    /**
     * \brief Associate this RRC entity with a particular CSG information.
     * \param csgId the intended Closed Subscriber Group identity
     * \param csgIndication if TRUE, only CSG members are allowed to access the
     *                      cell
     *
     * CSG identity is a number identifying a Closed Subscriber Group which the
     * cell belongs to. eNodeB is associated with a single CSG identity.
     *
     * The same CSG identity can also be associated to several UEs, which is
     * equivalent as enlisting these UEs as the members of this particular CSG.
     * When the CSG indication field is set to TRUE, only UEs which are members of
     * the CSG (i.e. same CSG ID) can gain access to the eNodeB, therefore
     * enforcing closed access mode. Otherwise, the eNodeB operates as a non-CSG
     * cell and implements open access mode.
     *
     * This restriction only applies to initial cell selection and EPC-enabled
     * simulation.
     */
    void SetCsgId (uint32_t csgId, bool csgIndication);
  
  private:
  
    /** 
     * Allocate a new SRS configuration index for a new UE. 
     *
     * \note this method can have the side effect of updating the SRS
     * configuration index of all UEs
     * 
     * \return the newly allocated SRS configuration index
     */
    uint16_t GetNewSrsConfigurationIndex (void);
  
    /** 
     * remove a previously allocated SRS configuration index
     *
     * \note this method can have the side effect of updating the SRS
     * configuration index of all UEs
     * 
     * \param srcCi the indext to be removed
     */
    void RemoveSrsConfigurationIndex (uint16_t srcCi);
  
   
  
    /** 
     * 
     * \param bearer the characteristics of the bearer
     * 
     * \return the Logical Channel Group in a bearer with these
     * characteristics is put. Used for MAC Buffer Status Reporting purposes. 
     */
    uint8_t GetLogicalChannelGroup (EpsBearer bearer);
  
    /** 
     * 
     * \param bearer the characteristics of the bearer
     * 
     * \return the priority level of a bearer with these
     * characteristics is put. Used for the part of UL MAC Scheduling
     * carried out by the UE
     */
    uint8_t GetLogicalChannelPriority (EpsBearer bearer);
  
  
    /** 
     * method used to periodically send System Information
     * 
     */
    void SendSystemInformation ();
  
    Callback <void, Ptr<Packet> > m_forwardUpCallback;
  
    /// Interface to receive messages from neighbour eNodeB over the X2 interface.
    EpcX2SapUser* m_x2SapUser;
    /// Interface to send messages to neighbour eNodeB over the X2 interface.
    EpcX2SapProvider* m_x2SapProvider;
  
    /// Receive API calls from the eNodeB MAC instance.
    LteEnbCmacSapUser* m_cmacSapUser;
    /// Interface to the eNodeB MAC instance.
    LteEnbCmacSapProvider* m_cmacSapProvider;
  
    /// Receive API calls from the handover algorithm instance.
    LteHandoverManagementSapUser* m_handoverManagementSapUser;
    /// Interface to the handover algorithm instance.
    LteHandoverManagementSapProvider* m_handoverManagementSapProvider;
  
    /// Receive API calls from the ANR instance.
    LteAnrSapUser* m_anrSapUser;
    /// Interface to the ANR instance.
    LteAnrSapProvider* m_anrSapProvider;
  
    /// Receive API calls from the FFR algorithm instance.
    LteFfrRrcSapUser* m_ffrRrcSapUser;
    /// Interface to the FFR algorithm instance.
    LteFfrRrcSapProvider* m_ffrRrcSapProvider;
  
    /// Interface to send messages to UE over the RRC protocol.
    LteEnbRrcSapUser* m_rrcSapUser;
    /// Interface to receive messages from UE over the RRC protocol.
    LteEnbRrcSapProvider* m_rrcSapProvider;
  
    /// Interface to the eNodeB MAC instance, to be used by RLC instances.
    LteMacSapProvider* m_macSapProvider;
  
    /// Interface to send messages to core network over the S1 protocol.
    EpcEnbS1SapProvider* m_s1SapProvider;
    /// Interface to receive messages from core network over the S1 protocol.
    EpcEnbS1SapUser* m_s1SapUser;
  
    /// Receive API calls from the eNodeB PHY instance.
    LteEnbCphySapUser* m_cphySapUser;
    /// Interface to the eNodeB PHY instance.
    LteEnbCphySapProvider* m_cphySapProvider;
  
    //for nb-iot send ue para
    //LteEnbMac* enb_mac;
  
    /// True if ConfigureCell() has been completed.
    bool m_configured;
    /// Cell identifier. Must be unique across the simulation.
    uint16_t m_cellId;
    /// Downlink E-UTRA Absolute Radio Frequency Channel Number.
    uint16_t m_dlEarfcn;
    /// Uplink E-UTRA Absolute Radio Frequency Channel Number.
    uint16_t m_ulEarfcn;
    /// Downlink transmission bandwidth configuration in number of Resource Blocks.
    uint16_t m_dlBandwidth;
    /// Uplink transmission bandwidth configuration in number of Resource Blocks.
    uint16_t m_ulBandwidth;
    ///
    uint16_t m_lastAllocatedRnti;
  
    /// The System Information Block Type 1 that is currently broadcasted over BCH.
    LteRrcSap::SystemInformationBlockType1 m_sib1;
  
    /**
     * The `UeMap` attribute. List of UeManager by C-RNTI.
     */
    std::map<uint16_t, Ptr<UeManager> > m_ueMap;
  
    /**
     * List of measurement configuration which are active in every UE attached to
     * this eNodeB instance.
     */
    LteRrcSap::MeasConfig m_ueMeasConfig;
  
    /// List of measurement identities which are intended for handover purpose.
    std::set<uint8_t> m_handoverMeasIds;
    /// List of measurement identities which are intended for ANR purpose.
    std::set<uint8_t> m_anrMeasIds;
    /// List of measurement identities which are intended for FFR purpose.
    std::set<uint8_t> m_ffrMeasIds;
  
    struct X2uTeidInfo
    {
      uint16_t rnti;
      uint8_t drbid;
    };
  
    //       TEID      RNTI, DRBID
    std::map<uint32_t, X2uTeidInfo> m_x2uTeidInfoMap;
  
    /**
     * The `DefaultTransmissionMode` attribute. The default UEs' transmission
     * mode (0: SISO).
     */
    uint8_t m_defaultTransmissionMode;
    /**
     * The `EpsBearerToRlcMapping` attribute. Specify which type of RLC will be
     * used for each type of EPS bearer.
     */
    enum LteEpsBearerToRlcMapping_t m_epsBearerToRlcMapping;
    /**
     * The `SystemInformationPeriodicity` attribute. The interval for sending
     * system information.
     */
    Time m_systemInformationPeriodicity;
    /**
     * The `SrsPeriodicity` attribute. The SRS periodicity in milliseconds.
     */
    uint16_t m_srsCurrentPeriodicityId;
    std::set<uint16_t> m_ueSrsConfigurationIndexSet;
    uint16_t m_lastAllocatedConfigurationIndex;
    bool m_reconfigureUes;
  
    /**
     * The `QRxLevMin` attribute. One of information transmitted within the SIB1
     * message, indicating the required minimum RSRP level that any UE must
     * receive from this cell before it is allowed to camp to this cell.
     */
    int8_t m_qRxLevMin;
    /**
     * The `AdmitHandoverRequest` attribute. Whether to admit an X2 handover
     * request from another eNB.
     */
    bool m_admitHandoverRequest;
    /**
     * The `AdmitRrcConnectionRequest` attribute. Whether to admit a connection
     * request from a UE.
     */
    bool m_admitRrcConnectionRequest;
    /**
     * The `RsrpFilterCoefficient` attribute. Determines the strength of
     * smoothing effect induced by layer 3 filtering of RSRP in all attached UE.
     * If equals to 0, no layer 3 filtering is applicable.
     */
    uint8_t m_rsrpFilterCoefficient;
    /**
     * The `RsrqFilterCoefficient` attribute. Determines the strength of
     * smoothing effect induced by layer 3 filtering of RSRQ in all attached UE.
     * If equals to 0, no layer 3 filtering is applicable.
     */
    uint8_t m_rsrqFilterCoefficient;
    /**
     * The `ConnectionRequestTimeoutDuration` attribute. After a RA attempt, if
     * no RRC CONNECTION REQUEST is received before this time, the UE context is
     * destroyed. Must account for reception of RAR and transmission of RRC
     * CONNECTION REQUEST over UL GRANT.
     */
    Time m_connectionRequestTimeoutDuration;
    /**
     * The `ConnectionSetupTimeoutDuration` attribute. After accepting connection
     * request, if no RRC CONNECTION SETUP COMPLETE is received before this time,
     * the UE context is destroyed. Must account for the UE's reception of RRC
     * CONNECTION SETUP and transmission of RRC CONNECTION SETUP COMPLETE.
     */
    Time m_connectionSetupTimeoutDuration;
    /**
     * The `ConnectionRejectedTimeoutDuration` attribute. Time to wait between
     * sending a RRC CONNECTION REJECT and destroying the UE context.
     */
    Time m_connectionRejectedTimeoutDuration;
    /**
     * The `HandoverJoiningTimeoutDuration` attribute. After accepting a handover
     * request, if no RRC CONNECTION RECONFIGURATION COMPLETE is received before
     * this time, the UE context is destroyed. Must account for reception of X2
     * HO REQ ACK by source eNB, transmission of the Handover Command,
     * non-contention-based random access and reception of the RRC CONNECTION
     * RECONFIGURATION COMPLETE message.
     */
    Time m_handoverJoiningTimeoutDuration;
    /**
     * The `HandoverLeavingTimeoutDuration` attribute. After issuing a Handover
     * Command, if neither RRC CONNECTION RE-ESTABLISHMENT nor X2 UE Context
     * Release has been previously received, the UE context is destroyed.
     */
    Time m_handoverLeavingTimeoutDuration;
  
    /**
     * The `NewUeContext` trace source. Fired upon creation of a new UE context.
     * Exporting cell ID and RNTI.
     */
    TracedCallback<uint16_t, uint16_t> m_newUeContextTrace;
    /**
     * The `ConnectionEstablished` trace source. Fired upon successful RRC
     * connection establishment. Exporting IMSI, cell ID, and RNTI.
     */
    TracedCallback<uint64_t, uint16_t, uint16_t> m_connectionEstablishedTrace;
    /**
     * The `ConnectionReconfiguration` trace source. Fired upon RRC connection
     * reconfiguration. Exporting IMSI, cell ID, and RNTI.
     */
    TracedCallback<uint64_t, uint16_t, uint16_t> m_connectionReconfigurationTrace;
    /**
     * The `HandoverStart` trace source. Fired upon start of a handover
     * procedure. Exporting IMSI, cell ID, RNTI, and target cell ID.
     */
    TracedCallback<uint64_t, uint16_t, uint16_t, uint16_t> m_handoverStartTrace;
    /**
     * The `HandoverEndOk` trace source. Fired upon successful termination of a
     * handover procedure. Exporting IMSI, cell ID, and RNTI.
     */
    TracedCallback<uint64_t, uint16_t, uint16_t> m_handoverEndOkTrace;
    /**
     * The `RecvMeasurementReport` trace source. Fired when measurement report is
     * received. Exporting IMSI, cell ID, and RNTI.
     */
    TracedCallback<uint64_t, uint16_t, uint16_t, LteRrcSap::MeasurementReport> m_recvMeasurementReportTrace;
  
  }; // end of `class LteEnbRrc`
  
  
  } // namespace ns3
  
  #endif // LTE_ENB_RRC_H
  