Stefan Sperling has uploaded this change for review. ( 
https://gerrit.osmocom.org/12446


Change subject: add BSC/MSC neighbor VTY commands for inter-MSC HO
......................................................................

add BSC/MSC neighbor VTY commands for inter-MSC HO

Allow configuration of neighbor BSC/MSC via osmo-msc.cfg
and the VTY.

Each neighbor is mapped to the list of identifiers of cells
which are reachable via that neighbor. A new neighbor_ident
API manages the neighbor list and supports mapping neighboring
BSCs/MSCs to cells, and vice versa.

Neighbours are managed with the following new VTY commands:

 [no] neighbor lac <0-65535> bsc-pc POINT_CODE
 [no] neighbor lac <0-65535> msc-ip-name IPA_NAME
 [no] neighbor lac <0-65535> ci <0-999>bsc-pc POINT_CODE
 [no] neighbor lac <0-65535> ci <0-999> msc-ip-name IPA_NAME
 [no] neighbor cgi <0-999> <0-999> <0-65535> <0-65535> bsc-pc POINT_CODE
 [no] neighbor cgi <0-999> <0-999> <0-65535> <0-65535> msc-ipa-name IPA_NAME
 show neighbor all
 show neighbor bsc-pc POINT_CODE
 show neighbor msc-ipa-name IPA_NAME

Change-Id: Ia0dd08b087bfd4aa22e234917669d003150a4cd4
Depends: I5535f0d149c2173294538df75764dd181b023312
---
M include/osmocom/msc/Makefile.am
M include/osmocom/msc/gsm_data.h
A include/osmocom/msc/neighbor_ident.h
M src/libmsc/Makefile.am
M src/libmsc/msc_vty.c
A src/libmsc/neighbor_ident.c
A src/libmsc/neighbor_ident_vty.c
7 files changed, 700 insertions(+), 0 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/osmo-msc refs/changes/46/12446/1

diff --git a/include/osmocom/msc/Makefile.am b/include/osmocom/msc/Makefile.am
index d98bc9c..e821993 100644
--- a/include/osmocom/msc/Makefile.am
+++ b/include/osmocom/msc/Makefile.am
@@ -19,6 +19,7 @@
        msc_common.h \
        msc_ifaces.h \
        msc_mgcp.h \
+       neighbor_ident.h \
        a_reset.h \
        ran_conn.h \
        rrlp.h \
diff --git a/include/osmocom/msc/gsm_data.h b/include/osmocom/msc/gsm_data.h
index d2511cb..8930380 100644
--- a/include/osmocom/msc/gsm_data.h
+++ b/include/osmocom/msc/gsm_data.h
@@ -16,6 +16,7 @@
 #include <osmocom/mgcp_client/mgcp_client.h>

 #include <osmocom/msc/msc_common.h>
+#include <osmocom/msc/neighbor_ident.h>

 #include "gsm_data_shared.h"

@@ -208,6 +209,10 @@
                struct osmo_sccp_instance *sccp;
        } a;

