<p>Stefan Sperling has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/12446">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">add BSC/MSC neighbor VTY commands for inter-MSC HO<br><br>Allow configuration of neighbor BSC/MSC via osmo-msc.cfg<br>and the VTY.<br><br>Each neighbor is mapped to the list of identifiers of cells<br>which are reachable via that neighbor. A new neighbor_ident<br>API manages the neighbor list and supports mapping neighboring<br>BSCs/MSCs to cells, and vice versa.<br><br>Neighbours are managed with the following new VTY commands:<br><br> [no] neighbor lac <0-65535> bsc-pc POINT_CODE<br> [no] neighbor lac <0-65535> msc-ip-name IPA_NAME<br> [no] neighbor lac <0-65535> ci <0-999>bsc-pc POINT_CODE<br> [no] neighbor lac <0-65535> ci <0-999> msc-ip-name IPA_NAME<br> [no] neighbor cgi <0-999> <0-999> <0-65535> <0-65535> bsc-pc POINT_CODE<br> [no] neighbor cgi <0-999> <0-999> <0-65535> <0-65535> msc-ipa-name IPA_NAME<br> show neighbor all<br> show neighbor bsc-pc POINT_CODE<br> show neighbor msc-ipa-name IPA_NAME<br><br>Change-Id: Ia0dd08b087bfd4aa22e234917669d003150a4cd4<br>Depends: I5535f0d149c2173294538df75764dd181b023312<br>---<br>M include/osmocom/msc/Makefile.am<br>M include/osmocom/msc/gsm_data.h<br>A include/osmocom/msc/neighbor_ident.h<br>M src/libmsc/Makefile.am<br>M src/libmsc/msc_vty.c<br>A src/libmsc/neighbor_ident.c<br>A src/libmsc/neighbor_ident_vty.c<br>7 files changed, 700 insertions(+), 0 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/osmo-msc refs/changes/46/12446/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/osmocom/msc/Makefile.am b/include/osmocom/msc/Makefile.am</span><br><span>index d98bc9c..e821993 100644</span><br><span>--- a/include/osmocom/msc/Makefile.am</span><br><span>+++ b/include/osmocom/msc/Makefile.am</span><br><span>@@ -19,6 +19,7 @@</span><br><span>   msc_common.h \</span><br><span>       msc_ifaces.h \</span><br><span>       msc_mgcp.h \</span><br><span style="color: hsl(120, 100%, 40%);">+  neighbor_ident.h \</span><br><span>   a_reset.h \</span><br><span>  ran_conn.h \</span><br><span>         rrlp.h \</span><br><span>diff --git a/include/osmocom/msc/gsm_data.h b/include/osmocom/msc/gsm_data.h</span><br><span>index d2511cb..8930380 100644</span><br><span>--- a/include/osmocom/msc/gsm_data.h</span><br><span>+++ b/include/osmocom/msc/gsm_data.h</span><br><span>@@ -16,6 +16,7 @@</span><br><span> #include <osmocom/mgcp_client/mgcp_client.h></span><br><span> </span><br><span> #include <osmocom/msc/msc_common.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/msc/neighbor_ident.h></span><br><span> </span><br><span> #include "gsm_data_shared.h"</span><br><span> </span><br><span>@@ -208,6 +209,10 @@</span><br><span>             struct osmo_sccp_instance *sccp;</span><br><span>     } a;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+      /* A list of neighbor BSCs. This list is defined statically via VTY and does not</span><br><span style="color: hsl(120, 100%, 40%);">+      * necessarily correspond to BSCs attached to the A interface at a given moment. */</span><br><span style="color: hsl(120, 100%, 40%);">+    struct neighbor_ident_list *neighbor_list;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         struct {</span><br><span>             /* MSISDN to which to route MO emergency calls */</span><br><span>            char *route_to_msisdn;</span><br><span>diff --git a/include/osmocom/msc/neighbor_ident.h b/include/osmocom/msc/neighbor_ident.h</span><br><span>new file mode 100644</span><br><span>index 0000000..d79d262</span><br><span>--- /dev/null</span><br><span>+++ b/include/osmocom/msc/neighbor_ident.h</span><br><span>@@ -0,0 +1,71 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* Manage identity of neighboring BSS cells for inter-BSC handover */</span><br><span style="color: hsl(120, 100%, 40%);">+#pragma once</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdint.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdbool.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/linuxlist.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/gsm0808.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct vty;</span><br><span style="color: hsl(120, 100%, 40%);">+struct gsm_network;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum msc_neighbor_type {</span><br><span style="color: hsl(120, 100%, 40%);">+  /* Neighboring BSC reachable via SCCP. */</span><br><span style="color: hsl(120, 100%, 40%);">+     MSC_NEIGHBOR_TYPE_BSC,</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* Neighboring MSC reachable via GSUP. */</span><br><span style="color: hsl(120, 100%, 40%);">+     MSC_NEIGHBOR_TYPE_MSC</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct neighbor_ident_addr {</span><br><span style="color: hsl(120, 100%, 40%);">+     enum msc_neighbor_type type;</span><br><span style="color: hsl(120, 100%, 40%);">+  union {</span><br><span style="color: hsl(120, 100%, 40%);">+               int point_code; /* BSC */</span><br><span style="color: hsl(120, 100%, 40%);">+             const char *ipa_name; /* MSC */</span><br><span style="color: hsl(120, 100%, 40%);">+       } a;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct neighbor_ident_list {</span><br><span style="color: hsl(120, 100%, 40%);">+      struct llist_head list;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct neighbor_ident {</span><br><span style="color: hsl(120, 100%, 40%);">+        struct llist_head entry;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* Address of a neighboring BSC or MSC. */</span><br><span style="color: hsl(120, 100%, 40%);">+    struct neighbor_ident_addr addr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* IDs of cells in this neighbor's domain. */</span><br><span style="color: hsl(120, 100%, 40%);">+     struct gsm0808_cell_id_list2 cell_ids;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct gsm0808_cell_id;</span><br><span style="color: hsl(120, 100%, 40%);">+struct gsm0808_cell_id_list2;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+const char *neighbor_ident_addr_name(struct gsm_network *net, const struct neighbor_ident_addr *ni_addr);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct neighbor_ident_list *neighbor_ident_init(void *talloc_ctx);</span><br><span style="color: hsl(120, 100%, 40%);">+void neighbor_ident_free(struct neighbor_ident_list *nil);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+bool neighbor_ident_addr_match(const struct neighbor_ident_addr *entry,</span><br><span style="color: hsl(120, 100%, 40%);">+                               const struct neighbor_ident_addr *search_for,</span><br><span style="color: hsl(120, 100%, 40%);">+                         bool exact_match);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int neighbor_ident_add(struct neighbor_ident_list *nil, const struct neighbor_ident_addr *addr,</span><br><span style="color: hsl(120, 100%, 40%);">+                 const struct gsm0808_cell_id_list2 *cell_ids);</span><br><span style="color: hsl(120, 100%, 40%);">+const struct gsm0808_cell_id_list2 *neighbor_ident_get(const struct neighbor_ident_list *nil,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                 const struct neighbor_ident_addr *addr);</span><br><span style="color: hsl(120, 100%, 40%);">+const struct neighbor_ident_addr *neighbor_ident_lookup_cell(const struct neighbor_ident_list *nil,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                       struct gsm0808_cell_id *cell_id);</span><br><span style="color: hsl(120, 100%, 40%);">+bool neighbor_ident_del(struct neighbor_ident_list *nil, const struct neighbor_ident_addr *addr);</span><br><span style="color: hsl(120, 100%, 40%);">+void neighbor_ident_clear(struct neighbor_ident_list *nil);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void neighbor_ident_iter(const struct neighbor_ident_list *nil,</span><br><span style="color: hsl(120, 100%, 40%);">+                      bool (* iter_cb )(const struct neighbor_ident_addr *addr,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       const struct gsm0808_cell_id_list2 *cell_ids,</span><br><span style="color: hsl(120, 100%, 40%);">+                                         void *cb_data),</span><br><span style="color: hsl(120, 100%, 40%);">+                     void *cb_data);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void neighbor_ident_vty_init(struct gsm_network *net);</span><br><span style="color: hsl(120, 100%, 40%);">+void neighbor_ident_vty_write(struct vty *vty);</span><br><span>diff --git a/src/libmsc/Makefile.am b/src/libmsc/Makefile.am</span><br><span>index 9183ff9..f498001 100644</span><br><span>--- a/src/libmsc/Makefile.am</span><br><span>+++ b/src/libmsc/Makefile.am</span><br><span>@@ -44,6 +44,8 @@</span><br><span>         mncc_sock.c \</span><br><span>        msc_ifaces.c \</span><br><span>       msc_mgcp.c \</span><br><span style="color: hsl(120, 100%, 40%);">+  neighbor_ident.c \</span><br><span style="color: hsl(120, 100%, 40%);">+    neighbor_ident_vty.c \</span><br><span>       ran_conn.c \</span><br><span>         rrlp.c \</span><br><span>     silent_call.c \</span><br><span>diff --git a/src/libmsc/msc_vty.c b/src/libmsc/msc_vty.c</span><br><span>index 7745e5d..1af42e4 100644</span><br><span>--- a/src/libmsc/msc_vty.c</span><br><span>+++ b/src/libmsc/msc_vty.c</span><br><span>@@ -1538,6 +1538,8 @@</span><br><span> #ifdef BUILD_IU</span><br><span>      ranap_iu_vty_init(MSC_NODE, &msc_network->iu.rab_assign_addr_enc);</span><br><span> #endif</span><br><span style="color: hsl(120, 100%, 40%);">+   neighbor_ident_vty_init(msc_network);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>      osmo_fsm_vty_add_cmds();</span><br><span> </span><br><span>         osmo_signal_register_handler(SS_SCALL, scall_cbfn, NULL);</span><br><span>diff --git a/src/libmsc/neighbor_ident.c b/src/libmsc/neighbor_ident.c</span><br><span>new file mode 100644</span><br><span>index 0000000..f7187a9</span><br><span>--- /dev/null</span><br><span>+++ b/src/libmsc/neighbor_ident.c</span><br><span>@@ -0,0 +1,206 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* Manage identity of neighboring BSS cells for inter-MSC handover. */</span><br><span style="color: hsl(120, 100%, 40%);">+/* (C) 2018 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * All Rights Reserved</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Author: Neels Hofmeyr <nhofmeyr@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+ * Author: Stefan Sperling <ssperling@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+ * it under the terms of the GNU Affero General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; either version 3 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+ * (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+ * GNU Affero General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * You should have received a copy of the GNU Affero General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/linuxlist.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/gsm0808.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/sigtran/osmo_ss7.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/msc/neighbor_ident.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/msc/gsm_data.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* XXX greater than or equal to IPA_STIRNG_MAX (libosmocore) and MAX_PC_STR_LEN (libosmo-sccp). */</span><br><span style="color: hsl(120, 100%, 40%);">+#define NEIGHBOR_IDENT_ADDR_STRING_MAX 64</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+const char *neighbor_ident_addr_name(struct gsm_network *net, const struct neighbor_ident_addr *na)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     static char buf[NEIGHBOR_IDENT_ADDR_STRING_MAX + 4];</span><br><span style="color: hsl(120, 100%, 40%);">+  struct osmo_ss7_instance *ss7;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      switch (na->type) {</span><br><span style="color: hsl(120, 100%, 40%);">+        case MSC_NEIGHBOR_TYPE_BSC:</span><br><span style="color: hsl(120, 100%, 40%);">+           ss7 = osmo_ss7_instance_find(net->a.cs7_instance);</span><br><span style="color: hsl(120, 100%, 40%);">+         OSMO_ASSERT(ss7);</span><br><span style="color: hsl(120, 100%, 40%);">+             snprintf(buf, sizeof(buf), "BSC %s", osmo_ss7_pointcode_print(ss7, na->a.point_code));</span><br><span style="color: hsl(120, 100%, 40%);">+           break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case MSC_NEIGHBOR_TYPE_MSC:</span><br><span style="color: hsl(120, 100%, 40%);">+           snprintf(buf, sizeof(buf), "MSC %s", na->a.ipa_name);</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return buf;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct neighbor_ident_list *neighbor_ident_init(void *talloc_ctx)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct neighbor_ident_list *nil = talloc_zero(talloc_ctx, struct neighbor_ident_list);</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(nil);</span><br><span style="color: hsl(120, 100%, 40%);">+     INIT_LLIST_HEAD(&nil->list);</span><br><span style="color: hsl(120, 100%, 40%);">+   return nil;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void neighbor_ident_free(struct neighbor_ident_list *nil)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!nil)</span><br><span style="color: hsl(120, 100%, 40%);">+             return;</span><br><span style="color: hsl(120, 100%, 40%);">+       talloc_free(nil);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct neighbor_ident *_neighbor_ident_get(const struct neighbor_ident_list *nil,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                const struct neighbor_ident_addr *na)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct neighbor_ident *ni;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  llist_for_each_entry(ni, &nil->list, entry) {</span><br><span style="color: hsl(120, 100%, 40%);">+          if (na->type != ni->addr.type)</span><br><span style="color: hsl(120, 100%, 40%);">+                  continue;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           switch (na->type) {</span><br><span style="color: hsl(120, 100%, 40%);">+                case MSC_NEIGHBOR_TYPE_BSC:</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (ni->addr.a.point_code == na->a.point_code)</span><br><span style="color: hsl(120, 100%, 40%);">+                          return ni;</span><br><span style="color: hsl(120, 100%, 40%);">+                    break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case MSC_NEIGHBOR_TYPE_MSC:</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (strcmp(ni->addr.a.ipa_name, na->a.ipa_name) == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                           return ni;</span><br><span style="color: hsl(120, 100%, 40%);">+                    break;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void _neighbor_ident_free(struct neighbor_ident *ni)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     llist_del(&ni->entry);</span><br><span style="color: hsl(120, 100%, 40%);">+ talloc_free(ni);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Add Cell Identifiers to a neighbor BSC/MSC entry.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Exactly one kind of identifier is allowed per entry, and any number of entries of that kind</span><br><span style="color: hsl(120, 100%, 40%);">+ * may be added up to the capacity of gsm0808_cell_id_list2, by one or more calls to this function. To</span><br><span style="color: hsl(120, 100%, 40%);">+ * replace an existing entry, first call neighbor_ident_del(nil, cell_id).</span><br><span style="color: hsl(120, 100%, 40%);">+ * \returns number of entries in the resulting identifier list, or negative on error:</span><br><span style="color: hsl(120, 100%, 40%);">+ *   see gsm0808_cell_id_list_add() for the meaning of returned error codes;</span><br><span style="color: hsl(120, 100%, 40%);">+ *   return -ENOMEM when the list is not initialized, -ERANGE when the BSIC value is too large. */</span><br><span style="color: hsl(120, 100%, 40%);">+int neighbor_ident_add(struct neighbor_ident_list *nil, const struct neighbor_ident_addr *addr,</span><br><span style="color: hsl(120, 100%, 40%);">+                   const struct gsm0808_cell_id_list2 *cell_id)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct neighbor_ident *ni;</span><br><span style="color: hsl(120, 100%, 40%);">+    int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!nil)</span><br><span style="color: hsl(120, 100%, 40%);">+             return -ENOMEM;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     ni = _neighbor_ident_get(nil, addr);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!ni) {</span><br><span style="color: hsl(120, 100%, 40%);">+            ni = talloc_zero(nil, struct neighbor_ident);</span><br><span style="color: hsl(120, 100%, 40%);">+         OSMO_ASSERT(ni);</span><br><span style="color: hsl(120, 100%, 40%);">+              ni->addr.type = addr->type;</span><br><span style="color: hsl(120, 100%, 40%);">+             switch (ni->addr.type) {</span><br><span style="color: hsl(120, 100%, 40%);">+           case MSC_NEIGHBOR_TYPE_MSC:</span><br><span style="color: hsl(120, 100%, 40%);">+                   ni->addr.a.ipa_name = talloc_strdup(ni, addr->a.ipa_name);</span><br><span style="color: hsl(120, 100%, 40%);">+                      break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case MSC_NEIGHBOR_TYPE_BSC:</span><br><span style="color: hsl(120, 100%, 40%);">+                   ni->addr.a.point_code = addr->a.point_code;</span><br><span style="color: hsl(120, 100%, 40%);">+                     break;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+             llist_add_tail(&ni->entry, &nil->list);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   rc = gsm0808_cell_id_list_add(&ni->cell_ids, cell_id);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  return ni->cell_ids.id_list_len;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Find cell identity for given BSC or MSC, as previously added by neighbor_ident_add().</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+const struct gsm0808_cell_id_list2 *neighbor_ident_get(const struct neighbor_ident_list *nil,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                      const struct neighbor_ident_addr *addr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct neighbor_ident *ni;</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!nil)</span><br><span style="color: hsl(120, 100%, 40%);">+             return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  ni = _neighbor_ident_get(nil, addr);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!ni)</span><br><span style="color: hsl(120, 100%, 40%);">+              return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  return &ni->cell_ids;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Find a BSC or MSC, as previously added by neighbor_ident_add(), for a given cell identity.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+const struct neighbor_ident_addr *neighbor_ident_lookup_cell(const struct neighbor_ident_list *nil,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                        struct gsm0808_cell_id *cell_id)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct neighbor_ident *ni;</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!nil)</span><br><span style="color: hsl(120, 100%, 40%);">+             return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  llist_for_each_entry(ni, &nil->list, entry) {</span><br><span style="color: hsl(120, 100%, 40%);">+          if (gsm0808_cell_id_matches_list(cell_id, &ni->cell_ids, 0))</span><br><span style="color: hsl(120, 100%, 40%);">+                   return &ni->addr;</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+bool neighbor_ident_del(struct neighbor_ident_list *nil, const struct neighbor_ident_addr *addr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct neighbor_ident *ni;</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!nil)</span><br><span style="color: hsl(120, 100%, 40%);">+             return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ ni = _neighbor_ident_get(nil, addr);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!ni)</span><br><span style="color: hsl(120, 100%, 40%);">+              return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ _neighbor_ident_free(ni);</span><br><span style="color: hsl(120, 100%, 40%);">+     return true;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void neighbor_ident_clear(struct neighbor_ident_list *nil)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct neighbor_ident *ni;</span><br><span style="color: hsl(120, 100%, 40%);">+    while ((ni = llist_first_entry_or_null(&nil->list, struct neighbor_ident, entry)))</span><br><span style="color: hsl(120, 100%, 40%);">+             _neighbor_ident_free(ni);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Iterate all neighbor_ident_list entries and call iter_cb for each.</span><br><span style="color: hsl(120, 100%, 40%);">+ * If iter_cb returns false, the iteration is stopped. */</span><br><span style="color: hsl(120, 100%, 40%);">+void neighbor_ident_iter(const struct neighbor_ident_list *nil,</span><br><span style="color: hsl(120, 100%, 40%);">+                     bool (* iter_cb )(const struct neighbor_ident_addr *addr,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       const struct gsm0808_cell_id_list2 *cell_ids,</span><br><span style="color: hsl(120, 100%, 40%);">+                                         void *cb_data),</span><br><span style="color: hsl(120, 100%, 40%);">+                     void *cb_data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct neighbor_ident *ni, *ni_next;</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!nil)</span><br><span style="color: hsl(120, 100%, 40%);">+             return;</span><br><span style="color: hsl(120, 100%, 40%);">+       llist_for_each_entry_safe(ni, ni_next, &nil->list, entry) {</span><br><span style="color: hsl(120, 100%, 40%);">+            if (!iter_cb(&ni->addr, &ni->cell_ids, cb_data))</span><br><span style="color: hsl(120, 100%, 40%);">+                        return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/libmsc/neighbor_ident_vty.c b/src/libmsc/neighbor_ident_vty.c</span><br><span>new file mode 100644</span><br><span>index 0000000..a44a284</span><br><span>--- /dev/null</span><br><span>+++ b/src/libmsc/neighbor_ident_vty.c</span><br><span>@@ -0,0 +1,413 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* Quagga VTY implementation to manage identity of neighboring BSS cells for inter-BSC handover. */</span><br><span style="color: hsl(120, 100%, 40%);">+/* (C) 2018 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * All Rights Reserved</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Author: Neels Hofmeyr <nhofmeyr@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+ * Author: Stefan Sperling <ssperling@sysmocom.de></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+ * it under the terms of the GNU Affero General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; either version 3 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+ * (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+ * GNU Affero General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * You should have received a copy of the GNU Affero General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdlib.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <string.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/vty/command.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/gsm0808.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/sigtran/osmo_ss7.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/msc/vty.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/msc/neighbor_ident.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/msc/gsm_data.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define NEIGHBOR_ADD_CMD "neighbor "</span><br><span style="color: hsl(120, 100%, 40%);">+#define NEIGHBOR_DEL_CMD "no neighbor "</span><br><span style="color: hsl(120, 100%, 40%);">+#define NEIGHBOR_SHOW_CMD "show neighbor "</span><br><span style="color: hsl(120, 100%, 40%);">+#define NEIGHBOR_DOC "Manage neighbor BSS cells\n"</span><br><span style="color: hsl(120, 100%, 40%);">+#define NEIGHBOR_ADD_DOC NEIGHBOR_DOC "Add "</span><br><span style="color: hsl(120, 100%, 40%);">+#define NEIGHBOR_DEL_DOC NO_STR "Remove neighbor BSS cell\n"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define LAC_PARAMS "lac <0-65535>"</span><br><span style="color: hsl(120, 100%, 40%);">+#define LAC_DOC "Neighbor cell by LAC\n" "LAC\n"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define LAC_CI_PARAMS "lac-ci <0-65535> <0-65535>"</span><br><span style="color: hsl(120, 100%, 40%);">+#define LAC_CI_DOC "Neighbor cell by LAC and CI\n" "LAC\n" "CI\n"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define CGI_PARAMS "cgi <0-999> <0-999> <0-65535> <0-65535>"</span><br><span style="color: hsl(120, 100%, 40%);">+#define CGI_DOC "Neighbor cell by cgi\n" "MCC\n" "MNC\n" "LAC\n" "CI\n"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define NEIGHBOR_IDENT_VTY_BSC_ADDR_PARAMS "bsc-pc POINT_CODE"</span><br><span style="color: hsl(120, 100%, 40%);">+#define NEIGHBOR_IDENT_VTY_BSC_ADDR_DOC "Point code of neighbor BSC\n" "Point code value\n"</span><br><span style="color: hsl(120, 100%, 40%);">+#define NEIGHBOR_IDENT_VTY_MSC_ADDR_PARAMS "msc-ipa-name IPA_NAME"</span><br><span style="color: hsl(120, 100%, 40%);">+#define NEIGHBOR_IDENT_VTY_MSC_ADDR_DOC "IPA name of neighbor MSC\n" "IPA name value\n"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct gsm_network *g_net = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct gsm0808_cell_id *neighbor_ident_vty_parse_lac(struct vty *vty, const char **argv)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   static struct gsm0808_cell_id cell_id;</span><br><span style="color: hsl(120, 100%, 40%);">+        cell_id = (struct gsm0808_cell_id){</span><br><span style="color: hsl(120, 100%, 40%);">+           .id_discr = CELL_IDENT_LAC,</span><br><span style="color: hsl(120, 100%, 40%);">+           .id.lac = atoi(argv[0]),</span><br><span style="color: hsl(120, 100%, 40%);">+      };</span><br><span style="color: hsl(120, 100%, 40%);">+    return &cell_id;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct gsm0808_cell_id *neighbor_ident_vty_parse_lac_ci(struct vty *vty, const char **argv)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      static struct gsm0808_cell_id cell_id;</span><br><span style="color: hsl(120, 100%, 40%);">+        cell_id = (struct gsm0808_cell_id){</span><br><span style="color: hsl(120, 100%, 40%);">+           .id_discr = CELL_IDENT_LAC_AND_CI,</span><br><span style="color: hsl(120, 100%, 40%);">+            .id.lac_and_ci = {</span><br><span style="color: hsl(120, 100%, 40%);">+                    .lac = atoi(argv[0]),</span><br><span style="color: hsl(120, 100%, 40%);">+                 .ci = atoi(argv[1]),</span><br><span style="color: hsl(120, 100%, 40%);">+          },</span><br><span style="color: hsl(120, 100%, 40%);">+    };</span><br><span style="color: hsl(120, 100%, 40%);">+    return &cell_id;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct gsm0808_cell_id *neighbor_ident_vty_parse_cgi(struct vty *vty, const char **argv)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ static struct gsm0808_cell_id cell_id;</span><br><span style="color: hsl(120, 100%, 40%);">+        cell_id = (struct gsm0808_cell_id){</span><br><span style="color: hsl(120, 100%, 40%);">+           .id_discr = CELL_IDENT_WHOLE_GLOBAL,</span><br><span style="color: hsl(120, 100%, 40%);">+  };</span><br><span style="color: hsl(120, 100%, 40%);">+    struct osmo_cell_global_id *cgi = &cell_id.id.global;</span><br><span style="color: hsl(120, 100%, 40%);">+     const char *mcc = argv[0];</span><br><span style="color: hsl(120, 100%, 40%);">+    const char *mnc = argv[1];</span><br><span style="color: hsl(120, 100%, 40%);">+    const char *lac = argv[2];</span><br><span style="color: hsl(120, 100%, 40%);">+    const char *ci = argv[3];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (osmo_mcc_from_str(mcc, &cgi->lai.plmn.mcc)) {</span><br><span style="color: hsl(120, 100%, 40%);">+              vty_out(vty, "%% Error decoding MCC: %s%s", mcc, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+              return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (osmo_mnc_from_str(mnc, &cgi->lai.plmn.mnc, &cgi->lai.plmn.mnc_3_digits)) {</span><br><span style="color: hsl(120, 100%, 40%);">+          vty_out(vty, "%% Error decoding MNC: %s%s", mnc, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+              return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   cgi->lai.lac = atoi(lac);</span><br><span style="color: hsl(120, 100%, 40%);">+  cgi->cell_identity = atoi(ci);</span><br><span style="color: hsl(120, 100%, 40%);">+     return &cell_id;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int add_neighbor(struct vty *vty, struct neighbor_ident_addr *addr, const struct gsm0808_cell_id *cell_id)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct gsm0808_cell_id_list2 cell_ids;</span><br><span style="color: hsl(120, 100%, 40%);">+        int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     gsm0808_cell_id_to_list(&cell_ids, cell_id);</span><br><span style="color: hsl(120, 100%, 40%);">+      rc = neighbor_ident_add(g_net->neighbor_list, addr, &cell_ids);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              vty_out(vty, "%% Error: cannot add cell %s to neighbor %s: %s%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                   gsm0808_cell_id_name(cell_id), neighbor_ident_addr_name(g_net, addr),</span><br><span style="color: hsl(120, 100%, 40%);">+                 strerror(-rc), VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+          return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+     return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int parse_point_code(const char *point_code_str)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct osmo_ss7_instance *ss7 = osmo_ss7_instance_find(g_net->a.cs7_instance);</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(ss7);</span><br><span style="color: hsl(120, 100%, 40%);">+     return osmo_ss7_pointcode_parse(ss7, point_code_str);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_neighbor_add_lac_bsc, cfg_neighbor_add_lac_bsc_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+     NEIGHBOR_ADD_CMD LAC_PARAMS " " NEIGHBOR_IDENT_VTY_BSC_ADDR_PARAMS,</span><br><span style="color: hsl(120, 100%, 40%);">+ NEIGHBOR_ADD_DOC LAC_DOC " " NEIGHBOR_IDENT_VTY_BSC_ADDR_DOC)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct neighbor_ident_addr addr;</span><br><span style="color: hsl(120, 100%, 40%);">+      int point_code = parse_point_code(argv[1]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (point_code < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              vty_out(vty, "Could not parse point code '%s'%s", argv[0], VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+            return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   addr.type = MSC_NEIGHBOR_TYPE_BSC;</span><br><span style="color: hsl(120, 100%, 40%);">+    addr.a.point_code = point_code;</span><br><span style="color: hsl(120, 100%, 40%);">+       return add_neighbor(vty, &addr, neighbor_ident_vty_parse_lac(vty, argv + 1));</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_neighbor_add_lac_msc, cfg_neighbor_add_lac_msc_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+ NEIGHBOR_ADD_CMD LAC_PARAMS " " NEIGHBOR_IDENT_VTY_MSC_ADDR_PARAMS,</span><br><span style="color: hsl(120, 100%, 40%);">+ NEIGHBOR_ADD_DOC LAC_DOC " " NEIGHBOR_IDENT_VTY_MSC_ADDR_DOC)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct neighbor_ident_addr addr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    addr.type = MSC_NEIGHBOR_TYPE_MSC;</span><br><span style="color: hsl(120, 100%, 40%);">+    addr.a.ipa_name = argv[1];</span><br><span style="color: hsl(120, 100%, 40%);">+    return add_neighbor(vty, &addr, neighbor_ident_vty_parse_lac(vty, argv + 1));</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_neighbor_add_lac_ci_bsc, cfg_neighbor_add_lac_ci_bsc_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+   NEIGHBOR_ADD_CMD LAC_CI_PARAMS " " NEIGHBOR_IDENT_VTY_BSC_ADDR_PARAMS,</span><br><span style="color: hsl(120, 100%, 40%);">+      NEIGHBOR_ADD_DOC LAC_CI_DOC " " NEIGHBOR_IDENT_VTY_BSC_ADDR_DOC)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct neighbor_ident_addr addr;</span><br><span style="color: hsl(120, 100%, 40%);">+      int point_code = parse_point_code(argv[2]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (point_code < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              vty_out(vty, "Could not parse point code '%s'%s", argv[0], VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+            return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   addr.type = MSC_NEIGHBOR_TYPE_BSC;</span><br><span style="color: hsl(120, 100%, 40%);">+    addr.a.point_code = point_code;</span><br><span style="color: hsl(120, 100%, 40%);">+       return add_neighbor(vty, &addr, neighbor_ident_vty_parse_lac_ci(vty, argv + 1));</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_neighbor_add_lac_ci_msc, cfg_neighbor_add_lac_ci_msc_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+        NEIGHBOR_ADD_CMD LAC_CI_PARAMS " " NEIGHBOR_IDENT_VTY_MSC_ADDR_PARAMS,</span><br><span style="color: hsl(120, 100%, 40%);">+      NEIGHBOR_ADD_DOC LAC_CI_DOC " " NEIGHBOR_IDENT_VTY_MSC_ADDR_DOC)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct neighbor_ident_addr addr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    addr.type = MSC_NEIGHBOR_TYPE_MSC;</span><br><span style="color: hsl(120, 100%, 40%);">+    addr.a.ipa_name = argv[2];</span><br><span style="color: hsl(120, 100%, 40%);">+    return add_neighbor(vty, &addr, neighbor_ident_vty_parse_lac_ci(vty, argv + 1));</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_neighbor_add_cgi_bsc, cfg_neighbor_add_cgi_bsc_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      NEIGHBOR_ADD_CMD CGI_PARAMS " " NEIGHBOR_IDENT_VTY_BSC_ADDR_PARAMS,</span><br><span style="color: hsl(120, 100%, 40%);">+ NEIGHBOR_ADD_DOC CGI_DOC " " NEIGHBOR_IDENT_VTY_BSC_ADDR_DOC)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct neighbor_ident_addr addr;</span><br><span style="color: hsl(120, 100%, 40%);">+      int point_code = parse_point_code(argv[4]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (point_code < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              vty_out(vty, "Could not parse point code '%s'%s", argv[0], VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+            return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   addr.type = MSC_NEIGHBOR_TYPE_BSC;</span><br><span style="color: hsl(120, 100%, 40%);">+    addr.a.point_code = point_code;</span><br><span style="color: hsl(120, 100%, 40%);">+       return add_neighbor(vty, &addr, neighbor_ident_vty_parse_cgi(vty, argv + 1));</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_neighbor_add_cgi_msc, cfg_neighbor_add_cgi_msc_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+ NEIGHBOR_ADD_CMD CGI_PARAMS " " NEIGHBOR_IDENT_VTY_MSC_ADDR_PARAMS,</span><br><span style="color: hsl(120, 100%, 40%);">+ NEIGHBOR_ADD_DOC CGI_DOC " " NEIGHBOR_IDENT_VTY_MSC_ADDR_DOC)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct neighbor_ident_addr addr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    addr.type = MSC_NEIGHBOR_TYPE_MSC;</span><br><span style="color: hsl(120, 100%, 40%);">+    addr.a.ipa_name = argv[4];</span><br><span style="color: hsl(120, 100%, 40%);">+    return add_neighbor(vty, &addr, neighbor_ident_vty_parse_cgi(vty, argv + 1));</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int del_by_addr(struct vty *vty, const struct neighbor_ident_addr *addr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    int removed = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (vty->node != MSC_NODE) {</span><br><span style="color: hsl(120, 100%, 40%);">+               vty_out(vty, "%% Error: cannot remove neighbor, not on MSC node%s", VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+           return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (neighbor_ident_del(g_net->neighbor_list, addr)) {</span><br><span style="color: hsl(120, 100%, 40%);">+              vty_out(vty, "%% Removed neighbor %s%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                    neighbor_ident_addr_name(g_net, addr), VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+          removed = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!removed) {</span><br><span style="color: hsl(120, 100%, 40%);">+               vty_out(vty, "%% Cannot remove, no such neighbor: %s%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                    neighbor_ident_addr_name(g_net, addr), VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+          return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_del_neighbor_bsc, cfg_del_neighbor_bsc_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      NEIGHBOR_DEL_CMD NEIGHBOR_IDENT_VTY_BSC_ADDR_PARAMS,</span><br><span style="color: hsl(120, 100%, 40%);">+      SHOW_STR "Delete a neighbor BSC\n" "BSC point code\n"</span><br><span style="color: hsl(120, 100%, 40%);">+      "Delete a specified neighbor BSC\n"</span><br><span style="color: hsl(120, 100%, 40%);">+      NEIGHBOR_IDENT_VTY_BSC_ADDR_DOC)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct neighbor_ident_addr addr;</span><br><span style="color: hsl(120, 100%, 40%);">+      int point_code = parse_point_code(argv[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (point_code < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              vty_out(vty, "Could not parse point code '%s'%s", argv[0], VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+            return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   addr.type = MSC_NEIGHBOR_TYPE_BSC;</span><br><span style="color: hsl(120, 100%, 40%);">+    addr.a.point_code = point_code;</span><br><span style="color: hsl(120, 100%, 40%);">+       return del_by_addr(vty, &addr);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_del_neighbor_msc, cfg_del_neighbor_msc_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      NEIGHBOR_DEL_CMD NEIGHBOR_IDENT_VTY_MSC_ADDR_PARAMS,</span><br><span style="color: hsl(120, 100%, 40%);">+      SHOW_STR "Delete a neighbor MSC\n" "MSC ipa-nam\n"</span><br><span style="color: hsl(120, 100%, 40%);">+      "Delete a specified neighbor MSC\n"</span><br><span style="color: hsl(120, 100%, 40%);">+      NEIGHBOR_IDENT_VTY_MSC_ADDR_DOC)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct neighbor_ident_addr addr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    addr.type = MSC_NEIGHBOR_TYPE_MSC;</span><br><span style="color: hsl(120, 100%, 40%);">+    addr.a.ipa_name = argv[0];</span><br><span style="color: hsl(120, 100%, 40%);">+    return del_by_addr(vty, &addr);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void write_neighbor_ident(struct vty *vty, const struct neighbor_ident *ni)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       const struct neighbor_ident_addr *addr = &ni->addr;</span><br><span style="color: hsl(120, 100%, 40%);">+    const struct gsm0808_cell_id_list2 *cell_ids = &ni->cell_ids;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct osmo_ss7_instance *ss7;</span><br><span style="color: hsl(120, 100%, 40%);">+        int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      switch (cell_ids->id_discr) {</span><br><span style="color: hsl(120, 100%, 40%);">+      case CELL_IDENT_LAC:</span><br><span style="color: hsl(120, 100%, 40%);">+          for (i = 0; i < cell_ids->id_list_len; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   vty_out(vty, " neighbor lac %u", cell_ids->id_list[i].lac);</span><br><span style="color: hsl(120, 100%, 40%);">+              }</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CELL_IDENT_LAC_AND_CI:</span><br><span style="color: hsl(120, 100%, 40%);">+           for (i = 0; i < cell_ids->id_list_len; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   vty_out(vty, " neighbor lac-ci %u %u", cell_ids->id_list[i].lac_and_ci.lac,</span><br><span style="color: hsl(120, 100%, 40%);">+                              cell_ids->id_list[i].lac_and_ci.ci);</span><br><span style="color: hsl(120, 100%, 40%);">+               }</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CELL_IDENT_WHOLE_GLOBAL:</span><br><span style="color: hsl(120, 100%, 40%);">+         for (i = 0; i < cell_ids->id_list_len; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   const struct osmo_cell_global_id *cgi = &cell_ids->id_list[i].global;</span><br><span style="color: hsl(120, 100%, 40%);">+                  vty_out(vty, " neighbor cgi %s %s %u %u", osmo_mcc_name(cgi->lai.plmn.mcc),</span><br><span style="color: hsl(120, 100%, 40%);">+                              osmo_mnc_name(cgi->lai.plmn.mnc, cgi->lai.plmn.mnc_3_digits),</span><br><span style="color: hsl(120, 100%, 40%);">+                           cgi->lai.lac, cgi->cell_identity);</span><br><span style="color: hsl(120, 100%, 40%);">+              }</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              vty_out(vty, "%% Unsupported Cell Identity%s", VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+                return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   switch (ni->addr.type) {</span><br><span style="color: hsl(120, 100%, 40%);">+   case MSC_NEIGHBOR_TYPE_BSC:</span><br><span style="color: hsl(120, 100%, 40%);">+           ss7 = osmo_ss7_instance_find(g_net->a.cs7_instance);</span><br><span style="color: hsl(120, 100%, 40%);">+               OSMO_ASSERT(ss7);</span><br><span style="color: hsl(120, 100%, 40%);">+             vty_out(vty, "bsc-pc %s%s", osmo_ss7_pointcode_print(ss7, addr->a.point_code), VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case MSC_NEIGHBOR_TYPE_MSC:</span><br><span style="color: hsl(120, 100%, 40%);">+           vty_out(vty, "msc-ipa-name %s%s", addr->a.ipa_name, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void neighbor_ident_vty_write(struct vty *vty)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     const struct neighbor_ident *ni;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    llist_for_each_entry(ni, &g_net->neighbor_list->list, entry)</span><br><span style="color: hsl(120, 100%, 40%);">+                write_neighbor_ident(vty, ni);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(show_neighbor_all, show_neighbor_all_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      NEIGHBOR_SHOW_CMD "all",</span><br><span style="color: hsl(120, 100%, 40%);">+      SHOW_STR "Display information about neighbor BSCs and MSCs\n"</span><br><span style="color: hsl(120, 100%, 40%);">+      "Show which cells are reachable via the neighbor BSCs and MSCs\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct neighbor_ident *ni;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  llist_for_each_entry(ni, &g_net->neighbor_list->list, entry) {</span><br><span style="color: hsl(120, 100%, 40%);">+              vty_out(vty, "%s: %s%s", neighbor_ident_addr_name(g_net, &ni->addr),</span><br><span style="color: hsl(120, 100%, 40%);">+         gsm0808_cell_id_list_name(&ni->cell_ids), VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(show_neighbor_bsc, show_neighbor_bsc_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      NEIGHBOR_SHOW_CMD NEIGHBOR_IDENT_VTY_BSC_ADDR_PARAMS,</span><br><span style="color: hsl(120, 100%, 40%);">+      SHOW_STR "Display information about a neighbor BSC\n" "BSC point code\n"</span><br><span style="color: hsl(120, 100%, 40%);">+      "Show which cells are reachable via the specified neighbor BSC\n"</span><br><span style="color: hsl(120, 100%, 40%);">+      NEIGHBOR_IDENT_VTY_BSC_ADDR_DOC)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      int point_code;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct neighbor_ident *ni;</span><br><span style="color: hsl(120, 100%, 40%);">+    int found = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      point_code = parse_point_code(argv[0]);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (point_code < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              vty_out(vty, "Could not parse point code '%s'%s", argv[0], VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+            return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   llist_for_each_entry(ni, &g_net->neighbor_list->list, entry) {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (ni->addr.type != MSC_NEIGHBOR_TYPE_BSC)</span><br><span style="color: hsl(120, 100%, 40%);">+                        continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             if (ni->addr.a.point_code == point_code) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 vty_out(vty, "%s%s", gsm0808_cell_id_list_name(&ni->cell_ids), VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+                 found = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+                    break;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!found)</span><br><span style="color: hsl(120, 100%, 40%);">+           vty_out(vty, "%% No entry for %s%s", argv[0], VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(show_neighbor_msc, show_neighbor_msc_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      NEIGHBOR_SHOW_CMD NEIGHBOR_IDENT_VTY_MSC_ADDR_PARAMS,</span><br><span style="color: hsl(120, 100%, 40%);">+      SHOW_STR "Display information about a neighbor MSC\n" "MSC ipa-name\n"</span><br><span style="color: hsl(120, 100%, 40%);">+      "Show which cells are reachable via the specified neighbor MSC\n"</span><br><span style="color: hsl(120, 100%, 40%);">+      NEIGHBOR_IDENT_VTY_MSC_ADDR_DOC)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        const char *ipa_name = argv[0];</span><br><span style="color: hsl(120, 100%, 40%);">+       struct neighbor_ident *ni;</span><br><span style="color: hsl(120, 100%, 40%);">+    int found = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      llist_for_each_entry(ni, &g_net->neighbor_list->list, entry) {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (ni->addr.type != MSC_NEIGHBOR_TYPE_MSC)</span><br><span style="color: hsl(120, 100%, 40%);">+                        continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             if (strcmp(ni->addr.a.ipa_name, ipa_name) == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  vty_out(vty, "%s%s", gsm0808_cell_id_list_name(&ni->cell_ids), VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+                 found = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+                    break;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!found)</span><br><span style="color: hsl(120, 100%, 40%);">+           vty_out(vty, "%% No entry for %s%s", ipa_name, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void neighbor_ident_vty_init(struct gsm_network *net)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    g_net = net;</span><br><span style="color: hsl(120, 100%, 40%);">+  g_net->neighbor_list = neighbor_ident_init(net);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ install_element(MSC_NODE, &cfg_neighbor_add_lac_bsc_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+ install_element(MSC_NODE, &cfg_neighbor_add_lac_msc_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+ install_element(MSC_NODE, &cfg_neighbor_add_lac_ci_bsc_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+      install_element(MSC_NODE, &cfg_neighbor_add_lac_ci_msc_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+      install_element(MSC_NODE, &cfg_neighbor_add_cgi_bsc_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+ install_element(MSC_NODE, &cfg_neighbor_add_cgi_msc_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+ install_element(MSC_NODE, &cfg_del_neighbor_bsc_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+     install_element(MSC_NODE, &cfg_del_neighbor_msc_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+     install_element_ve(&show_neighbor_all_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+       install_element_ve(&show_neighbor_bsc_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+       install_element_ve(&show_neighbor_msc_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/12446">change 12446</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/12446"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmo-msc </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>
<div style="display:none"> Gerrit-Change-Id: Ia0dd08b087bfd4aa22e234917669d003150a4cd4 </div>
<div style="display:none"> Gerrit-Change-Number: 12446 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Stefan Sperling <stsp@stsp.name> </div>