//-----------------------------------------------------------------------------
rlc_union_t* rrc_rlc_add_rlc   (
  const protocol_ctxt_t* const ctxt_pP,
  const srb_flag_t        srb_flagP,
  const MBMS_flag_t       MBMS_flagP,
  const rb_id_t           rb_idP,
  const logical_chan_id_t chan_idP,
  const rlc_mode_t        rlc_modeP)
{
  //-----------------------------------------------------------------------------
  hash_key_t             key         = HASHTABLE_NOT_A_KEY_VALUE;
  hashtable_rc_t         h_rc;
  rlc_union_t           *rlc_union_p = NULL;
#ifdef Rel10
  rlc_mbms_id_t         *mbms_id_p  = NULL;
  logical_chan_id_t      lcid            = 0;
#endif

#ifdef OAI_EMU

  CHECK_CTXT_ARGS(ctxt_pP)

#endif

  if (MBMS_flagP == FALSE) {
    AssertFatal (rb_idP < NB_RB_MAX, "RB id is too high (%u/%d)!\n", rb_idP, NB_RB_MAX);
    AssertFatal (chan_idP < RLC_MAX_LC, "LC id is too high (%u/%d)!\n", chan_idP, RLC_MAX_LC);
  }

#ifdef Rel10

  if (MBMS_flagP == TRUE) {
    if (ctxt_pP->enb_flag) {
      lcid = rlc_mbms_enb_get_lcid_by_rb_id(ctxt_pP->module_id,rb_idP);
      mbms_id_p = &rlc_mbms_lcid2service_session_id_eNB[ctxt_pP->module_id][lcid];
      //LG 2014-04-15rlc_mbms_lcid2service_session_id_eNB[ctxt_pP->module_id][lcid].service_id = 0;
      //LG 2014-04-15rlc_mbms_lcid2service_session_id_eNB[ctxt_pP->module_id][lcid].session_id = 0;
      //LG 2014-04-15rlc_mbms_rbid2lcid_eNB[ctxt_pP->module_id][rb_idP] = RLC_LC_UNALLOCATED;

    } else {
      lcid = rlc_mbms_ue_get_lcid_by_rb_id(ctxt_pP->module_id,rb_idP);
      mbms_id_p = &rlc_mbms_lcid2service_session_id_ue[ctxt_pP->module_id][lcid];
      //LG 2014-04-15rlc_mbms_lcid2service_session_id_eNB[ctxt_pP->module_id][lcid].service_id = 0;
      //LG 2014-04-15rlc_mbms_lcid2service_session_id_eNB[ctxt_pP->module_id][lcid].session_id = 0;
      //LG 2014-04-15rlc_mbms_rbid2lcid_ue[ctxt_pP->module_id][rb_idP] = RLC_LC_UNALLOCATED;
    }

    key = RLC_COLL_KEY_MBMS_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, mbms_id_p->service_id, mbms_id_p->session_id);
  } else