+       /* A list of neighbor BSCs. This list is defined statically via VTY and 
does not
+       * necessarily correspond to BSCs attached to the A interface at a given 
moment. */
+       struct neighbor_ident_list *neighbor_list;
+
        struct {
                /* MSISDN to which to route MO emergency calls */
                char *route_to_msisdn;
diff --git a/include/osmocom/msc/neighbor_ident.h 
b/include/osmocom/msc/neighbor_ident.h
new file mode 100644
index 0000000..d79d262
--- /dev/null
+++ b/include/osmocom/msc/neighbor_ident.h
@@ -0,0 +1,71 @@
+/* Manage identity of neighboring BSS cells for inter-BSC handover */
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/gsm/gsm0808.h>
+
+struct vty;
+struct gsm_network;
+
+enum msc_neighbor_type {
+       /* Neighboring BSC reachable via SCCP. */
+       MSC_NEIGHBOR_TYPE_BSC,
+
+       /* Neighboring MSC reachable via GSUP. */
+       MSC_NEIGHBOR_TYPE_MSC
+};
+
+struct neighbor_ident_addr {
+       enum msc_neighbor_type type;
+       union {
+               int point_code; /* BSC */
+               const char *ipa_name; /* MSC */
+       } a;
+};
+
+struct neighbor_ident_list {
+       struct llist_head list;
+};
+
+struct neighbor_ident {
+       struct llist_head entry;
+
+       /* Address of a neighboring BSC or MSC. */
+       struct neighbor_ident_addr addr;
+
+       /* IDs of cells in this neighbor's domain. */
+       struct gsm0808_cell_id_list2 cell_ids;
+};
+
+struct gsm0808_cell_id;
+struct gsm0808_cell_id_list2;
+
+const char *neighbor_ident_addr_name(struct gsm_network *net, const struct 
neighbor_ident_addr *ni_addr);
+
+struct neighbor_ident_list *neighbor_ident_init(void *talloc_ctx);
+void neighbor_ident_free(struct neighbor_ident_list *nil);
+
+bool neighbor_ident_addr_match(const struct neighbor_ident_addr *entry,
+                              const struct neighbor_ident_addr *search_for,
+                              bool exact_match);
+
+int neighbor_ident_add(struct neighbor_ident_list *nil, const struct 
neighbor_ident_addr *addr,
+                      const struct gsm0808_cell_id_list2 *cell_ids);
+const struct gsm0808_cell_id_list2 *neighbor_ident_get(const struct 
neighbor_ident_list *nil,
+                                                      const struct 
neighbor_ident_addr *addr);
+const struct neighbor_ident_addr *neighbor_ident_lookup_cell(const struct 
neighbor_ident_list *nil,
+                                                            struct 
gsm0808_cell_id *cell_id);
+bool neighbor_ident_del(struct neighbor_ident_list *nil, const struct 
neighbor_ident_addr *addr);
+void neighbor_ident_clear(struct neighbor_ident_list *nil);
+
+void neighbor_ident_iter(const struct neighbor_ident_list *nil,
+                        bool (* iter_cb )(const struct neighbor_ident_addr 
*addr,
+                                          const struct gsm0808_cell_id_list2 
*cell_ids,
+                                          void *cb_data),
+                        void *cb_data);
+
+void neighbor_ident_vty_init(struct gsm_network *net);
+void neighbor_ident_vty_write(struct vty *vty);
diff --git a/src/libmsc/Makefile.am b/src/libmsc/Makefile.am
index 9183ff9..f498001 100644
--- a/src/libmsc/Makefile.am
+++ b/src/libmsc/Makefile.am
@@ -44,6 +44,8 @@
        mncc_sock.c \
        msc_ifaces.c \
        msc_mgcp.c \
+       neighbor_ident.c \
+       neighbor_ident_vty.c \
        ran_conn.c \
        rrlp.c \
        silent_call.c \
diff --git a/src/libmsc/msc_vty.c b/src/libmsc/msc_vty.c
index 7745e5d..1af42e4 100644
--- a/src/libmsc/msc_vty.c
+++ b/src/libmsc/msc_vty.c
@@ -1538,6 +1538,8 @@
 #ifdef BUILD_IU
        ranap_iu_vty_init(MSC_NODE, &msc_network->iu.rab_assign_addr_enc);
 #endif
+       neighbor_ident_vty_init(msc_network);
+
        osmo_fsm_vty_add_cmds();

        osmo_signal_register_handler(SS_SCALL, scall_cbfn, NULL);
diff --git a/src/libmsc/neighbor_ident.c b/src/libmsc/neighbor_ident.c
new file mode 100644
index 0000000..f7187a9
--- /dev/null
+++ b/src/libmsc/neighbor_ident.c
@@ -0,0 +1,206 @@
+/* Manage identity of neighboring BSS cells for inter-MSC handover. */
+/* (C) 2018 by sysmocom - s.f.m.c. GmbH <i...@sysmocom.de>
+ *
+ * All Rights Reserved
+ *
+ * Author: Neels Hofmeyr <nhofm...@sysmocom.de>
+ * Author: Stefan Sperling <ssperl...@sysmocom.de>
+ *
+ * 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 <errno.h>
+
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/gsm/gsm0808.h>
+#include <osmocom/sigtran/osmo_ss7.h>
+
+#include <osmocom/msc/neighbor_ident.h>
+#include <osmocom/msc/gsm_data.h>
+
+/* XXX greater than or equal to IPA_STIRNG_MAX (libosmocore) and 
MAX_PC_STR_LEN (libosmo-sccp). */
+#define NEIGHBOR_IDENT_ADDR_STRING_MAX 64
+
+const char *neighbor_ident_addr_name(struct gsm_network *net, const struct 
neighbor_ident_addr *na)
+{
+       static char buf[NEIGHBOR_IDENT_ADDR_STRING_MAX + 4];
+       struct osmo_ss7_instance *ss7;
+
+       switch (na->type) {
+       case MSC_NEIGHBOR_TYPE_BSC:
+               ss7 = osmo_ss7_instance_find(net->a.cs7_instance);
+               OSMO_ASSERT(ss7);
+               snprintf(buf, sizeof(buf), "BSC %s", 
osmo_ss7_pointcode_print(ss7, na->a.point_code));
+               break;
+       case MSC_NEIGHBOR_TYPE_MSC:
+               snprintf(buf, sizeof(buf), "MSC %s", na->a.ipa_name);
+               break;
+       default:
+               return NULL;
+       }
+
+       return buf;
+}
+
+struct neighbor_ident_list *neighbor_ident_init(void *talloc_ctx)
+{
+       struct neighbor_ident_list *nil = talloc_zero(talloc_ctx, struct 
neighbor_ident_list);
+       OSMO_ASSERT(nil);
+       INIT_LLIST_HEAD(&nil->list);
+       return nil;
+}
+
+void neighbor_ident_free(struct neighbor_ident_list *nil)
+{
+       if (!nil)
+               return;
+       talloc_free(nil);
+}
+
+static struct neighbor_ident *_neighbor_ident_get(const struct 
neighbor_ident_list *nil,
+                                                 const struct 
neighbor_ident_addr *na)
+{
+       struct neighbor_ident *ni;
+
+       llist_for_each_entry(ni, &nil->list, entry) {
+               if (na->type != ni->addr.type)
+                       continue;
+
+               switch (na->type) {
+               case MSC_NEIGHBOR_TYPE_BSC:
+                       if (ni->addr.a.point_code == na->a.point_code)
+                               return ni;
+                       break;
+               case MSC_NEIGHBOR_TYPE_MSC:
+                       if (strcmp(ni->addr.a.ipa_name, na->a.ipa_name) == 0)
+                               return ni;
+                       break;
+               }
+       }
+
+       return NULL;
+}
+
+static void _neighbor_ident_free(struct neighbor_ident *ni)
+{
+       llist_del(&ni->entry);
+       talloc_free(ni);
+}
+
+/*! Add Cell Identifiers to a neighbor BSC/MSC entry.
+ * Exactly one kind of identifier is allowed per entry, and any number of 
entries of that kind
+ * may be added up to the capacity of gsm0808_cell_id_list2, by one or more 
calls to this function. To
+ * replace an existing entry, first call neighbor_ident_del(nil, cell_id).
+ * \returns number of entries in the resulting identifier list, or negative on 
error:
+ *   see gsm0808_cell_id_list_add() for the meaning of returned error codes;
+ *   return -ENOMEM when the list is not initialized, -ERANGE when the BSIC 
value is too large. */
+int neighbor_ident_add(struct neighbor_ident_list *nil, const struct 
neighbor_ident_addr *addr,
+                      const struct gsm0808_cell_id_list2 *cell_id)
+{
+       struct neighbor_ident *ni;
+       int rc;
+
+       if (!nil)
+               return -ENOMEM;
+
+       ni = _neighbor_ident_get(nil, addr);
+       if (!ni) {
+               ni = talloc_zero(nil, struct neighbor_ident);
+               OSMO_ASSERT(ni);
+               ni->addr.type = addr->type;
+               switch (ni->addr.type) {
+               case MSC_NEIGHBOR_TYPE_MSC:
+                       ni->addr.a.ipa_name = talloc_strdup(ni, 
addr->a.ipa_name);
+                       break;
+               case MSC_NEIGHBOR_TYPE_BSC:
+                       ni->addr.a.point_code = addr->a.point_code;
+                       break;
+               }
+               llist_add_tail(&ni->entry, &nil->list);
+       }
+
+       rc = gsm0808_cell_id_list_add(&ni->cell_ids, cell_id);
+       if (rc < 0)
+               return rc;
+
+       return ni->cell_ids.id_list_len;
+}
+
+/*! Find cell identity for given BSC or MSC, as previously added by 
neighbor_ident_add().
+ */
+const struct gsm0808_cell_id_list2 *neighbor_ident_get(const struct 
neighbor_ident_list *nil,
+                                                      const struct 
neighbor_ident_addr *addr)
+{
+       struct neighbor_ident *ni;
+       if (!nil)
+               return NULL;
+       ni = _neighbor_ident_get(nil, addr);
+       if (!ni)
+               return NULL;
+       return &ni->cell_ids;
+}
+
+/*! Find a BSC or MSC, as previously added by neighbor_ident_add(), for a 
given cell identity.
+ */
+const struct neighbor_ident_addr *neighbor_ident_lookup_cell(const struct 
neighbor_ident_list *nil,
+                                                            struct 
gsm0808_cell_id *cell_id)
+{
+       struct neighbor_ident *ni;
+       if (!nil)
+               return NULL;
+       llist_for_each_entry(ni, &nil->list, entry) {
+               if (gsm0808_cell_id_matches_list(cell_id, &ni->cell_ids, 0))
+                       return &ni->addr;
+       }
+
+       return NULL;
+}
+
+bool neighbor_ident_del(struct neighbor_ident_list *nil, const struct 
neighbor_ident_addr *addr)
+{
+       struct neighbor_ident *ni;
+       if (!nil)
+               return false;
+       ni = _neighbor_ident_get(nil, addr);
+       if (!ni)
+               return false;
+       _neighbor_ident_free(ni);
+       return true;
+}
+
+void neighbor_ident_clear(struct neighbor_ident_list *nil)
+{
+       struct neighbor_ident *ni;
+       while ((ni = llist_first_entry_or_null(&nil->list, struct 
neighbor_ident, entry)))
+               _neighbor_ident_free(ni);
+}
+
+/*! Iterate all neighbor_ident_list entries and call iter_cb for each.
+ * If iter_cb returns false, the iteration is stopped. */
+void neighbor_ident_iter(const struct neighbor_ident_list *nil,
+                        bool (* iter_cb )(const struct neighbor_ident_addr 
*addr,
+                                          const struct gsm0808_cell_id_list2 
*cell_ids,
+                                          void *cb_data),
+                        void *cb_data)
+{
+       struct neighbor_ident *ni, *ni_next;
+       if (!nil)
+               return;
+       llist_for_each_entry_safe(ni, ni_next, &nil->list, entry) {
+               if (!iter_cb(&ni->addr, &ni->cell_ids, cb_data))
+                       return;
+       }
+}
diff --git a/src/libmsc/neighbor_ident_vty.c b/src/libmsc/neighbor_ident_vty.c
new file mode 100644
index 0000000..a44a284
--- /dev/null
+++ b/src/libmsc/neighbor_ident_vty.c
@@ -0,0 +1,413 @@
+/* Quagga VTY implementation to manage identity of neighboring BSS cells for 
inter-BSC handover. */
+/* (C) 2018 by sysmocom - s.f.m.c. GmbH <i...@sysmocom.de>
+ *
+ * All Rights Reserved
+ *
+ * Author: Neels Hofmeyr <nhofm...@sysmocom.de>
+ * Author: Stefan Sperling <ssperl...@sysmocom.de>
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <osmocom/vty/command.h>
+#include <osmocom/gsm/gsm0808.h>
+#include <osmocom/sigtran/osmo_ss7.h>
+
+#include <osmocom/msc/vty.h>
+#include <osmocom/msc/neighbor_ident.h>
+#include <osmocom/msc/gsm_data.h>
+
+#define NEIGHBOR_ADD_CMD "neighbor "
+#define NEIGHBOR_DEL_CMD "no neighbor "
+#define NEIGHBOR_SHOW_CMD "show neighbor "
+#define NEIGHBOR_DOC "Manage neighbor BSS cells\n"
+#define NEIGHBOR_ADD_DOC NEIGHBOR_DOC "Add "
+#define NEIGHBOR_DEL_DOC NO_STR "Remove neighbor BSS cell\n"
+
+#define LAC_PARAMS "lac <0-65535>"
+#define LAC_DOC "Neighbor cell by LAC\n" "LAC\n"
+
+#define LAC_CI_PARAMS "lac-ci <0-65535> <0-65535>"
+#define LAC_CI_DOC "Neighbor cell by LAC and CI\n" "LAC\n" "CI\n"
+
+#define CGI_PARAMS "cgi <0-999> <0-999> <0-65535> <0-65535>"
+#define CGI_DOC "Neighbor cell by cgi\n" "MCC\n" "MNC\n" "LAC\n" "CI\n"
+
+#define NEIGHBOR_IDENT_VTY_BSC_ADDR_PARAMS "bsc-pc POINT_CODE"
+#define NEIGHBOR_IDENT_VTY_BSC_ADDR_DOC "Point code of neighbor BSC\n" "Point 
code value\n"
+#define NEIGHBOR_IDENT_VTY_MSC_ADDR_PARAMS "msc-ipa-name IPA_NAME"
+#define NEIGHBOR_IDENT_VTY_MSC_ADDR_DOC "IPA name of neighbor MSC\n" "IPA name 
value\n"
+
+static struct gsm_network *g_net = NULL;
+
+static struct gsm0808_cell_id *neighbor_ident_vty_parse_lac(struct vty *vty, 
const char **argv)
+{
+       static struct gsm0808_cell_id cell_id;
+       cell_id = (struct gsm0808_cell_id){
+               .id_discr = CELL_IDENT_LAC,
+               .id.lac = atoi(argv[0]),
+       };
+       return &cell_id;
+}
+
+static struct gsm0808_cell_id *neighbor_ident_vty_parse_lac_ci(struct vty 
*vty, const char **argv)
+{
+       static struct gsm0808_cell_id cell_id;
+       cell_id = (struct gsm0808_cell_id){
+               .id_discr = CELL_IDENT_LAC_AND_CI,
+               .id.lac_and_ci = {
+                       .lac = atoi(argv[0]),
+                       .ci = atoi(argv[1]),
+               },
+       };
+       return &cell_id;
+}
+
+static struct gsm0808_cell_id *neighbor_ident_vty_parse_cgi(struct vty *vty, 
const char **argv)
+{
+       static struct gsm0808_cell_id cell_id;
+       cell_id = (struct gsm0808_cell_id){
+               .id_discr = CELL_IDENT_WHOLE_GLOBAL,
+       };
+       struct osmo_cell_global_id *cgi = &cell_id.id.global;
+       const char *mcc = argv[0];
+       const char *mnc = argv[1];
+       const char *lac = argv[2];
+       const char *ci = argv[3];
+
+       if (osmo_mcc_from_str(mcc, &cgi->lai.plmn.mcc)) {
+               vty_out(vty, "%% Error decoding MCC: %s%s", mcc, VTY_NEWLINE);
+               return NULL;
+       }
+
+       if (osmo_mnc_from_str(mnc, &cgi->lai.plmn.mnc, 
&cgi->lai.plmn.mnc_3_digits)) {
+               vty_out(vty, "%% Error decoding MNC: %s%s", mnc, VTY_NEWLINE);
+               return NULL;
+       }
+
+       cgi->lai.lac = atoi(lac);
+       cgi->cell_identity = atoi(ci);
+       return &cell_id;
+}
+
+static int add_neighbor(struct vty *vty, struct neighbor_ident_addr *addr, 
const struct gsm0808_cell_id *cell_id)
+{
+       struct gsm0808_cell_id_list2 cell_ids;
+       int rc;
+
+       gsm0808_cell_id_to_list(&cell_ids, cell_id);
+       rc = neighbor_ident_add(g_net->neighbor_list, addr, &cell_ids);
+       if (rc < 0) {
+               vty_out(vty, "%% Error: cannot add cell %s to neighbor %s: 
%s%s",
+                       gsm0808_cell_id_name(cell_id), 
neighbor_ident_addr_name(g_net, addr),
+                       strerror(-rc), VTY_NEWLINE);
+               return CMD_WARNING;
+       }
+       return CMD_SUCCESS;
+}
+
+static int parse_point_code(const char *point_code_str)
+{
+       struct osmo_ss7_instance *ss7 = 
osmo_ss7_instance_find(g_net->a.cs7_instance);
+       OSMO_ASSERT(ss7);
+       return osmo_ss7_pointcode_parse(ss7, point_code_str);
+}
+
+DEFUN(cfg_neighbor_add_lac_bsc, cfg_neighbor_add_lac_bsc_cmd,
+       NEIGHBOR_ADD_CMD LAC_PARAMS " " NEIGHBOR_IDENT_VTY_BSC_ADDR_PARAMS,
+       NEIGHBOR_ADD_DOC LAC_DOC " " NEIGHBOR_IDENT_VTY_BSC_ADDR_DOC)
+{
+       struct neighbor_ident_addr addr;
+       int point_code = parse_point_code(argv[1]);
+
+       if (point_code < 0) {
+               vty_out(vty, "Could not parse point code '%s'%s", argv[0], 
VTY_NEWLINE);
+               return CMD_WARNING;
+       }
+
+       addr.type = MSC_NEIGHBOR_TYPE_BSC;
+       addr.a.point_code = point_code;
+       return add_neighbor(vty, &addr, neighbor_ident_vty_parse_lac(vty, argv 
+ 1));
+}
+
+DEFUN(cfg_neighbor_add_lac_msc, cfg_neighbor_add_lac_msc_cmd,
+       NEIGHBOR_ADD_CMD LAC_PARAMS " " NEIGHBOR_IDENT_VTY_MSC_ADDR_PARAMS,
+       NEIGHBOR_ADD_DOC LAC_DOC " " NEIGHBOR_IDENT_VTY_MSC_ADDR_DOC)
+{
+       struct neighbor_ident_addr addr;
+
+       addr.type = MSC_NEIGHBOR_TYPE_MSC;
+       addr.a.ipa_name = argv[1];
+       return add_neighbor(vty, &addr, neighbor_ident_vty_parse_lac(vty, argv 
+ 1));
+}
+
+DEFUN(cfg_neighbor_add_lac_ci_bsc, cfg_neighbor_add_lac_ci_bsc_cmd,
+       NEIGHBOR_ADD_CMD LAC_CI_PARAMS " " NEIGHBOR_IDENT_VTY_BSC_ADDR_PARAMS,
+       NEIGHBOR_ADD_DOC LAC_CI_DOC " " NEIGHBOR_IDENT_VTY_BSC_ADDR_DOC)
+{
+       struct neighbor_ident_addr addr;
+       int point_code = parse_point_code(argv[2]);
+
+       if (point_code < 0) {
+               vty_out(vty, "Could not parse point code '%s'%s", argv[0], 
VTY_NEWLINE);
+               return CMD_WARNING;
+       }
+
+       addr.type = MSC_NEIGHBOR_TYPE_BSC;
+       addr.a.point_code = point_code;
+       return add_neighbor(vty, &addr, neighbor_ident_vty_parse_lac_ci(vty, 
argv + 1));
+}
+
+DEFUN(cfg_neighbor_add_lac_ci_msc, cfg_neighbor_add_lac_ci_msc_cmd,
+       NEIGHBOR_ADD_CMD LAC_CI_PARAMS " " NEIGHBOR_IDENT_VTY_MSC_ADDR_PARAMS,
+       NEIGHBOR_ADD_DOC LAC_CI_DOC " " NEIGHBOR_IDENT_VTY_MSC_ADDR_DOC)
+{
+       struct neighbor_ident_addr addr;
+
+       addr.type = MSC_NEIGHBOR_TYPE_MSC;
+       addr.a.ipa_name = argv[2];
+       return add_neighbor(vty, &addr, neighbor_ident_vty_parse_lac_ci(vty, 
argv + 1));
+}
+
+DEFUN(cfg_neighbor_add_cgi_bsc, cfg_neighbor_add_cgi_bsc_cmd,
+       NEIGHBOR_ADD_CMD CGI_PARAMS " " NEIGHBOR_IDENT_VTY_BSC_ADDR_PARAMS,
+       NEIGHBOR_ADD_DOC CGI_DOC " " NEIGHBOR_IDENT_VTY_BSC_ADDR_DOC)
+{
+       struct neighbor_ident_addr addr;
+       int point_code = parse_point_code(argv[4]);
+
+       if (point_code < 0) {
+               vty_out(vty, "Could not parse point code '%s'%s", argv[0], 
VTY_NEWLINE);
+               return CMD_WARNING;
+       }
+
+       addr.type = MSC_NEIGHBOR_TYPE_BSC;
+       addr.a.point_code = point_code;
+       return add_neighbor(vty, &addr, neighbor_ident_vty_parse_cgi(vty, argv 
+ 1));
+}
+
+DEFUN(cfg_neighbor_add_cgi_msc, cfg_neighbor_add_cgi_msc_cmd,
+       NEIGHBOR_ADD_CMD CGI_PARAMS " " NEIGHBOR_IDENT_VTY_MSC_ADDR_PARAMS,
+       NEIGHBOR_ADD_DOC CGI_DOC " " NEIGHBOR_IDENT_VTY_MSC_ADDR_DOC)
+{
+       struct neighbor_ident_addr addr;
+
+       addr.type = MSC_NEIGHBOR_TYPE_MSC;
+       addr.a.ipa_name = argv[4];
+       return add_neighbor(vty, &addr, neighbor_ident_vty_parse_cgi(vty, argv 
+ 1));
+}
+
+static int del_by_addr(struct vty *vty, const struct neighbor_ident_addr *addr)
+{
+       int removed = 0;
+
+       if (vty->node != MSC_NODE) {
+               vty_out(vty, "%% Error: cannot remove neighbor, not on MSC 
node%s", VTY_NEWLINE);
+               return CMD_WARNING;
+       }
+
+       if (neighbor_ident_del(g_net->neighbor_list, addr)) {
+               vty_out(vty, "%% Removed neighbor %s%s",
+                       neighbor_ident_addr_name(g_net, addr), VTY_NEWLINE);
+               removed = 1;
+       }
+
+       if (!removed) {
+               vty_out(vty, "%% Cannot remove, no such neighbor: %s%s",
+                       neighbor_ident_addr_name(g_net, addr), VTY_NEWLINE);
+               return CMD_WARNING;
+       }
+
+       return CMD_SUCCESS;
+}
+
+DEFUN(cfg_del_neighbor_bsc, cfg_del_neighbor_bsc_cmd,
+      NEIGHBOR_DEL_CMD NEIGHBOR_IDENT_VTY_BSC_ADDR_PARAMS,
+      SHOW_STR "Delete a neighbor BSC\n" "BSC point code\n"
+      "Delete a specified neighbor BSC\n"
+      NEIGHBOR_IDENT_VTY_BSC_ADDR_DOC)
+{
+       struct neighbor_ident_addr addr;
+       int point_code = parse_point_code(argv[0]);
+
+       if (point_code < 0) {
+               vty_out(vty, "Could not parse point code '%s'%s", argv[0], 
VTY_NEWLINE);
+               return CMD_WARNING;
+       }
+
+       addr.type = MSC_NEIGHBOR_TYPE_BSC;
+       addr.a.point_code = point_code;
+       return del_by_addr(vty, &addr);
+}
+
+DEFUN(cfg_del_neighbor_msc, cfg_del_neighbor_msc_cmd,
+      NEIGHBOR_DEL_CMD NEIGHBOR_IDENT_VTY_MSC_ADDR_PARAMS,
+      SHOW_STR "Delete a neighbor MSC\n" "MSC ipa-nam\n"
+      "Delete a specified neighbor MSC\n"
+      NEIGHBOR_IDENT_VTY_MSC_ADDR_DOC)
+{
+       struct neighbor_ident_addr addr;
+
+       addr.type = MSC_NEIGHBOR_TYPE_MSC;
+       addr.a.ipa_name = argv[0];
+       return del_by_addr(vty, &addr);
+}
+
+static void write_neighbor_ident(struct vty *vty, const struct neighbor_ident 
*ni)
+{
+       const struct neighbor_ident_addr *addr = &ni->addr;
+       const struct gsm0808_cell_id_list2 *cell_ids = &ni->cell_ids;
+       struct osmo_ss7_instance *ss7;
+       int i;
+
+       switch (cell_ids->id_discr) {
+       case CELL_IDENT_LAC:
+               for (i = 0; i < cell_ids->id_list_len; i++) {
+                       vty_out(vty, " neighbor lac %u", 
cell_ids->id_list[i].lac);
+               }
+               break;
+       case CELL_IDENT_LAC_AND_CI:
+               for (i = 0; i < cell_ids->id_list_len; i++) {
+                       vty_out(vty, " neighbor lac-ci %u %u", 
cell_ids->id_list[i].lac_and_ci.lac,
+                               cell_ids->id_list[i].lac_and_ci.ci);
+               }
+               break;
+       case CELL_IDENT_WHOLE_GLOBAL:
+               for (i = 0; i < cell_ids->id_list_len; i++) {
+                       const struct osmo_cell_global_id *cgi = 
&cell_ids->id_list[i].global;
+                       vty_out(vty, " neighbor cgi %s %s %u %u", 
osmo_mcc_name(cgi->lai.plmn.mcc),
+                               osmo_mnc_name(cgi->lai.plmn.mnc, 
cgi->lai.plmn.mnc_3_digits),
+                               cgi->lai.lac, cgi->cell_identity);
+               }
+               break;
+       default:
+               vty_out(vty, "%% Unsupported Cell Identity%s", VTY_NEWLINE);
+               return;
+       }
+
+       switch (ni->addr.type) {
+       case MSC_NEIGHBOR_TYPE_BSC:
+               ss7 = osmo_ss7_instance_find(g_net->a.cs7_instance);
+               OSMO_ASSERT(ss7);
+               vty_out(vty, "bsc-pc %s%s", osmo_ss7_pointcode_print(ss7, 
addr->a.point_code), VTY_NEWLINE);
+               break;
+       case MSC_NEIGHBOR_TYPE_MSC:
+               vty_out(vty, "msc-ipa-name %s%s", addr->a.ipa_name, 
VTY_NEWLINE);
+               break;
+       }
+}
+
+void neighbor_ident_vty_write(struct vty *vty)
+{
+       const struct neighbor_ident *ni;
+
+       llist_for_each_entry(ni, &g_net->neighbor_list->list, entry)
+               write_neighbor_ident(vty, ni);
+}
+
+DEFUN(show_neighbor_all, show_neighbor_all_cmd,
+      NEIGHBOR_SHOW_CMD "all",
+      SHOW_STR "Display information about neighbor BSCs and MSCs\n"
+      "Show which cells are reachable via the neighbor BSCs and MSCs\n")
+{
+       struct neighbor_ident *ni;
+
+       llist_for_each_entry(ni, &g_net->neighbor_list->list, entry) {
+               vty_out(vty, "%s: %s%s", neighbor_ident_addr_name(g_net, 
&ni->addr),
+               gsm0808_cell_id_list_name(&ni->cell_ids), VTY_NEWLINE);
+       }
+
+       return CMD_SUCCESS;
+}
+
+DEFUN(show_neighbor_bsc, show_neighbor_bsc_cmd,
+      NEIGHBOR_SHOW_CMD NEIGHBOR_IDENT_VTY_BSC_ADDR_PARAMS,
+      SHOW_STR "Display information about a neighbor BSC\n" "BSC point code\n"
+      "Show which cells are reachable via the specified neighbor BSC\n"
+      NEIGHBOR_IDENT_VTY_BSC_ADDR_DOC)
+{
+       int point_code;
+       struct neighbor_ident *ni;
+       int found = 0;
+
+       point_code = parse_point_code(argv[0]);
+       if (point_code < 0) {
+               vty_out(vty, "Could not parse point code '%s'%s", argv[0], 
VTY_NEWLINE);
+               return CMD_WARNING;
+       }
+
+       llist_for_each_entry(ni, &g_net->neighbor_list->list, entry) {
+               if (ni->addr.type != MSC_NEIGHBOR_TYPE_BSC)
+                       continue;
+               if (ni->addr.a.point_code == point_code) {
+                       vty_out(vty, "%s%s", 
gsm0808_cell_id_list_name(&ni->cell_ids), VTY_NEWLINE);
+                       found = 1;
+                       break;
+               }
+       }
+
+       if (!found)
+               vty_out(vty, "%% No entry for %s%s", argv[0], VTY_NEWLINE);
+
+       return CMD_SUCCESS;
+}
+
+DEFUN(show_neighbor_msc, show_neighbor_msc_cmd,
+      NEIGHBOR_SHOW_CMD NEIGHBOR_IDENT_VTY_MSC_ADDR_PARAMS,
+      SHOW_STR "Display information about a neighbor MSC\n" "MSC ipa-name\n"
+      "Show which cells are reachable via the specified neighbor MSC\n"
+      NEIGHBOR_IDENT_VTY_MSC_ADDR_DOC)
+{
+       const char *ipa_name = argv[0];
+       struct neighbor_ident *ni;
+       int found = 0;
+
+       llist_for_each_entry(ni, &g_net->neighbor_list->list, entry) {
+               if (ni->addr.type != MSC_NEIGHBOR_TYPE_MSC)
+                       continue;
+               if (strcmp(ni->addr.a.ipa_name, ipa_name) == 0) {
+                       vty_out(vty, "%s%s", 
gsm0808_cell_id_list_name(&ni->cell_ids), VTY_NEWLINE);
+                       found = 1;
+                       break;
+               }
+       }
+
+       if (!found)
+               vty_out(vty, "%% No entry for %s%s", ipa_name, VTY_NEWLINE);
+
+       return CMD_SUCCESS;
+}
+
+void neighbor_ident_vty_init(struct gsm_network *net)
+{
+       g_net = net;
+       g_net->neighbor_list = neighbor_ident_init(net);
+
+       install_element(MSC_NODE, &cfg_neighbor_add_lac_bsc_cmd);
+       install_element(MSC_NODE, &cfg_neighbor_add_lac_msc_cmd);
+       install_element(MSC_NODE, &cfg_neighbor_add_lac_ci_bsc_cmd);
+       install_element(MSC_NODE, &cfg_neighbor_add_lac_ci_msc_cmd);
+       install_element(MSC_NODE, &cfg_neighbor_add_cgi_bsc_cmd);
+       install_element(MSC_NODE, &cfg_neighbor_add_cgi_msc_cmd);
+       install_element(MSC_NODE, &cfg_del_neighbor_bsc_cmd);
+       install_element(MSC_NODE, &cfg_del_neighbor_msc_cmd);
+       install_element_ve(&show_neighbor_all_cmd);
+       install_element_ve(&show_neighbor_bsc_cmd);
+       install_element_ve(&show_neighbor_msc_cmd);
+}

--
To view, visit https://gerrit.osmocom.org/12446
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings

Gerrit-Project: osmo-msc
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ia0dd08b087bfd4aa22e234917669d003150a4cd4
Gerrit-Change-Number: 12446
Gerrit-PatchSet: 1
Gerrit-Owner: Stefan Sperling <s...@stsp.name>

Reply via email to