laforge has submitted this change. ( 
https://gerrit.osmocom.org/c/osmo-hnbgw/+/36081?usp=email )

Change subject: Introduce concept of per-HNB persistent data structure
......................................................................

Introduce concept of per-HNB persistent data structure

This allows us to add a new "hnb-policy closed", which means we do not
accept any random HNB connection anymore, but only those whose identity
is pre-configured explicitly using administrative means.

Furthermore, this new data structure will allow us (in future patches)
to keep persistent data like uptime / downtime of each HNB.

Related: SYS#6773
Change-Id: Ife89a7a206836bd89334d19d3cf8c92969dd74de
---
M include/osmocom/hnbgw/hnbgw.h
M include/osmocom/hnbgw/vty.h
M src/osmo-hnbgw/hnbgw.c
M src/osmo-hnbgw/hnbgw_hnbap.c
M src/osmo-hnbgw/hnbgw_rua.c
M src/osmo-hnbgw/hnbgw_vty.c
M tests/osmo-hnbgw.vty
7 files changed, 223 insertions(+), 10 deletions(-)

Approvals:
  laforge: Looks good to me, approved; Verified




diff --git a/include/osmocom/hnbgw/hnbgw.h b/include/osmocom/hnbgw/hnbgw.h
index 62b548c..864d7ee 100644
--- a/include/osmocom/hnbgw/hnbgw.h
+++ b/include/osmocom/hnbgw/hnbgw.h
@@ -71,16 +71,34 @@
 #define IUH_MSGB_SIZE  2048

 struct umts_cell_id {
-       uint16_t mcc;   /*!< Mobile Country Code */
-       uint16_t mnc;   /*!< Mobile Network Code */
-       uint16_t lac;   /*!< Locaton Area Code */
-       uint16_t rac;   /*!< Routing Area Code */
+       uint16_t mcc;   /*!< Mobile Country Code (0-999) */
+       uint16_t mnc;   /*!< Mobile Network Code (0-999) */
+       uint16_t lac;   /*!< Locaton Area Code (1-65534) */
+       uint16_t rac;   /*!< Routing Area Code (0-255) */
        uint16_t sac;   /*!< Service Area Code */
        uint32_t cid;   /*!< Cell ID */
 };
 const char *umts_cell_id_name(const struct umts_cell_id *ucid);
 int umts_cell_id_from_str(struct umts_cell_id *ucid, const char *instr);

+/*! are both given umts_cell_id euqal? */
+static inline bool umts_cell_id_equal(const struct umts_cell_id *a, const 
struct umts_cell_id *b)
+{
+       if (a->mcc != b->mcc)
+               return false;
+       if (a->mnc != b->mnc)
+               return false;
+       if (a->lac != b->lac)
+               return false;
+       if (a->rac != b->rac)
+               return false;
+       if (a->sac != b->sac)
+               return false;
+       if (a->cid != b->cid)
+               return false;
+       return true;
+}
+
 struct hnbgw_context_map;

 /* osmo-hnbgw keeps a single hnbgw_sccp_user per osmo_sccp_instance, for the 
local point-code and SSN == RANAP.
@@ -234,6 +252,22 @@

        /* linked list of hnbgw_context_map */
        struct llist_head map_list;
+
+       /*! pointer to the associated hnb persistent state */
+       struct hnb_persistent *persistent;
+};
+
+/* persistent data for one HNB.  This continues to exist even as conn / 
hnb_context is deleted on disconnect */
+struct hnb_persistent {
+       /*! Entry in HNBGW-global list of hnb_persistent */
+       struct llist_head list;
+       /*! back-pointer to hnb_context.  Can be NULL if no context at this 
point */
+       struct hnb_context *ctx;
+
+       /*! unique cell identity; copied from HNB REGISTER REQ */
+       struct umts_cell_id id;
+       /*! stringified version of the cell identiy above (for printing/naming) 
*/
+       const char *id_str;
 };

 struct ue_context {
@@ -260,6 +294,7 @@
                bool hnbap_allow_tmsi;
                /*! print hnb-id (true) or MCC-MNC-LAC-RAC-SAC (false) in logs 
*/
                bool log_prefix_hnb_id;
+               bool accept_all_hnb;
                struct mgcp_client_conf *mgcp_client;
                struct {
                        char *local_addr;
@@ -276,6 +311,8 @@
        struct osmo_stream_srv_link *iuh;
        /* list of struct hnb_context */
        struct llist_head hnb_list;
+       /* list of struct hnb_persistent */
+       struct llist_head hnb_persistent_list;
        /* list of struct ue_context */
        struct llist_head ue_list;
        /* next availble UE Context ID */
@@ -324,6 +361,10 @@
 void hnb_context_release(struct hnb_context *ctx);
 void hnb_context_release_ue_state(struct hnb_context *ctx);

+struct hnb_persistent *hnb_persistent_alloc(const struct umts_cell_id *id);
+struct hnb_persistent *hnb_persistent_find_by_id(const struct umts_cell_id 
*id);
+void hnb_persistent_free(struct hnb_persistent *hnbp);
+
 void hnbgw_vty_init(void);
 int hnbgw_vty_go_parent(struct vty *vty);

diff --git a/include/osmocom/hnbgw/vty.h b/include/osmocom/hnbgw/vty.h
index da0c469..9134521 100644
--- a/include/osmocom/hnbgw/vty.h
+++ b/include/osmocom/hnbgw/vty.h
@@ -4,6 +4,7 @@

 enum osmo_iuh_vty_node {
        HNBGW_NODE = _LAST_OSMOVTY_NODE + 1,
+       HNB_NODE,
        IUH_NODE,
        IUCS_NODE,
        IUPS_NODE,
diff --git a/src/osmo-hnbgw/hnbgw.c b/src/osmo-hnbgw/hnbgw.c
index 366568d..3709274 100644
--- a/src/osmo-hnbgw/hnbgw.c
+++ b/src/osmo-hnbgw/hnbgw.c
@@ -1,6 +1,6 @@
 /* kitchen sink for OsmoHNBGW implementation */

-/* (C) 2015 by Harald Welte <[email protected]>
+/* (C) 2015,2024 by Harald Welte <[email protected]>
  * (C) 2016-2023 by sysmocom s.f.m.c. GmbH <[email protected]>
  * All Rights Reserved
  *
@@ -294,10 +294,49 @@
                map->hnb_ctx = NULL;
        }

+       /* remove back reference from hnb_persistent to context */
+       if (ctx->persistent)
+               ctx->persistent->ctx = NULL;
+
        talloc_free(ctx);
 }

+/***********************************************************************
+ * HNB Persistent Data
+ ***********************************************************************/

+struct hnb_persistent *hnb_persistent_alloc(const struct umts_cell_id *id)
+{
+       struct hnb_persistent *hnbp = talloc_zero(g_hnbgw, struct 
hnb_persistent);
+       if (!hnbp)
+               return NULL;
+
+       hnbp->id = *id;
+       hnbp->id_str = talloc_strdup(hnbp, umts_cell_id_name(id));
+
+       llist_add(&hnbp->list, &g_hnbgw->hnb_persistent_list);
+
+       return hnbp;
+}
+
+struct hnb_persistent *hnb_persistent_find_by_id(const struct umts_cell_id *id)
+{
+       struct hnb_persistent *hnbp;
+
+       llist_for_each_entry(hnbp, &g_hnbgw->hnb_persistent_list, list) {
+               if (umts_cell_id_equal(&hnbp->id, id))
+                       return hnbp;
+       }
+
+       return NULL;
+}
+
+void hnb_persistent_free(struct hnb_persistent *hnbp)
+{
+       /* FIXME: check if in use? */
+       llist_del(&hnbp->list);
+       talloc_free(hnbp);
+}

 /***********************************************************************
  * SCTP Socket / stream handling
@@ -610,12 +649,14 @@
        g_hnbgw->config.iuh_local_ip = talloc_strdup(g_hnbgw, 
HNBGW_LOCAL_IP_DEFAULT);
        g_hnbgw->config.iuh_local_port = IUH_DEFAULT_SCTP_PORT;
        g_hnbgw->config.log_prefix_hnb_id = true;
+       g_hnbgw->config.accept_all_hnb = true;

        /* Set zero PLMN to detect a missing PLMN when transmitting RESET */
        g_hnbgw->config.plmn = (struct osmo_plmn_id){ 0, 0, false };

        g_hnbgw->next_ue_ctx_id = 23;
        INIT_LLIST_HEAD(&g_hnbgw->hnb_list);
+       INIT_LLIST_HEAD(&g_hnbgw->hnb_persistent_list);
        INIT_LLIST_HEAD(&g_hnbgw->ue_list);
        INIT_LLIST_HEAD(&g_hnbgw->sccp.users);

diff --git a/src/osmo-hnbgw/hnbgw_hnbap.c b/src/osmo-hnbgw/hnbgw_hnbap.c
index 06d1a9d..f9ad478 100644
--- a/src/osmo-hnbgw/hnbgw_hnbap.c
+++ b/src/osmo-hnbgw/hnbgw_hnbap.c
@@ -404,21 +404,24 @@

 static int hnbgw_rx_hnb_register_req(struct hnb_context *ctx, ANY_t *in)
 {
+       struct hnb_persistent *hnbp;
        struct hnb_context *hnb, *tmp;
        HNBAP_HNBRegisterRequestIEs_t ies;
        int rc;
        struct osmo_plmn_id plmn;
        struct osmo_fd *ofd = osmo_stream_srv_get_ofd(ctx->conn);
+       char identity_str[256];
+       const char *cell_id_str;

        rc = hnbap_decode_hnbregisterrequesties(&ies, in);
        if (rc < 0) {
                LOGHNB(ctx, DHNBAP, LOGL_ERROR, "Failure to decode 
HNB-REGISTER-REQ: rc=%d\n", rc);
                return rc;
        }
+       asn1_strncpy(identity_str, &ies.hnB_Identity.hNB_Identity_Info, 
sizeof(identity_str));

        /* copy all identity parameters from the message to ctx */
-       asn1_strncpy(ctx->identity_info, &ies.hnB_Identity.hNB_Identity_Info,
-                       sizeof(ctx->identity_info));
+       OSMO_STRLCPY_ARRAY(ctx->identity_info, identity_str);
        ctx->id.lac = asn1str_to_u16(&ies.lac);
        ctx->id.sac = asn1str_to_u16(&ies.sac);
        ctx->id.rac = asn1str_to_u8(&ies.rac);
@@ -426,6 +429,19 @@
        osmo_plmn_from_bcd(ies.plmNidentity.buf, &plmn);
        ctx->id.mcc = plmn.mcc;
        ctx->id.mnc = plmn.mnc;
+       cell_id_str = umts_cell_id_name(&ctx->id);
+
+       hnbp = hnb_persistent_find_by_id(&ctx->id);
+       if (!hnbp && g_hnbgw->config.accept_all_hnb)
+               hnbp = hnb_persistent_alloc(&ctx->id);
+
+       if (!hnbp) {
+               LOGHNB(ctx, DHNBAP, LOGL_NOTICE, "Rejecting unknonwn HNB with 
identity %s\n", identity_str);
+               hnbap_free_hnbregisterrequesties(&ies);
+               return hnbgw_tx_hnb_register_rej(ctx);
+       }
+       ctx->persistent = hnbp;
+

        llist_for_each_entry_safe(hnb, tmp, &g_hnbgw->hnb_list, list) {
                if (hnb->hnb_registered && ctx != hnb && memcmp(&ctx->id, 
&hnb->id, sizeof(ctx->id)) == 0) {
@@ -456,15 +472,14 @@

                        /* If new conn registering same HNB is from anoter 
remote addr+port, let's reject it to avoid
                         * misconfigurations or someone trying to impersonate 
an already working HNB: */
-                       LOGHNB(ctx, DHNBAP, LOGL_ERROR, "rejecting 
HNB-REGISTER-REQ with duplicate cell identity %s\n",
-                              umts_cell_id_name(&ctx->id));
+                       LOGHNB(ctx, DHNBAP, LOGL_ERROR, "rejecting 
HNB-REGISTER-REQ with duplicate cell identity %s\n", cell_id_str);
                        hnbap_free_hnbregisterrequesties(&ies);
                        return hnbgw_tx_hnb_register_rej(ctx);
                }
        }

        LOGHNB(ctx, DHNBAP, LOGL_DEBUG, "HNB-REGISTER-REQ %s %s%s\n",
-              ctx->identity_info, umts_cell_id_name(&ctx->id), 
ctx->hnb_registered ? " (re-connecting)" : "");
+              ctx->identity_info, cell_id_str, ctx->hnb_registered ? " 
(re-connecting)" : "");

        /* The HNB is already registered, and we are seeing a new HNB Register 
Request. The HNB has restarted
         * without us noticing. Clearly, the HNB does not expect any UE state 
to be active here, so discard any
diff --git a/src/osmo-hnbgw/hnbgw_rua.c b/src/osmo-hnbgw/hnbgw_rua.c
index d73f22d..76e3231 100644
--- a/src/osmo-hnbgw/hnbgw_rua.c
+++ b/src/osmo-hnbgw/hnbgw_rua.c
@@ -579,6 +579,10 @@
        asn_dec_rval_t dec_ret;
        int rc;

+       /* RUA is only processed after HNB registration, and as soon as the HNB 
is registered,
+        * it should have a persistent config associated with it */
+       OSMO_ASSERT(hnb->persistent);
+
        /* decode and handle to _hnbgw_hnbap_rx() */

        memset(pdu, 0, sizeof(*pdu));
diff --git a/src/osmo-hnbgw/hnbgw_vty.c b/src/osmo-hnbgw/hnbgw_vty.c
index cb34d7f..1870f5d 100644
--- a/src/osmo-hnbgw/hnbgw_vty.c
+++ b/src/osmo-hnbgw/hnbgw_vty.c
@@ -1,6 +1,7 @@
 /* HNB-GW interface to quagga VTY */

 /* (C) 2016 by sysmocom s.f.m.c. GmbH <[email protected]>
+ * (C) 2024 by Harald Welte <[email protected]>
  * All Rights Reserved
  *
  * This program is free software; you can redistribute it and/or modify
@@ -53,6 +54,12 @@
        return CMD_SUCCESS;
 }

+static struct cmd_node hnb_node = {
+       HNB_NODE,
+       "%s(config-hnbgw-hnb)# ",
+       1,
+};
+
 static struct cmd_node iuh_node = {
        IUH_NODE,
        "%s(config-hnbgw-iuh)# ",
@@ -355,6 +362,19 @@
        return CMD_SUCCESS;
 }

+DEFUN(cfg_hnbgw_hnb_policy, cfg_hnbgw_hnb_policy_cmd,
+       "hnb-policy (accept-all|closed)",
+       "Configure the policy of which HNB connections to accept\n"
+       "Accept HNB of any identity\n"
+       "Accept only HNB whose identity is explicitly configured via VTY\n")
+{
+       if (!strcmp(argv[0], "accept-all"))
+               g_hnbgw->config.accept_all_hnb = true;
+       else
+               g_hnbgw->config.accept_all_hnb = false;
+       return CMD_SUCCESS;
+}
+
 DEFUN_DEPRECATED(cfg_hnbgw_max_sccp_cr_payload_len, 
cfg_hnbgw_max_sccp_cr_payload_len_cmd,
       "sccp cr max-payload-len <0-999999>",
       "Configure SCCP behavior\n"
@@ -799,6 +819,58 @@
        return CMD_SUCCESS;
 }

+#define HNB_STR "hNodeB specific configuration\n"
+
+DEFUN(cfg_hnbgw_hnb, cfg_hnbgw_hnb_cmd,
+      "hnb UMTS_CELL_ID",
+      HNB_STR
+      "Identity of hNodeB in xxx-yyy-Llac-Rrac-Ssac-Ccid format\n")
+{
+       struct umts_cell_id ucid;
+       struct hnb_persistent *hnbp;
+
+       if (umts_cell_id_from_str(&ucid, argv[0])) {
+               vty_out(vty, "%% Invalid UMTS_CELL_ID '%s'%s", argv[0], 
VTY_NEWLINE);
+               return CMD_WARNING;
+       }
+
+       hnbp = hnb_persistent_find_by_id(&ucid);
+       if (!hnbp)
+               hnbp = hnb_persistent_alloc(&ucid);
+       if (!hnbp) {
+               vty_out(vty, "%% Could not create HNB '%s'%s", argv[0], 
VTY_NEWLINE);
+               return CMD_WARNING;
+       }
+
+       vty->index = hnbp;
+       vty->node = HNB_NODE;
+
+       return CMD_SUCCESS;
+}
+
+DEFUN(cfg_hnbgw_no_hnb, cfg_hnbgw_no_hnb_cmd,
+       "no hnb IDENTITY_INFO",
+       NO_STR "Remove configuration for specified hNodeB\n"
+       "Identity of hNodeB\n")
+{
+       struct umts_cell_id ucid;
+       struct hnb_persistent *hnbp;
+
+       if (umts_cell_id_from_str(&ucid, argv[0])) {
+               vty_out(vty, "%% Invalid UMTS_CELL_ID '%s'%s", argv[0], 
VTY_NEWLINE);
+               return CMD_WARNING;
+       }
+
+       hnbp = hnb_persistent_find_by_id(&ucid);
+       if (!hnbp) {
+               vty_out(vty, "%% Could not find any HNB for identity '%s'%s", 
argv[0], VTY_NEWLINE);
+               return CMD_WARNING;
+       }
+
+       hnb_persistent_free(hnbp);
+       return CMD_SUCCESS;
+}
+
 #if ENABLE_PFCP

 static struct cmd_node pfcp_node = {
@@ -889,8 +961,15 @@
        cnpool_write_nri(vty, cnpool, false);
 }

+static void write_one_hnbp(struct vty *vty, const struct hnb_persistent *hnbp)
+{
+       vty_out(vty, " hnb %s%s", hnbp->id_str, VTY_NEWLINE);
+}
+
 static int config_write_hnbgw(struct vty *vty)
 {
+       const struct hnb_persistent *hnbp;
+
        vty_out(vty, "hnbgw%s", VTY_NEWLINE);

        if (g_hnbgw->config.plmn.mcc)
@@ -903,8 +982,15 @@

        vty_out(vty, " log-prefix %s%s", g_hnbgw->config.log_prefix_hnb_id ? 
"hnb-id" : "umts-cell-id",
                VTY_NEWLINE);
+
+       if (!g_hnbgw->config.accept_all_hnb)
+               vty_out(vty, " hnb-policy closed%s", VTY_NEWLINE);
+
        osmo_tdef_vty_groups_write(vty, " ");

+       llist_for_each_entry(hnbp, &g_hnbgw->hnb_persistent_list, list)
+               write_one_hnbp(vty, hnbp);
+
        _config_write_cnpool(vty, &g_hnbgw->sccp.cnpool_iucs);
        _config_write_cnpool(vty, &g_hnbgw->sccp.cnpool_iups);

@@ -1003,6 +1089,7 @@
        install_element(HNBGW_NODE, &cfg_hnbgw_rnc_id_cmd);
        install_element(HNBGW_NODE, &cfg_hnbgw_log_prefix_cmd);
        install_element(HNBGW_NODE, &cfg_hnbgw_max_sccp_cr_payload_len_cmd);
+       install_element(HNBGW_NODE, &cfg_hnbgw_hnb_policy_cmd);

        install_element(HNBGW_NODE, &cfg_hnbgw_iuh_cmd);
        install_node(&iuh_node, config_write_hnbgw_iuh);
@@ -1027,6 +1114,10 @@
        install_element(IUCS_NODE, &cfg_hnbgw_cnpool_remote_addr_cmd);
        install_element(IUPS_NODE, &cfg_hnbgw_cnpool_remote_addr_cmd);

+       install_element(HNBGW_NODE, &cfg_hnbgw_hnb_cmd);
+       install_element(HNBGW_NODE, &cfg_hnbgw_no_hnb_cmd);
+       install_node(&hnb_node, NULL);
+
        install_element_ve(&show_cnlink_cmd);
        install_element_ve(&show_hnb_cmd);
        install_element_ve(&show_one_hnb_cmd);
diff --git a/tests/osmo-hnbgw.vty b/tests/osmo-hnbgw.vty
index 41bcb73..8443f86 100644
--- a/tests/osmo-hnbgw.vty
+++ b/tests/osmo-hnbgw.vty
@@ -14,9 +14,12 @@
   plmn <1-999> <0-999>
   rnc-id <0-65535>
   log-prefix (hnb-id|umts-cell-id)
+  hnb-policy (accept-all|closed)
   iuh
   iucs
   iups
+  hnb UMTS_CELL_ID
+  no hnb IDENTITY_INFO
 ...

 OsmoHNBGW(config-hnbgw)# plmn?

--
To view, visit https://gerrit.osmocom.org/c/osmo-hnbgw/+/36081?usp=email
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings

Gerrit-Project: osmo-hnbgw
Gerrit-Branch: master
Gerrit-Change-Id: Ife89a7a206836bd89334d19d3cf8c92969dd74de
Gerrit-Change-Number: 36081
Gerrit-PatchSet: 4
Gerrit-Owner: laforge <[email protected]>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <[email protected]>
Gerrit-Reviewer: osmith <[email protected]>
Gerrit-Reviewer: pespin <[email protected]>
Gerrit-MessageType: merged

Reply via email to