#endif
  {
    key = RLC_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, rb_idP, srb_flagP);
  }

  h_rc = hashtable_get(rlc_coll_p, key, (void**)&rlc_union_p);

  if (h_rc == HASH_TABLE_OK) {
    LOG_W(RLC, PROTOCOL_CTXT_FMT"[%s %u] rrc_rlc_add_rlc , already exist %s\n",
          PROTOCOL_CTXT_ARGS(ctxt_pP),
          (srb_flagP) ? "SRB" : "DRB",
          rb_idP,
          (srb_flagP) ? "SRB" : "DRB");
    AssertFatal(rlc_union_p->mode == rlc_modeP, "Error rrc_rlc_add_rlc , already exist but RLC mode differ");
    return rlc_union_p;
  } else if (h_rc == HASH_TABLE_KEY_NOT_EXISTS) {
    rlc_union_p = calloc(1, sizeof(rlc_union_t));
    h_rc = hashtable_insert(rlc_coll_p, key, rlc_union_p);

    if (h_rc == HASH_TABLE_OK) {
#ifdef Rel10

      if (MBMS_flagP == TRUE) {
        LOG_I(RLC, PROTOCOL_CTXT_FMT" RLC service id %u session id %u rrc_rlc_add_rlc\n",
              PROTOCOL_CTXT_ARGS(ctxt_pP),
              mbms_id_p->service_id,
              mbms_id_p->session_id);
      } else
#endif
      {
        LOG_I(RLC, PROTOCOL_CTXT_FMT" [%s %u] rrc_rlc_add_rlc  %s\n",
              PROTOCOL_CTXT_ARGS(ctxt_pP),
              (srb_flagP) ? "SRB" : "DRB",
              rb_idP,
              (srb_flagP) ? "SRB" : "DRB");
      }

      rlc_union_p->mode = rlc_modeP;
      return rlc_union_p;
    } else {
      LOG_E(RLC, PROTOCOL_CTXT_FMT"[%s %u] rrc_rlc_add_rlc  FAILED %s\n",
            PROTOCOL_CTXT_ARGS(ctxt_pP),
            (srb_flagP) ? "SRB" : "DRB",
            rb_idP,
            (srb_flagP) ? "SRB" : "DRB");
      free(rlc_union_p);
      rlc_union_p = NULL;
      return NULL;
    }
  } else {
    LOG_E(RLC, PROTOCOL_CTXT_FMT"[%s %u] rrc_rlc_add_rlc , INTERNAL ERROR %s\n",
          PROTOCOL_CTXT_ARGS(ctxt_pP),
          (srb_flagP) ? "SRB" : "DRB",
          rb_idP,
          (srb_flagP) ? "SRB" : "DRB");
  }

  return NULL;
}
//-----------------------------------------------------------------------------
rlc_union_t* rrc_rlc_add_rlc   (
    const module_id_t       enb_mod_idP,
    const module_id_t       ue_mod_idP,
    const frame_t           frameP,
    const eNB_flag_t        enb_flagP,
    const srb_flag_t        srb_flagP,
    const MBMS_flag_t       MBMS_flagP,
    const rb_id_t           rb_idP,
    const logical_chan_id_t chan_idP,
    const rlc_mode_t        rlc_modeP) {
//-----------------------------------------------------------------------------
  hash_key_t             key         = HASHTABLE_QUESTIONABLE_KEY_VALUE;
  hashtable_rc_t         h_rc;
  rlc_union_t           *rlc_union_p = NULL;
#ifdef Rel10
    rlc_mbms_id_t         *mbms_id_p  = NULL;
    logical_chan_id_t      lcid            = 0;
#endif

#ifdef OAI_EMU
    if (enb_flagP) {
        AssertFatal ((enb_mod_idP >= oai_emulation.info.first_enb_local) && (oai_emulation.info.nb_enb_local > 0),
            "eNB module id is too low (%u/%d)!\n",
            enb_mod_idP,
            oai_emulation.info.first_enb_local);
        AssertFatal ((enb_mod_idP < (oai_emulation.info.first_enb_local + oai_emulation.info.nb_enb_local)) && (oai_emulation.info.nb_enb_local > 0),
            "eNB module id is too high (%u/%d)!\n",
            enb_mod_idP,
            oai_emulation.info.first_enb_local + oai_emulation.info.nb_enb_local);
        AssertFatal (ue_mod_idP  < NB_UE_INST,
            "UE module id is too high (%u/%d)!\n",
            ue_mod_idP,
            oai_emulation.info.first_ue_local + oai_emulation.info.nb_ue_local);
    } else {
        AssertFatal (ue_mod_idP  < (oai_emulation.info.first_ue_local + oai_emulation.info.nb_ue_local),
            "UE module id is too high (%u/%d)!\n",
            ue_mod_idP,
            oai_emulation.info.first_ue_local + oai_emulation.info.nb_ue_local);
        AssertFatal (ue_mod_idP  >= oai_emulation.info.first_ue_local,
            "UE module id is too low (%u/%d)!\n",
            ue_mod_idP,
            oai_emulation.info.first_ue_local);
    }
#endif
    if (MBMS_flagP == FALSE) {
        AssertFatal (rb_idP < NB_RB_MAX, "RB id is too high (%u/%d)!\n", rb_idP, NB_RB_MAX);
        AssertFatal (chan_idP < RLC_MAX_LC, "LC id is too high (%u/%d)!\n", chan_idP, RLC_MAX_LC);
    }

#ifdef Rel10
  if (MBMS_flagP == TRUE) {
      if (enb_flagP) {
          lcid = rlc_mbms_enb_get_lcid_by_rb_id(enb_mod_idP,rb_idP);
          LOG_I(RLC,
                  "[Frame %05u] lcid %d = rlc_mbms_enb_get_lcid_by_rb_id(enb_mod_idP %u, rb_idP %u)\n",
                  frameP,lcid, enb_mod_idP, rb_idP);

          mbms_id_p = &rlc_mbms_lcid2service_session_id_eNB[enb_mod_idP][lcid];

          //LG 2014-04-15rlc_mbms_lcid2service_session_id_eNB[enb_mod_idP][lcid].service_id = 0;
          //LG 2014-04-15rlc_mbms_lcid2service_session_id_eNB[enb_mod_idP][lcid].session_id = 0;
          //LG 2014-04-15rlc_mbms_rbid2lcid_eNB[enb_mod_idP][rb_idP] = RLC_LC_UNALLOCATED;
      } else {
          lcid = rlc_mbms_ue_get_lcid_by_rb_id(ue_mod_idP,rb_idP);
          mbms_id_p = &rlc_mbms_lcid2service_session_id_ue[ue_mod_idP][lcid];

          //LG 2014-04-15rlc_mbms_lcid2service_session_id_eNB[ue_mod_idP][lcid].service_id = 0;
          //LG 2014-04-15rlc_mbms_lcid2service_session_id_eNB[ue_mod_idP][lcid].session_id = 0;
          //LG 2014-04-15rlc_mbms_rbid2lcid_ue[ue_mod_idP][rb_idP] = RLC_LC_UNALLOCATED;
      }
      key = RLC_COLL_KEY_MBMS_VALUE(enb_mod_idP, ue_mod_idP, enb_flagP, mbms_id_p->service_id, mbms_id_p->session_id);
  } else
#endif
  {
      key = RLC_COLL_KEY_VALUE(enb_mod_idP, ue_mod_idP, enb_flagP, rb_idP, srb_flagP);
  }

  h_rc = hashtable_get(rlc_coll_p, key, (void**)&rlc_union_p);
  if (h_rc == HASH_TABLE_OK) {
      LOG_W(RLC, "[Frame %05u][%s][RLC_RRC][INST %u/%u][%s %u] rrc_rlc_add_rlc , already exist %s\n",
          frameP,
          (enb_flagP) ? "eNB" : "UE",
          enb_mod_idP,
          ue_mod_idP,
          (srb_flagP) ? "SRB" : "DRB",
          rb_idP,
          (srb_flagP) ? "SRB" : "DRB");
      AssertFatal(rlc_union_p->mode == rlc_modeP, "Error rrc_rlc_add_rlc , already exist but RLC mode differ");
      return rlc_union_p;
  } else if (h_rc == HASH_TABLE_KEY_NOT_EXISTS) {
      rlc_union_p = calloc(1, sizeof(rlc_union_t));
      h_rc = hashtable_insert(rlc_coll_p, key, rlc_union_p);
      if (h_rc == HASH_TABLE_OK) {
#ifdef Rel10
          if (MBMS_flagP == TRUE) {
              LOG_I(RLC, "[Frame %05u][%s][RLC_RRC][INST %u/%u] RLC service id %u session id %u rrc_rlc_add_rlc\n",
                  frameP,
                  (enb_flagP) ? "eNB" : "UE",
                  enb_mod_idP,
                  ue_mod_idP,
                  mbms_id_p->service_id,
                  mbms_id_p->session_id);
          } else
#endif
          {
              LOG_I(RLC, "[Frame %05u][%s][RLC_RRC][INST %u/%u][%s %u] rrc_rlc_add_rlc  %s\n",
                  frameP,
                  (enb_flagP) ? "eNB" : "UE",
                  enb_mod_idP,
                  ue_mod_idP,
                  (srb_flagP) ? "SRB" : "DRB",
                  rb_idP,
                  (srb_flagP) ? "SRB" : "DRB");
          }
          rlc_union_p->mode = rlc_modeP;
          return rlc_union_p;
      } else {
          LOG_E(RLC, "[Frame %05u][%s][RLC_RRC][INST %u/%u][%s %u] rrc_rlc_add_rlc  FAILED %s\n",
              frameP,
              (enb_flagP) ? "eNB" : "UE",
              enb_mod_idP,
              ue_mod_idP,
              (srb_flagP) ? "SRB" : "DRB",
              rb_idP,
              (srb_flagP) ? "SRB" : "DRB");
          free(rlc_union_p);
          rlc_union_p = NULL;
          return NULL;
      }
  } else {
      LOG_E(RLC, "[Frame %05u][%s][RLC_RRC][INST %u/%u][%s %u] rrc_rlc_add_rlc , INTERNAL ERROR %s\n",
          frameP,
          (enb_flagP) ? "eNB" : "UE",
          enb_mod_idP,
          ue_mod_idP,
          (srb_flagP) ? "SRB" : "DRB",
          rb_idP,
          (srb_flagP) ? "SRB" : "DRB");
  }
  return NULL;
}
//-----------------------------------------------------------------------------
rlc_op_status_t rrc_rlc_remove_rlc   (
  const protocol_ctxt_t* const ctxt_pP,
  const srb_flag_t  srb_flagP,
  const MBMS_flag_t MBMS_flagP,
  const rb_id_t     rb_idP)
{
  //-----------------------------------------------------------------------------
  logical_chan_id_t      lcid            = 0;
  hash_key_t             key             = HASHTABLE_NOT_A_KEY_VALUE;
  hashtable_rc_t         h_rc;
  rlc_union_t           *rlc_union_p = NULL;
#ifdef Rel10
  rlc_mbms_id_t         *mbms_id_p  = NULL;
#endif
#ifdef OAI_EMU
  CHECK_CTXT_ARGS(ctxt_pP)

#endif

#ifdef Rel10

  if (MBMS_flagP == TRUE) {
    if (ctxt_pP->enb_flag) {
      lcid = rlc_mbms_enb_get_lcid_by_rb_id(ctxt_pP->module_id,rb_idP);
      mbms_id_p = &rlc_mbms_lcid2service_session_id_eNB[ctxt_pP->module_id][lcid];
      rlc_mbms_lcid2service_session_id_eNB[ctxt_pP->module_id][lcid].service_id = 0;
      rlc_mbms_lcid2service_session_id_eNB[ctxt_pP->module_id][lcid].session_id = 0;
      rlc_mbms_rbid2lcid_ue[ctxt_pP->module_id][rb_idP] = RLC_LC_UNALLOCATED;

    } else {
      lcid = rlc_mbms_ue_get_lcid_by_rb_id(ctxt_pP->module_id,rb_idP);
      mbms_id_p = &rlc_mbms_lcid2service_session_id_ue[ctxt_pP->module_id][lcid];
      rlc_mbms_lcid2service_session_id_eNB[ctxt_pP->module_id][lcid].service_id = 0;
      rlc_mbms_lcid2service_session_id_eNB[ctxt_pP->module_id][lcid].session_id = 0;
      rlc_mbms_rbid2lcid_ue[ctxt_pP->module_id][rb_idP] = RLC_LC_UNALLOCATED;
    }

    key = RLC_COLL_KEY_MBMS_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, mbms_id_p->service_id, mbms_id_p->session_id);
  } else
