laforge has submitted this change. ( https://gerrit.osmocom.org/c/osmo-hnbgw/+/36311?usp=email )
Change subject: RAB activation/modification/release statistics ......................................................................
RAB activation/modification/release statistics
Add rate_ctr based statistics for RAB activation, deactivation and failures. This requires us to parse RANAP in both uplink and downlink and to iterate deep into the setup/modify/release/failure lists.
Given the way how the protocol works, the only way to distinguish an activation from a modification is because sender and recipient know whether a given RAB is already active at the time of the message. So we also need to track the activation state of each RAB.
Depends: osmo-iuh.git Change-Id I328819c650fc6cefe735093a846277b4f03e6b29 Change-Id: I198fa37699e22380909764de6a0522ac79aa1d39 --- M include/osmocom/hnbgw/Makefile.am M include/osmocom/hnbgw/context_map.h M include/osmocom/hnbgw/hnbgw.h A include/osmocom/hnbgw/kpi.h M src/osmo-hnbgw/Makefile.am M src/osmo-hnbgw/context_map_rua.c M src/osmo-hnbgw/context_map_sccp.c M src/osmo-hnbgw/hnbgw.c A src/osmo-hnbgw/kpi_ranap.c 9 files changed, 504 insertions(+), 0 deletions(-)
Approvals: Jenkins Builder: Verified pespin: Looks good to me, but someone else must approve laforge: Looks good to me, approved fixeria: Looks good to me, but someone else must approve
diff --git a/include/osmocom/hnbgw/Makefile.am b/include/osmocom/hnbgw/Makefile.am index b6824b3..6338e4e 100644 --- a/include/osmocom/hnbgw/Makefile.am +++ b/include/osmocom/hnbgw/Makefile.am @@ -2,6 +2,7 @@ vty.h \ context_map.h hnbgw.h hnbgw_cn.h \ hnbgw_hnbap.h hnbgw_rua.h hnbgw_ranap.h \ + kpi.h \ ranap_rab_ass.h mgw_fsm.h tdefs.h \ hnbgw_pfcp.h \ ps_rab_ass_fsm.h \ diff --git a/include/osmocom/hnbgw/context_map.h b/include/osmocom/hnbgw/context_map.h index d401635..1e23777 100644 --- a/include/osmocom/hnbgw/context_map.h +++ b/include/osmocom/hnbgw/context_map.h @@ -101,6 +101,14 @@ bool from_other_plmn; };
+/* used in hnbgw_context_map.rab_state[] */ +enum rab_state { + RAB_STATE_INACTIVE, + RAB_STATE_ACT_REQ, + RAB_STATE_ACTIVE, + RAB_STATE_REL_REQ, +}; + struct hnbgw_context_map { /* entry in the per-CN list of mappings */ struct llist_head hnbgw_cnlink_entry; @@ -160,6 +168,9 @@ * communication for one particular RAB ID. */ struct llist_head ps_rabs;
+ /* RAB state tracking. As RAB-ID is an 8-bit integer, we need 256 elements in the array */ + uint8_t rab_state[256]; + /* Flag to prevent calling context_map_free() from cleanup code paths triggered by context_map_free() itself. */ bool deallocating; }; diff --git a/include/osmocom/hnbgw/hnbgw.h b/include/osmocom/hnbgw/hnbgw.h index bd8a853..b3ba3b2 100644 --- a/include/osmocom/hnbgw/hnbgw.h +++ b/include/osmocom/hnbgw/hnbgw.h @@ -80,6 +80,36 @@ HNB_CTR_RANAP_PS_RESET_REQ_UL, HNB_CTR_RANAP_CS_RESET_REQ_UL,
+ HNB_CTR_RANAP_PS_RAB_ACT_REQ, + HNB_CTR_RANAP_CS_RAB_ACT_REQ, + + HNB_CTR_RANAP_PS_RAB_ACT_CNF, + HNB_CTR_RANAP_CS_RAB_ACT_CNF, + + HNB_CTR_RANAP_PS_RAB_ACT_FAIL, + HNB_CTR_RANAP_CS_RAB_ACT_FAIL, + + HNB_CTR_RANAP_PS_RAB_MOD_REQ, + HNB_CTR_RANAP_CS_RAB_MOD_REQ, + + HNB_CTR_RANAP_PS_RAB_MOD_CNF, + HNB_CTR_RANAP_CS_RAB_MOD_CNF, + + HNB_CTR_RANAP_PS_RAB_MOD_FAIL, + HNB_CTR_RANAP_CS_RAB_MOD_FAIL, + + HNB_CTR_RANAP_PS_RAB_REL_REQ, + HNB_CTR_RANAP_CS_RAB_REL_REQ, + + HNB_CTR_RANAP_PS_RAB_REL_CNF, + HNB_CTR_RANAP_CS_RAB_REL_CNF, + + HNB_CTR_RANAP_PS_RAB_REL_FAIL, + HNB_CTR_RANAP_CS_RAB_REL_FAIL, + + HNB_CTR_RANAP_PS_RAB_REL_IMPLICIT, + HNB_CTR_RANAP_CS_RAB_REL_IMPLICIT, + HNB_CTR_RUA_ERR_IND,
HNB_CTR_RUA_PS_CONNECT_UL, @@ -301,6 +331,7 @@
#define HNBP_CTR(hnbp, x) rate_ctr_group_get_ctr((hnbp)->ctrs, x) #define HNBP_CTR_INC(hnbp, x) rate_ctr_inc(HNBP_CTR(hnbp, x)) +#define HNBP_CTR_ADD(hnbp, x, y) rate_ctr_add2((hnbp)->ctrs, x, y)
#define HNBP_STAT(hbp, x) osmo_stat_item_group_get_item((hnbp)->statg, x) #define HNBP_STAT_SET(hnbp, x, val) osmo_stat_item_set(HNBP_STAT(hnbp, x), val) diff --git a/include/osmocom/hnbgw/kpi.h b/include/osmocom/hnbgw/kpi.h new file mode 100644 index 0000000..63f3477 --- /dev/null +++ b/include/osmocom/hnbgw/kpi.h @@ -0,0 +1,8 @@ +#pragma once + +#include <osmocom/ranap/ranap_ies_defs.h> + +#include <osmocom/hnbgw/hnbgw.h> + +void kpi_ranap_process_ul(struct hnbgw_context_map *map, ranap_message *ranap); +void kpi_ranap_process_dl(struct hnbgw_context_map *map, ranap_message *ranap); diff --git a/src/osmo-hnbgw/Makefile.am b/src/osmo-hnbgw/Makefile.am index 910fdda..0727f30 100644 --- a/src/osmo-hnbgw/Makefile.am +++ b/src/osmo-hnbgw/Makefile.am @@ -44,6 +44,7 @@ cnlink.c \ ranap_rab_ass.c \ mgw_fsm.c \ + kpi_ranap.c \ tdefs.c \ $(NULL)
diff --git a/src/osmo-hnbgw/context_map_rua.c b/src/osmo-hnbgw/context_map_rua.c index 2263792..a943a64 100644 --- a/src/osmo-hnbgw/context_map_rua.c +++ b/src/osmo-hnbgw/context_map_rua.c @@ -36,6 +36,7 @@ #include <osmocom/hnbgw/hnbgw_rua.h> #include <osmocom/hnbgw/mgw_fsm.h> #include <osmocom/hnbgw/ps_rab_ass_fsm.h> +#include <osmocom/hnbgw/kpi.h>
enum map_rua_fsm_state { MAP_RUA_ST_INIT, @@ -168,6 +169,8 @@ LOGPFSML(fi, LOGL_DEBUG, "rx from RUA: RANAP %s\n", get_value_string(ranap_procedure_code_vals, message->procedureCode));
+ kpi_ranap_process_ul(map, message); + switch (message->procedureCode) { case RANAP_ProcedureCode_id_RAB_Assignment: /* mgw_fsm_handle_rab_ass_resp() takes ownership of prim->oph and (ranap) message */ @@ -182,6 +185,8 @@ LOGPFSML(fi, LOGL_DEBUG, "rx from RUA: RANAP %s\n", get_value_string(ranap_procedure_code_vals, message->procedureCode));
+ kpi_ranap_process_ul(map, message); + switch (message->procedureCode) { case RANAP_ProcedureCode_id_RAB_Assignment: /* ps_rab_ass_fsm takes ownership of prim->oph and RANAP message */ diff --git a/src/osmo-hnbgw/context_map_sccp.c b/src/osmo-hnbgw/context_map_sccp.c index 5eb97e2..e7e27b6 100644 --- a/src/osmo-hnbgw/context_map_sccp.c +++ b/src/osmo-hnbgw/context_map_sccp.c @@ -38,6 +38,7 @@ #include <osmocom/hnbgw/tdefs.h> #include <osmocom/hnbgw/mgw_fsm.h> #include <osmocom/hnbgw/ps_rab_ass_fsm.h> +#include <osmocom/hnbgw/kpi.h>
enum map_sccp_fsm_state { MAP_SCCP_ST_INIT, @@ -215,6 +216,8 @@ LOGPFSML(fi, LOGL_DEBUG, "rx from SCCP: RANAP %s\n", get_value_string(ranap_procedure_code_vals, message->procedureCode));
+ kpi_ranap_process_dl(map, message); + switch (message->procedureCode) { case RANAP_ProcedureCode_id_RAB_Assignment: /* mgw_fsm_alloc_and_handle_rab_ass_req() takes ownership of (ranap) message */ @@ -239,6 +242,8 @@ LOGPFSML(fi, LOGL_DEBUG, "rx from SCCP: RANAP %s\n", get_value_string(ranap_procedure_code_vals, message->procedureCode));
+ kpi_ranap_process_dl(map, message); + switch (message->procedureCode) {
case RANAP_ProcedureCode_id_RAB_Assignment: diff --git a/src/osmo-hnbgw/hnbgw.c b/src/osmo-hnbgw/hnbgw.c index e1bac5f..fff900a 100644 --- a/src/osmo-hnbgw/hnbgw.c +++ b/src/osmo-hnbgw/hnbgw.c @@ -364,6 +364,59 @@ [HNB_CTR_RANAP_CS_RESET_REQ_UL] = { "ranap:cs:reset_req:ul", "Received RESET Requests in Uplink (CS Domain)" },
+ + [HNB_CTR_RANAP_PS_RAB_ACT_REQ] = { + "ranap:ps:rab_act:req", "PS RAB Activations requested" }, + [HNB_CTR_RANAP_CS_RAB_ACT_REQ] = { + "ranap:cs:rab_act:req", "CS RAB Activations requested" }, + + [HNB_CTR_RANAP_PS_RAB_ACT_CNF] = { + "ranap:ps:rab_act:cnf", "PS RAB Activations confirmed" }, + [HNB_CTR_RANAP_CS_RAB_ACT_CNF] = { + "ranap:cs:rab_act:cnf", "CS RAB Activations confirmed" }, + + [HNB_CTR_RANAP_PS_RAB_ACT_FAIL] = { + "ranap:ps:rab_act:fail", "PS RAB Activations failed" }, + [HNB_CTR_RANAP_CS_RAB_ACT_FAIL] = { + "ranap:cs:rab_act:fail", "CS RAB Activations failed" }, + + + [HNB_CTR_RANAP_PS_RAB_MOD_REQ] = { + "ranap:ps:rab_mod:req", "PS RAB Modifications requested" }, + [HNB_CTR_RANAP_CS_RAB_MOD_REQ] = { + "ranap:cs:rab_mod:req", "CS RAB Modifications requested" }, + + [HNB_CTR_RANAP_PS_RAB_MOD_CNF] = { + "ranap:ps:rab_mod:cnf", "PS RAB Modifications confirmed" }, + [HNB_CTR_RANAP_CS_RAB_MOD_CNF] = { + "ranap:cs:rab_mod:cnf", "CS RAB Modifications confirmed" }, + + [HNB_CTR_RANAP_PS_RAB_MOD_FAIL] = { + "ranap:ps:rab_mod:fail", "PS RAB Modifications failed" }, + [HNB_CTR_RANAP_CS_RAB_MOD_FAIL] = { + "ranap:cs:rab_mod:fail", "CS RAB Modifications failed" }, + + + [HNB_CTR_RANAP_PS_RAB_REL_REQ] = { + "ranap:ps:rab_rel:req", "PS RAB Release requested" }, + [HNB_CTR_RANAP_CS_RAB_REL_REQ] = { + "ranap:cs:rab_rel:req", "CS RAB Release requested" }, + + [HNB_CTR_RANAP_PS_RAB_REL_CNF] = { + "ranap:ps:rab_rel:cnf", "PS RAB Release confirmed" }, + [HNB_CTR_RANAP_CS_RAB_REL_CNF] = { + "ranap:cs:rab_rel:cnf", "CS RAB Release confirmed" }, + + [HNB_CTR_RANAP_PS_RAB_REL_FAIL] = { + "ranap:ps:rab_rel:fail", "PS RAB Release failed" }, + [HNB_CTR_RANAP_CS_RAB_REL_FAIL] = { + "ranap:cs:rab_rel:fail", "CS RAB Release failed" }, + + [HNB_CTR_RANAP_PS_RAB_REL_IMPLICIT] = { + "ranap:ps:rab_rel:implicit", "PS RAB Release implicit (during Iu Release)" }, + [HNB_CTR_RANAP_CS_RAB_REL_IMPLICIT] = { + "ranap:cs:rab_rel:implicit", "CS RAB Release implicit (during Iu Release)" }, + [HNB_CTR_RUA_ERR_IND] = { "rua:error_ind", "Received RUA Error Indications" },
diff --git a/src/osmo-hnbgw/kpi_ranap.c b/src/osmo-hnbgw/kpi_ranap.c new file mode 100644 index 0000000..76f6e22 --- /dev/null +++ b/src/osmo-hnbgw/kpi_ranap.c @@ -0,0 +1,370 @@ +/* KPI (statistics, counters) at RANAP level */ +/* (C) 2024 by Harald Welte laforge@osmocom.org + * All Rights Reserved + * + * SPDX-License-Identifier: AGPL-3.0+ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ + +#include "config.h" + +#include <osmocom/core/utils.h> + +#include <osmocom/ranap/ranap_common_ran.h> + +#include <osmocom/hnbgw/hnbgw_cn.h> +#include <osmocom/hnbgw/context_map.h> +#include <osmocom/hnbgw/kpi.h> + + +/*********************************************************************** + * DOWNLINK messages + ***********************************************************************/ + +static void kpi_ranap_process_dl_iu_rel_cmd(struct hnbgw_context_map *map, const ranap_message *ranap) +{ + struct hnb_persistent *hnbp = map->hnb_ctx->persistent; + + OSMO_ASSERT(ranap->procedureCode == RANAP_ProcedureCode_id_Iu_Release); + + /* When Iu is released, all RABs are released implicitly */ + for (unsigned int i = 0; i < ARRAY_SIZE(map->rab_state); i++) { + switch (map->rab_state[i]) { + case RAB_STATE_ACTIVE: + HNBP_CTR_INC(hnbp, map->is_ps ? HNB_CTR_RANAP_PS_RAB_REL_IMPLICIT : HNB_CTR_RANAP_CS_RAB_REL_IMPLICIT); + break; + } + } + /* clear all RAB state */ + memset(map->rab_state, 0, sizeof(map->rab_state)); +} + +static void kpi_ranap_process_dl_rab_ass_req(struct hnbgw_context_map *map, ranap_message *ranap) +{ + struct hnb_persistent *hnbp = map->hnb_ctx->persistent; + RANAP_RAB_AssignmentRequestIEs_t *ies; + int rc; + + OSMO_ASSERT(ranap->procedureCode == RANAP_ProcedureCode_id_RAB_Assignment); + + ies = &ranap->msg.raB_AssignmentRequestIEs; + + if (ies->presenceMask & RAB_ASSIGNMENTREQUESTIES_RANAP_RAB_SETUPORMODIFYLIST_PRESENT) { + RANAP_RAB_SetupOrModifyList_t *som_list = &ies->raB_SetupOrModifyList; + for (unsigned int i = 0; i < som_list->list.count; i++) { + RANAP_ProtocolIE_ContainerPair_t *container_pair = som_list->list.array[i]; + RANAP_ProtocolIE_FieldPair_t *field_pair = container_pair->list.array[0]; + RANAP_RAB_SetupOrModifyItemFirst_t _rab_setup_or_modify_item_first = {}; + RANAP_RAB_SetupOrModifyItemFirst_t *rab_setup_or_modify_item_first = &_rab_setup_or_modify_item_first; + uint8_t rab_id; + + if (!field_pair) + continue; + + if (field_pair->id != RANAP_ProtocolIE_ID_id_RAB_SetupOrModifyItem) + continue; + + rc = ranap_decode_rab_setupormodifyitemfirst(rab_setup_or_modify_item_first, &field_pair->firstValue); + if (rc < 0) + continue; + + /* RAB-ID is an 8-bit bit-string, so it's the first byte */ + rab_id = rab_setup_or_modify_item_first->rAB_ID.buf[0]; + + /* the only way to distinguish a "setup" from a "modify" is to know which RABs are + * already established. If it's already established, it is a modification; if it's + * new, it is a setup */ + switch (map->rab_state[rab_id]) { + case RAB_STATE_ACTIVE: + HNBP_CTR_INC(hnbp, map->is_ps ? HNB_CTR_RANAP_PS_RAB_MOD_REQ : HNB_CTR_RANAP_CS_RAB_MOD_REQ); + break; + case RAB_STATE_INACTIVE: + HNBP_CTR_INC(hnbp, map->is_ps ? HNB_CTR_RANAP_PS_RAB_ACT_REQ : HNB_CTR_RANAP_CS_RAB_ACT_REQ); + map->rab_state[rab_id] = RAB_STATE_ACT_REQ; + break; + default: + LOG_MAP(map, DRANAP, LOGL_NOTICE, + "Unexpected RAB Activation/Modification Req for RAB in state %u\n", map->rab_state[rab_id]); + break; + } + + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_RAB_SetupOrModifyItemFirst, rab_setup_or_modify_item_first); + } + } + + if (ies->presenceMask & RAB_ASSIGNMENTREQUESTIES_RANAP_RAB_RELEASELIST_PRESENT) { + RANAP_RAB_ReleaseList_t *r_list = &ies->raB_ReleaseList; + /* increment number of released RABs, we don't need to do that individually during iteration */ + HNBP_CTR_ADD(hnbp, map->is_ps ? HNB_CTR_RANAP_PS_RAB_REL_REQ : HNB_CTR_RANAP_CS_RAB_REL_REQ, + r_list->raB_ReleaseList_ies.list.count); + + for (unsigned int i = 0; i < r_list->raB_ReleaseList_ies.list.count; i++) { + RANAP_IE_t *release_list_ie = r_list->raB_ReleaseList_ies.list.array[i]; + RANAP_RAB_ReleaseItemIEs_t _rab_rel_item_ies = {}; + RANAP_RAB_ReleaseItemIEs_t *rab_rel_item_ies = &_rab_rel_item_ies; + RANAP_RAB_ReleaseItem_t *rab_rel_item; + uint8_t rab_id; + + if (!release_list_ie) + continue; + + if (release_list_ie->id != RANAP_ProtocolIE_ID_id_RAB_ReleaseItem) + continue; + + rc = ranap_decode_rab_releaseitemies_fromlist(rab_rel_item_ies, &release_list_ie->value); + if (rc < 0) + continue; + + rab_rel_item = &rab_rel_item_ies->raB_ReleaseItem; + /* RAB-ID is an 8-bit bit-string, so it's the first byte */ + rab_id = rab_rel_item->rAB_ID.buf[0]; + + switch (map->rab_state[rab_id]) { + case RAB_STATE_ACTIVE: + break; + default: + LOG_MAP(map, DRANAP, LOGL_NOTICE, + "Unexpected RAB Release Req in state %u\n", map->rab_state[rab_id]); + break; + } + /* mark that RAB as release requested */ + map->rab_state[rab_id] = RAB_STATE_REL_REQ; + + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_RAB_ReleaseItem, rab_rel_item_ies); + } + } +} + +void kpi_ranap_process_dl(struct hnbgw_context_map *map, ranap_message *ranap) +{ + switch (ranap->procedureCode) { + case RANAP_ProcedureCode_id_RAB_Assignment: /* RAB ASSIGNMENT REQ (8.2) */ + kpi_ranap_process_dl_rab_ass_req(map, ranap); + break; + case RANAP_ProcedureCode_id_Iu_Release: + kpi_ranap_process_dl_iu_rel_cmd(map, ranap); /* IU RELEASE CMD (8.5) */ + break; + default: + break; + } +} + +/*********************************************************************** + * UPLINK messages + ***********************************************************************/ + +static void kpi_ranap_process_ul_rab_ass_resp(struct hnbgw_context_map *map, ranap_message *ranap) +{ + struct hnb_persistent *hnbp = map->hnb_ctx->persistent; + RANAP_RAB_AssignmentResponseIEs_t *ies; + int rc; + + OSMO_ASSERT(ranap->procedureCode == RANAP_ProcedureCode_id_RAB_Assignment); + + ies = &ranap->msg.raB_AssignmentResponseIEs; + + if (ies->presenceMask & RAB_ASSIGNMENTRESPONSEIES_RANAP_RAB_SETUPORMODIFIEDLIST_PRESENT) { + RANAP_RAB_SetupOrModifiedList_t *som_list = &ies->raB_SetupOrModifiedList; + for (unsigned int i = 0; i < som_list->raB_SetupOrModifiedList_ies.list.count; i++) { + RANAP_IE_t *som_list_ie = som_list->raB_SetupOrModifiedList_ies.list.array[i]; + RANAP_RAB_SetupOrModifiedItemIEs_t _rab_som_item_ies = {}; + RANAP_RAB_SetupOrModifiedItemIEs_t *rab_som_item_ies = &_rab_som_item_ies; + RANAP_RAB_SetupOrModifiedItem_t *rab_som_item; + uint8_t rab_id; + + if (!som_list_ie) + continue; + + if (som_list_ie->id != RANAP_ProtocolIE_ID_id_RAB_SetupOrModifiedItem) + continue; + + rc = ranap_decode_rab_setupormodifieditemies_fromlist(rab_som_item_ies, &som_list_ie->value); + if (rc < 0) + continue; + + rab_som_item = &rab_som_item_ies->raB_SetupOrModifiedItem; + /* RAB-ID is an 8-bit bit-string, so it's the first byte */ + rab_id = rab_som_item->rAB_ID.buf[0]; + + /* differentiate modify / activate */ + switch (map->rab_state[rab_id]) { + case RAB_STATE_ACT_REQ: + HNBP_CTR_INC(hnbp, map->is_ps ? HNB_CTR_RANAP_PS_RAB_ACT_CNF : HNB_CTR_RANAP_CS_RAB_ACT_CNF); + map->rab_state[rab_id] = RAB_STATE_ACTIVE; + break; + case RAB_STATE_ACTIVE: + HNBP_CTR_INC(hnbp, map->is_ps ? HNB_CTR_RANAP_PS_RAB_MOD_CNF : HNB_CTR_RANAP_CS_RAB_MOD_CNF); + break; + default: + LOG_MAP(map, DRANAP, LOGL_NOTICE, + "Unexpected RAB Activation/Modification Conf for RAB in state %u\n", map->rab_state[rab_id]); + break; + } + + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_RAB_SetupOrModifiedItem, rab_som_item_ies); + } + } + + if (ies->presenceMask & RAB_ASSIGNMENTRESPONSEIES_RANAP_RAB_RELEASEDLIST_PRESENT) { + RANAP_RAB_ReleasedList_t *r_list = &ies->raB_ReleasedList; + /* increment number of released RABs, we don't need to do that individually during iteration */ + HNBP_CTR_ADD(hnbp, map->is_ps ? HNB_CTR_RANAP_PS_RAB_REL_CNF : HNB_CTR_RANAP_CS_RAB_REL_CNF, + r_list->raB_ReleasedList_ies.list.count); + for (unsigned int i = 0; i < r_list->raB_ReleasedList_ies.list.count; i++) { + RANAP_IE_t *released_list_ie = r_list->raB_ReleasedList_ies.list.array[i]; + RANAP_RAB_ReleasedItemIEs_t _rab_rel_item_ies = {}; + RANAP_RAB_ReleasedItemIEs_t *rab_rel_item_ies = &_rab_rel_item_ies; + RANAP_RAB_ReleasedItem_t *rab_rel_item; + uint8_t rab_id; + + if (!released_list_ie) + continue; + + if (released_list_ie->id != RANAP_ProtocolIE_ID_id_RAB_ReleasedItem) + continue; + + rc = ranap_decode_rab_releaseditemies_fromlist(rab_rel_item_ies, &released_list_ie->value); + if (rc < 0) + continue; + + rab_rel_item = &rab_rel_item_ies->raB_ReleasedItem; + /* RAB-ID is an 8-bit bit-string, so it's the first byte */ + rab_id = rab_rel_item->rAB_ID.buf[0]; + + switch (map->rab_state[rab_id]) { + case RAB_STATE_REL_REQ: + break; + default: + LOG_MAP(map, DRANAP, LOGL_NOTICE, + "Unexpected RAB Release Conf for RAB in state %u\n", map->rab_state[rab_id]); + break; + } + /* mark that RAB as released */ + map->rab_state[rab_id] = RAB_STATE_INACTIVE; + + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_RAB_ReleasedItem, rab_rel_item_ies); + } + } + + if (ies->presenceMask & RAB_ASSIGNMENTRESPONSEIES_RANAP_RAB_QUEUEDLIST_PRESENT) + LOG_MAP(map, DRANAP, LOGL_NOTICE, "RAB Activation has been queued; we don't support KPIs for this\n"); + + if (ies->presenceMask & RAB_ASSIGNMENTRESPONSEIES_RANAP_RAB_FAILEDLIST_PRESENT) { + RANAP_RAB_FailedList_t *f_list = &ies->raB_FailedList; + for (unsigned int i = 0; i < f_list->raB_FailedList_ies.list.count; i++) { + RANAP_IE_t *failed_list_ie = f_list->raB_FailedList_ies.list.array[i]; + RANAP_RAB_FailedItemIEs_t _rab_failed_item_ies = {}; + RANAP_RAB_FailedItemIEs_t *rab_failed_item_ies = &_rab_failed_item_ies; + RANAP_RAB_FailedItem_t *rab_failed_item; + uint8_t rab_id; + + if (!failed_list_ie) + continue; + + if (failed_list_ie->id != RANAP_ProtocolIE_ID_id_RAB_FailedItem) + continue; + + rc = ranap_decode_rab_faileditemies_fromlist(rab_failed_item_ies, &failed_list_ie->value); + if (rc < 0) + continue; + + rab_failed_item = &rab_failed_item_ies->raB_FailedItem; + /* RAB-ID is an 8-bit bit-string, so it's the first byte */ + rab_id = rab_failed_item->rAB_ID.buf[0]; + + /* differentiate modify / activate */ + switch (map->rab_state[rab_id]) { + case RAB_STATE_ACT_REQ: + HNBP_CTR_INC(hnbp, map->is_ps ? HNB_CTR_RANAP_PS_RAB_ACT_FAIL : HNB_CTR_RANAP_CS_RAB_ACT_FAIL); + map->rab_state[rab_id] = RAB_STATE_INACTIVE; + break; + case RAB_STATE_ACTIVE: + HNBP_CTR_INC(hnbp, map->is_ps ? HNB_CTR_RANAP_PS_RAB_MOD_FAIL : HNB_CTR_RANAP_CS_RAB_MOD_FAIL); + // FIXME: does it remain active after modification failure? + break; + default: + LOG_MAP(map, DRANAP, LOGL_NOTICE, + "Unexpected RAB Activation/Modification Failed for RAB in state %u\n", map->rab_state[rab_id]); + break; + } + + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_RAB_FailedItem, rab_failed_item_ies); + } + } + + if (ies->presenceMask & RAB_ASSIGNMENTRESPONSEIES_RANAP_RAB_RELEASEFAILEDLIST_PRESENT) { + RANAP_RAB_ReleaseFailedList_t *rf_list = &ies->raB_ReleaseFailedList; + /* increment number of released RABs, we don't need to do that individually during iteration */ + HNBP_CTR_ADD(hnbp, map->is_ps ? HNB_CTR_RANAP_PS_RAB_REL_FAIL : HNB_CTR_RANAP_CS_RAB_REL_FAIL, + rf_list->raB_FailedList_ies.list.count); + for (unsigned int i = 0; i < rf_list->raB_FailedList_ies.list.count; i++) { + RANAP_IE_t *failed_list_ie = rf_list->raB_FailedList_ies.list.array[i]; + RANAP_RAB_FailedItemIEs_t _rab_failed_item_ies = {}; + RANAP_RAB_FailedItemIEs_t *rab_failed_item_ies = &_rab_failed_item_ies; + RANAP_RAB_FailedItem_t *rab_failed_item; + uint8_t rab_id; + + if (!failed_list_ie) + continue; + + if (failed_list_ie->id != RANAP_ProtocolIE_ID_id_RAB_FailedItem) + continue; + + rc = ranap_decode_rab_faileditemies_fromlist(rab_failed_item_ies, &failed_list_ie->value); + if (rc < 0) + continue; + + rab_failed_item = &rab_failed_item_ies->raB_FailedItem; + /* RAB-ID is an 8-bit bit-string, so it's the first byte */ + rab_id = rab_failed_item->rAB_ID.buf[0]; + + /* differentiate modify / activate */ + switch (map->rab_state[rab_id]) { + case RAB_STATE_ACT_REQ: + HNBP_CTR_INC(hnbp, map->is_ps ? HNB_CTR_RANAP_PS_RAB_ACT_FAIL : HNB_CTR_RANAP_CS_RAB_ACT_FAIL); + map->rab_state[rab_id] = RAB_STATE_INACTIVE; + break; + case RAB_STATE_ACTIVE: + HNBP_CTR_INC(hnbp, map->is_ps ? HNB_CTR_RANAP_PS_RAB_MOD_FAIL : HNB_CTR_RANAP_CS_RAB_MOD_FAIL); + // FIXME: does it remain active after modification failure? + break; + default: + LOG_MAP(map, DRANAP, LOGL_NOTICE, + "Unexpected RAB Release Failed for RAB in state %u\n", map->rab_state[rab_id]); + break; + } + + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_RAB_FailedItem, rab_failed_item_ies); + + } + } +} + +void kpi_ranap_process_ul(struct hnbgw_context_map *map, ranap_message *ranap) +{ + switch (ranap->procedureCode) { + case RANAP_ProcedureCode_id_RAB_Assignment: /* RAB ASSIGNMENT REQ (8.2) */ + kpi_ranap_process_ul_rab_ass_resp(map, ranap); + break; + case RANAP_ProcedureCode_id_Iu_Release: + /* TODO: We might want to parse the list of released RABs here and then mark each of those as + * released. For now we simply assume that all RABs are released in IU RELEASE during + * processing of the downlink Iu Release Command. It's not like the RNC/HNB has any way to + * refuse the release anyway. */ + break; + default: + break; + } +}