#endif
  {
    key = RLC_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, rb_idP, srb_flagP);
  }


  AssertFatal (rb_idP < NB_RB_MAX, "RB id is too high (%u/%d)!\n", rb_idP, NB_RB_MAX);

  h_rc = hashtable_get(rlc_coll_p, key, (void**)&rlc_union_p);

  if (h_rc == HASH_TABLE_OK) {
    h_rc = hashtable_remove(rlc_coll_p, key);
    LOG_D(RLC, PROTOCOL_CTXT_FMT"[%s %u] RELEASED %s\n",
          PROTOCOL_CTXT_ARGS(ctxt_pP),
          (srb_flagP) ? "SRB" : "DRB",
          rb_idP,
          (srb_flagP) ? "SRB" : "DRB");
  } else if (h_rc == HASH_TABLE_KEY_NOT_EXISTS) {
    LOG_D(RLC, PROTOCOL_CTXT_FMT"[%s %u] RELEASE : RLC NOT FOUND %s\n",
          PROTOCOL_CTXT_ARGS(ctxt_pP),
          (srb_flagP) ? "SRB" : "DRB",
          rb_idP,
          (srb_flagP) ? "SRB" : "DRB");
  } else {
    LOG_E(RLC, PROTOCOL_CTXT_FMT"[%s %u] RELEASE : INTERNAL ERROR %s\n",
          PROTOCOL_CTXT_ARGS(ctxt_pP),
          (srb_flagP) ? "SRB" : "DRB",
          rb_idP,
          (srb_flagP) ? "SRB" : "DRB");
  }

  return RLC_OP_STATUS_OK;
}
//-----------------------------------------------------------------------------
rlc_op_status_t rrc_rlc_remove_rlc   (
    const module_id_t enb_mod_idP,
    const module_id_t ue_mod_idP,
    const frame_t     frameP,
    const eNB_flag_t  enb_flagP,
    const srb_flag_t  srb_flagP,
    const MBMS_flag_t MBMS_flagP,
    const rb_id_t     rb_idP) {
//-----------------------------------------------------------------------------
    logical_chan_id_t      lcid            = 0;
    hash_key_t             key             = HASHTABLE_QUESTIONABLE_KEY_VALUE;
    hashtable_rc_t         h_rc;
#ifdef Rel10
    rlc_mbms_id_t         *mbms_id_p  = NULL;
#endif
#ifdef OAI_EMU
    AssertFatal ((enb_mod_idP >= oai_emulation.info.first_enb_local) && (oai_emulation.info.nb_enb_local > 0),
        "eNB module id is too low (%u/%d)!\n",
        enb_mod_idP,
        oai_emulation.info.first_enb_local);
    AssertFatal (enb_mod_idP < (oai_emulation.info.first_enb_local + oai_emulation.info.nb_enb_local),
        "eNB module id is too high (%u/%d)!\n",
        enb_mod_idP,
        oai_emulation.info.first_enb_local + oai_emulation.info.nb_enb_local);
    if (enb_flagP) {
        AssertFatal (ue_mod_idP  < NB_UE_INST,
            "UE module id is too high (%u/%d)!\n",
            ue_mod_idP,
            oai_emulation.info.first_ue_local + oai_emulation.info.nb_ue_local);
    } else {
        AssertFatal (ue_mod_idP  < (oai_emulation.info.first_ue_local + oai_emulation.info.nb_ue_local),
            "UE module id is too high (%u/%d)!\n",
            ue_mod_idP,
            oai_emulation.info.first_ue_local + oai_emulation.info.nb_ue_local);
        AssertFatal (ue_mod_idP  >= oai_emulation.info.first_ue_local,
            "UE module id is too low (%u/%d)!\n",
            ue_mod_idP,
            oai_emulation.info.first_ue_local);
    }
#endif

#ifdef Rel10
  if (MBMS_flagP == TRUE) {
      if (enb_flagP) {
          lcid = rlc_mbms_enb_get_lcid_by_rb_id(enb_mod_idP,rb_idP);
          mbms_id_p = &rlc_mbms_lcid2service_session_id_eNB[enb_mod_idP][lcid];

          rlc_mbms_lcid2service_session_id_eNB[enb_mod_idP][lcid].service_id = 0;
          rlc_mbms_lcid2service_session_id_eNB[enb_mod_idP][lcid].session_id = 0;
          rlc_mbms_rbid2lcid_ue[enb_mod_idP][rb_idP] = RLC_LC_UNALLOCATED;
      } else {
          lcid = rlc_mbms_ue_get_lcid_by_rb_id(ue_mod_idP,rb_idP);
          mbms_id_p = &rlc_mbms_lcid2service_session_id_ue[ue_mod_idP][lcid];

          rlc_mbms_lcid2service_session_id_eNB[ue_mod_idP][lcid].service_id = 0;
          rlc_mbms_lcid2service_session_id_eNB[ue_mod_idP][lcid].session_id = 0;
          rlc_mbms_rbid2lcid_ue[ue_mod_idP][rb_idP] = RLC_LC_UNALLOCATED;
      }
      key = RLC_COLL_KEY_MBMS_VALUE(enb_mod_idP, ue_mod_idP, enb_flagP, mbms_id_p->service_id, mbms_id_p->session_id);
  } else
#endif
  {
      key = RLC_COLL_KEY_VALUE(enb_mod_idP, ue_mod_idP, enb_flagP, rb_idP, srb_flagP);
  }


    AssertFatal (rb_idP < NB_RB_MAX, "RB id is too high (%u/%d)!\n", rb_idP, NB_RB_MAX);

    h_rc = hashtable_remove(rlc_coll_p, key);
    if (h_rc == HASH_TABLE_OK) {
        LOG_D(RLC, "[Frame %05u][%s][RLC_RRC][INST %u/%u][%s %u] RELEASED %s\n",
            frameP,
            (enb_flagP) ? "eNB" : "UE",
            enb_mod_idP,
            ue_mod_idP,
            (srb_flagP) ? "SRB" : "DRB",
            rb_idP,
            (srb_flagP) ? "SRB" : "DRB");
    } else if (h_rc == HASH_TABLE_KEY_NOT_EXISTS) {
        LOG_W(RLC, "[Frame %05u][%s][RLC_RRC][INST %u/%u][%s %u] RELEASE : RLC NOT FOUND %s\n",
            frameP,
            (enb_flagP) ? "eNB" : "UE",
            enb_mod_idP,
            ue_mod_idP,
            (srb_flagP) ? "SRB" : "DRB",
            rb_idP,
            (srb_flagP) ? "SRB" : "DRB");
    } else {
        LOG_E(RLC, "[Frame %05u][%s][RLC_RRC][INST %u/%u][%s %u] RELEASE : INTERNAL ERROR %s\n",
            frameP,
            (enb_flagP) ? "eNB" : "UE",
            enb_mod_idP,
            ue_mod_idP,
            (srb_flagP) ? "SRB" : "DRB",
            rb_idP,
            (srb_flagP) ? "SRB" : "DRB");    }

    return RLC_OP_STATUS_OK;
}