<p>Neels Hofmeyr has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/9666">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">inter-BSC HO: add neighbor_ident API to manage neighbor-BSS-cells<br><br>Change-Id: I0153d7069817fba9146ddc11214de2757d7d37bf<br>---<br>M include/osmocom/bsc/Makefile.am<br>M include/osmocom/bsc/gsm_data.h<br>M include/osmocom/bsc/handover.h<br>A include/osmocom/bsc/neighbor_ident.h<br>M src/osmo-bsc/Makefile.am<br>M src/osmo-bsc/bsc_init.c<br>M src/osmo-bsc/bsc_vty.c<br>M src/osmo-bsc/gsm_data.c<br>M src/osmo-bsc/handover_logic.c<br>A src/osmo-bsc/neighbor_ident.c<br>A src/osmo-bsc/neighbor_ident_vty.c<br>M src/osmo-bsc/net_init.c<br>M src/osmo-bsc/system_information.c<br>M tests/bsc/Makefile.am<br>M tests/gsm0408/Makefile.am<br>M tests/handover/Makefile.am<br>A tests/handover/neighbor_ident_test.c<br>A tests/handover/neighbor_ident_test.err<br>A tests/handover/neighbor_ident_test.ok<br>A tests/neighbor_ident.vty<br>M tests/testsuite.at<br>21 files changed, 1,958 insertions(+), 5 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/osmo-bsc refs/changes/66/9666/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/osmocom/bsc/Makefile.am b/include/osmocom/bsc/Makefile.am</span><br><span>index 5fa39eb..18737a3 100644</span><br><span>--- a/include/osmocom/bsc/Makefile.am</span><br><span>+++ b/include/osmocom/bsc/Makefile.am</span><br><span>@@ -27,6 +27,7 @@</span><br><span>      meas_feed.h \</span><br><span>        meas_rep.h \</span><br><span>         misdn.h \</span><br><span style="color: hsl(120, 100%, 40%);">+     neighbor_ident.h \</span><br><span>   network_listen.h \</span><br><span>   openbscdefines.h \</span><br><span>   osmo_bsc.h \</span><br><span>diff --git a/include/osmocom/bsc/gsm_data.h b/include/osmocom/bsc/gsm_data.h</span><br><span>index 5794617..76a1b30 100644</span><br><span>--- a/include/osmocom/bsc/gsm_data.h</span><br><span>+++ b/include/osmocom/bsc/gsm_data.h</span><br><span>@@ -35,6 +35,7 @@</span><br><span> struct mgcp_client_conf;</span><br><span> struct mgcp_client;</span><br><span> struct mgcp_ctx;</span><br><span style="color: hsl(120, 100%, 40%);">+struct gsm0808_cell_id;</span><br><span> </span><br><span> /** annotations for msgb ownership */</span><br><span> #define __uses</span><br><span>@@ -750,6 +751,12 @@</span><br><span>  unsigned int used;</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* Useful to track N-N relations between BTS, for example neighbors. */</span><br><span style="color: hsl(120, 100%, 40%);">+struct gsm_bts_ref {</span><br><span style="color: hsl(120, 100%, 40%);">+   struct llist_head entry;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gsm_bts *bts;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* One BTS */</span><br><span> struct gsm_bts {</span><br><span>      /* list header in net->bts_list */</span><br><span>@@ -984,6 +991,11 @@</span><br><span> </span><br><span>     struct handover_cfg *ho;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+  /* A list of struct gsm_bts_ref, indicating neighbors of this BTS.</span><br><span style="color: hsl(120, 100%, 40%);">+     * When the si_common neigh_list is in automatic mode, it is populated from this list as well as</span><br><span style="color: hsl(120, 100%, 40%);">+       * gsm_network->neighbor_bss_cells. */</span><br><span style="color: hsl(120, 100%, 40%);">+     struct llist_head local_neighbors;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>         /* BTS-specific overrides for timer values from struct gsm_network. */</span><br><span>       uint8_t T3122;  /* ASSIGMENT REJECT wait indication */</span><br><span> </span><br><span>@@ -998,6 +1010,10 @@</span><br><span> </span><br><span> struct gsm_bts *gsm_bts_alloc(struct gsm_network *net, uint8_t bts_num);</span><br><span> struct gsm_bts *gsm_bts_num(struct gsm_network *net, int num);</span><br><span style="color: hsl(120, 100%, 40%);">+bool gsm_bts_matches_cell_id(struct gsm_bts *bts, const struct gsm0808_cell_id *ci);</span><br><span style="color: hsl(120, 100%, 40%);">+struct gsm_bts *gsm_bts_by_cell_id(struct gsm_network *net, const struct gsm0808_cell_id *ci);</span><br><span style="color: hsl(120, 100%, 40%);">+int gsm_bts_local_neighbor_add(struct gsm_bts *bts, struct gsm_bts *neighbor);</span><br><span style="color: hsl(120, 100%, 40%);">+int gsm_bts_local_neighbor_del(struct gsm_bts *bts, const struct gsm_bts *neighbor);</span><br><span> </span><br><span> struct gsm_bts_trx *gsm_bts_trx_alloc(struct gsm_bts *bts);</span><br><span> struct gsm_bts_trx *gsm_bts_trx_num(const struct gsm_bts *bts, int num);</span><br><span>@@ -1281,6 +1297,9 @@</span><br><span>              struct mgcp_client_conf *conf;</span><br><span>               struct mgcp_client *client;</span><br><span>  } mgw;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* Remote BSS Cell Identifier Lists */</span><br><span style="color: hsl(120, 100%, 40%);">+        struct neighbor_ident_list *neighbor_bss_cells;</span><br><span> };</span><br><span> </span><br><span> static inline const struct osmo_location_area_id *bts_lai(struct gsm_bts *bts)</span><br><span>diff --git a/include/osmocom/bsc/handover.h b/include/osmocom/bsc/handover.h</span><br><span>index eb03f6a..847d985 100644</span><br><span>--- a/include/osmocom/bsc/handover.h</span><br><span>+++ b/include/osmocom/bsc/handover.h</span><br><span>@@ -6,6 +6,8 @@</span><br><span> #include <osmocom/core/timer.h></span><br><span> #include <osmocom/gsm/gsm_utils.h></span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/neighbor_ident.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> struct gsm_lchan;</span><br><span> struct gsm_bts;</span><br><span> struct gsm_subscriber_connection;</span><br><span>@@ -93,3 +95,7 @@</span><br><span> </span><br><span> void handover_decision_callbacks_register(struct handover_decision_callbacks *hdc);</span><br><span> struct handover_decision_callbacks *handover_decision_callbacks_get(int hodec_id);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct gsm_bts *bts_by_neighbor_ident(const struct gsm_network *net,</span><br><span style="color: hsl(120, 100%, 40%);">+                                      const struct neighbor_ident_key *search_for);</span><br><span style="color: hsl(120, 100%, 40%);">+struct neighbor_ident_key *bts_ident_key(const struct gsm_bts *bts);</span><br><span>diff --git a/include/osmocom/bsc/neighbor_ident.h b/include/osmocom/bsc/neighbor_ident.h</span><br><span>new file mode 100644</span><br><span>index 0000000..86e062a</span><br><span>--- /dev/null</span><br><span>+++ b/include/osmocom/bsc/neighbor_ident.h</span><br><span>@@ -0,0 +1,60 @@</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%);">+</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%);">+struct gsm_bts;</span><br><span style="color: hsl(120, 100%, 40%);">+struct neighbor_ident_list;</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%);">+enum bsic_kind {</span><br><span style="color: hsl(120, 100%, 40%);">+  BSIC_NONE,</span><br><span style="color: hsl(120, 100%, 40%);">+    BSIC_6BIT,</span><br><span style="color: hsl(120, 100%, 40%);">+    BSIC_9BIT,</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%);">+#define NEIGHBOR_IDENT_KEY_ANY_BTS -1</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct neighbor_ident_key {</span><br><span style="color: hsl(120, 100%, 40%);">+        int from_bts; /*< BTS nr 0..255 or NEIGHBOR_IDENT_KEY_ANY_BTS */</span><br><span style="color: hsl(120, 100%, 40%);">+   uint16_t arfcn;</span><br><span style="color: hsl(120, 100%, 40%);">+       enum bsic_kind bsic_kind;</span><br><span style="color: hsl(120, 100%, 40%);">+     uint16_t bsic;</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%);">+const char *neighbor_ident_key_name(const struct neighbor_ident_key *ni_key);</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_key_match(const struct neighbor_ident_key *entry,</span><br><span style="color: hsl(120, 100%, 40%);">+                              const struct neighbor_ident_key *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_key *key,</span><br><span style="color: hsl(120, 100%, 40%);">+                    const struct gsm0808_cell_id_list2 *val);</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_key *key);</span><br><span style="color: hsl(120, 100%, 40%);">+bool neighbor_ident_del(struct neighbor_ident_list *nil, const struct neighbor_ident_key *key);</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_key *key,</span><br><span style="color: hsl(120, 100%, 40%);">+                                         const struct gsm0808_cell_id_list2 *val,</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, struct neighbor_ident_list *nil);</span><br><span style="color: hsl(120, 100%, 40%);">+void neighbor_ident_vty_write(struct vty *vty, const char *indent, struct gsm_bts *bts);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define NEIGHBOR_IDENT_VTY_KEY_PARAMS "arfcn <0-1023> (bsic|bsic9) (<0-511>|any)"</span><br><span style="color: hsl(120, 100%, 40%);">+#define NEIGHBOR_IDENT_VTY_KEY_DOC \</span><br><span style="color: hsl(120, 100%, 40%);">+        "ARFCN of neighbor cell\n" "ARFCN value\n" \</span><br><span style="color: hsl(120, 100%, 40%);">+      "BSIC of neighbor cell\n" "9-bit BSIC of neighbor cell\n" "BSIC value\n" \</span><br><span style="color: hsl(120, 100%, 40%);">+      "for all BSICs / use any BSIC in this ARFCN\n"</span><br><span style="color: hsl(120, 100%, 40%);">+bool neighbor_ident_vty_parse_key_params(struct vty *vty, const char **argv, struct neighbor_ident_key *key);</span><br><span>diff --git a/src/osmo-bsc/Makefile.am b/src/osmo-bsc/Makefile.am</span><br><span>index a459a92..afae0b6 100644</span><br><span>--- a/src/osmo-bsc/Makefile.am</span><br><span>+++ b/src/osmo-bsc/Makefile.am</span><br><span>@@ -64,6 +64,8 @@</span><br><span>     handover_vty.c \</span><br><span>     meas_feed.c \</span><br><span>        meas_rep.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>       net_init.c \</span><br><span>         osmo_bsc_api.c \</span><br><span>     osmo_bsc_audio.c \</span><br><span>diff --git a/src/osmo-bsc/bsc_init.c b/src/osmo-bsc/bsc_init.c</span><br><span>index b6bd410..1fe4847 100644</span><br><span>--- a/src/osmo-bsc/bsc_init.c</span><br><span>+++ b/src/osmo-bsc/bsc_init.c</span><br><span>@@ -247,6 +247,7 @@</span><br><span> </span><br><span>        net->ho = ho_cfg_init(net, NULL);</span><br><span>         net->hodec2.congestion_check_interval_s = HO_CFG_CONGESTION_CHECK_DEFAULT;</span><br><span style="color: hsl(120, 100%, 40%);">+ net->neighbor_bss_cells = neighbor_ident_init(net);</span><br><span> </span><br><span>   /* init statistics */</span><br><span>        net->bsc_ctrs = rate_ctr_group_alloc(net, &bsc_ctrg_desc, 0);</span><br><span>diff --git a/src/osmo-bsc/bsc_vty.c b/src/osmo-bsc/bsc_vty.c</span><br><span>index 57c5363..f25f731 100644</span><br><span>--- a/src/osmo-bsc/bsc_vty.c</span><br><span>+++ b/src/osmo-bsc/bsc_vty.c</span><br><span>@@ -62,6 +62,8 @@</span><br><span> #include <osmocom/bsc/gsm_04_08_utils.h></span><br><span> #include <osmocom/bsc/acc_ramp.h></span><br><span> #include <osmocom/bsc/meas_feed.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/neighbor_ident.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/handover.h></span><br><span> </span><br><span> #include <inttypes.h></span><br><span> </span><br><span>@@ -909,6 +911,8 @@</span><br><span>                  VTY_NEWLINE);</span><br><span>        }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ neighbor_ident_vty_write(vty, "  ", bts);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>        vty_out(vty, "  codec-support fr");</span><br><span>        if (bts->codec.hr)</span><br><span>                vty_out(vty, " hr");</span><br><span>@@ -4967,6 +4971,7 @@</span><br><span>       install_element(BTS_NODE, &cfg_bts_no_acc_ramping_cmd);</span><br><span>  install_element(BTS_NODE, &cfg_bts_acc_ramping_step_interval_cmd);</span><br><span>       install_element(BTS_NODE, &cfg_bts_acc_ramping_step_size_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+    neighbor_ident_vty_init(network, network->neighbor_bss_cells);</span><br><span>    /* See also handover commands added on bts level from handover_vty.c */</span><br><span> </span><br><span>  install_element(BTS_NODE, &cfg_trx_cmd);</span><br><span>diff --git a/src/osmo-bsc/gsm_data.c b/src/osmo-bsc/gsm_data.c</span><br><span>index 0f062d2..734e2fb 100644</span><br><span>--- a/src/osmo-bsc/gsm_data.c</span><br><span>+++ b/src/osmo-bsc/gsm_data.c</span><br><span>@@ -33,6 +33,7 @@</span><br><span> #include <osmocom/core/statistics.h></span><br><span> #include <osmocom/gsm/protocol/gsm_04_08.h></span><br><span> #include <osmocom/gsm/gsm48.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/gsm0808_utils.h></span><br><span> </span><br><span> #include <osmocom/bsc/gsm_data.h></span><br><span> #include <osmocom/bsc/bsc_msc_data.h></span><br><span>@@ -563,6 +564,117 @@</span><br><span>     return NULL;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+bool gsm_bts_matches_cell_id(struct gsm_bts *bts, const struct gsm0808_cell_id *ci)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!bts || !ci)</span><br><span style="color: hsl(120, 100%, 40%);">+              return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (ci->id_discr) {</span><br><span style="color: hsl(120, 100%, 40%);">+    case CELL_IDENT_WHOLE_GLOBAL:</span><br><span style="color: hsl(120, 100%, 40%);">+         if (osmo_plmn_cmp(&bts->network->plmn, &ci->id.global.lai.plmn))</span><br><span style="color: hsl(120, 100%, 40%);">+                     return false;</span><br><span style="color: hsl(120, 100%, 40%);">+         if (bts->location_area_code != ci->id.global.lai.lac)</span><br><span style="color: hsl(120, 100%, 40%);">+                   return false;</span><br><span style="color: hsl(120, 100%, 40%);">+         if (bts->cell_identity != ci->id.global.cell_identity)</span><br><span style="color: hsl(120, 100%, 40%);">+                  return false;</span><br><span style="color: hsl(120, 100%, 40%);">+         return true;</span><br><span style="color: hsl(120, 100%, 40%);">+  case CELL_IDENT_LAC_AND_CI:</span><br><span style="color: hsl(120, 100%, 40%);">+           if (bts->location_area_code != ci->id.lac_and_ci.lac)</span><br><span style="color: hsl(120, 100%, 40%);">+                   return false;</span><br><span style="color: hsl(120, 100%, 40%);">+         if (bts->cell_identity != ci->id.lac_and_ci.ci)</span><br><span style="color: hsl(120, 100%, 40%);">+                 return false;</span><br><span style="color: hsl(120, 100%, 40%);">+         return true;</span><br><span style="color: hsl(120, 100%, 40%);">+  case CELL_IDENT_CI:</span><br><span style="color: hsl(120, 100%, 40%);">+           if (bts->cell_identity != ci->id.ci)</span><br><span style="color: hsl(120, 100%, 40%);">+                    return false;</span><br><span style="color: hsl(120, 100%, 40%);">+         return true;</span><br><span style="color: hsl(120, 100%, 40%);">+  case CELL_IDENT_NO_CELL:</span><br><span style="color: hsl(120, 100%, 40%);">+              return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ case CELL_IDENT_LAI_AND_LAC:</span><br><span style="color: hsl(120, 100%, 40%);">+          if (osmo_plmn_cmp(&bts->network->plmn, &ci->id.lai_and_lac.plmn))</span><br><span style="color: hsl(120, 100%, 40%);">+                    return false;</span><br><span style="color: hsl(120, 100%, 40%);">+         if (bts->location_area_code != ci->id.lai_and_lac.lac)</span><br><span style="color: hsl(120, 100%, 40%);">+                  return false;</span><br><span style="color: hsl(120, 100%, 40%);">+         return true;</span><br><span style="color: hsl(120, 100%, 40%);">+  case CELL_IDENT_LAC:</span><br><span style="color: hsl(120, 100%, 40%);">+          if (bts->location_area_code != ci->id.lac)</span><br><span style="color: hsl(120, 100%, 40%);">+                      return false;</span><br><span style="color: hsl(120, 100%, 40%);">+         return true;</span><br><span style="color: hsl(120, 100%, 40%);">+  case CELL_IDENT_BSS:</span><br><span style="color: hsl(120, 100%, 40%);">+          return true;</span><br><span style="color: hsl(120, 100%, 40%);">+  case CELL_IDENT_UTRAN_PLMN_LAC_RNC:</span><br><span style="color: hsl(120, 100%, 40%);">+   case CELL_IDENT_UTRAN_RNC:</span><br><span style="color: hsl(120, 100%, 40%);">+    case CELL_IDENT_UTRAN_LAC_RNC:</span><br><span style="color: hsl(120, 100%, 40%);">+                /* Not implemented */</span><br><span style="color: hsl(120, 100%, 40%);">+ default:</span><br><span style="color: hsl(120, 100%, 40%);">+              return false;</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%);">+struct gsm_bts *gsm_bts_by_cell_id(struct gsm_network *net, const struct gsm0808_cell_id *ci)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gsm_bts *bts;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        llist_for_each_entry(bts, &net->bts_list, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (gsm_bts_matches_cell_id(bts, ci))</span><br><span style="color: hsl(120, 100%, 40%);">+                 return bts;</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%);">+struct gsm_bts_ref *gsm_bts_ref_find(const struct llist_head *list, const struct gsm_bts *bts)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct gsm_bts_ref *ref;</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!bts)</span><br><span style="color: hsl(120, 100%, 40%);">+             return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  llist_for_each_entry(ref, list, entry) {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (ref->bts == bts)</span><br><span style="color: hsl(120, 100%, 40%);">+                       return ref;</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%);">+/* Add a BTS reference to the local_neighbors list.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Return 1 if added, 0 if such an entry already existed, and negative on errors. */</span><br><span style="color: hsl(120, 100%, 40%);">+int gsm_bts_local_neighbor_add(struct gsm_bts *bts, struct gsm_bts *neighbor)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct gsm_bts_ref *ref;</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!bts || !neighbor)</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%);">+     if (bts == neighbor)</span><br><span style="color: hsl(120, 100%, 40%);">+          return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Already got this entry? */</span><br><span style="color: hsl(120, 100%, 40%);">+ ref = gsm_bts_ref_find(&bts->local_neighbors, neighbor);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (ref)</span><br><span style="color: hsl(120, 100%, 40%);">+              return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   ref = talloc_zero(bts, struct gsm_bts_ref);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!ref)</span><br><span style="color: hsl(120, 100%, 40%);">+             return -ENOMEM;</span><br><span style="color: hsl(120, 100%, 40%);">+       ref->bts = neighbor;</span><br><span style="color: hsl(120, 100%, 40%);">+       llist_add_tail(&ref->entry, &bts->local_neighbors);</span><br><span style="color: hsl(120, 100%, 40%);">+     return 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%);">+/* Remove a BTS reference from the local_neighbors list.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Return 1 if removed, 0 if no such entry existed, and negative on errors. */</span><br><span style="color: hsl(120, 100%, 40%);">+int gsm_bts_local_neighbor_del(struct gsm_bts *bts, const struct gsm_bts *neighbor)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gsm_bts_ref *ref;</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!bts || !neighbor)</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%);">+     ref = gsm_bts_ref_find(&bts->local_neighbors, neighbor);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!ref)</span><br><span style="color: hsl(120, 100%, 40%);">+             return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   llist_del(&ref->entry);</span><br><span style="color: hsl(120, 100%, 40%);">+        talloc_free(ref);</span><br><span style="color: hsl(120, 100%, 40%);">+     return 1;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> struct gsm_bts_trx *gsm_bts_trx_alloc(struct gsm_bts *bts)</span><br><span> {</span><br><span>    struct gsm_bts_trx *trx = talloc_zero(bts, struct gsm_bts_trx);</span><br><span>@@ -756,6 +868,7 @@</span><br><span> </span><br><span>    INIT_LLIST_HEAD(&bts->abis_queue);</span><br><span>    INIT_LLIST_HEAD(&bts->loc_list);</span><br><span style="color: hsl(120, 100%, 40%);">+       INIT_LLIST_HEAD(&bts->local_neighbors);</span><br><span> </span><br><span>   return bts;</span><br><span> }</span><br><span>diff --git a/src/osmo-bsc/handover_logic.c b/src/osmo-bsc/handover_logic.c</span><br><span>index 960bf69..55af0ed 100644</span><br><span>--- a/src/osmo-bsc/handover_logic.c</span><br><span>+++ b/src/osmo-bsc/handover_logic.c</span><br><span>@@ -392,6 +392,50 @@</span><br><span>     return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct gsm_bts *bts_by_neighbor_ident(const struct gsm_network *net,</span><br><span style="color: hsl(120, 100%, 40%);">+                                    const struct neighbor_ident_key *search_for)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gsm_bts *found = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gsm_bts *bts;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct gsm_bts *wildcard_match = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      llist_for_each_entry(bts, &net->bts_list, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+              struct neighbor_ident_key entry = {</span><br><span style="color: hsl(120, 100%, 40%);">+                   .from_bts = NEIGHBOR_IDENT_KEY_ANY_BTS,</span><br><span style="color: hsl(120, 100%, 40%);">+                       .arfcn = bts->c0->arfcn,</span><br><span style="color: hsl(120, 100%, 40%);">+                        .bsic_kind = BSIC_6BIT,</span><br><span style="color: hsl(120, 100%, 40%);">+                       .bsic = bts->bsic,</span><br><span style="color: hsl(120, 100%, 40%);">+         };</span><br><span style="color: hsl(120, 100%, 40%);">+            if (neighbor_ident_key_match(&entry, search_for, true)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 if (found) {</span><br><span style="color: hsl(120, 100%, 40%);">+                          LOGP(DHO, LOGL_ERROR, "CONFIG ERROR: Multiple BTS match %s: %d and %d\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                neighbor_ident_key_name(search_for),</span><br><span style="color: hsl(120, 100%, 40%);">+                                  found->nr, bts->nr);</span><br><span style="color: hsl(120, 100%, 40%);">+                               return found;</span><br><span style="color: hsl(120, 100%, 40%);">+                 }</span><br><span style="color: hsl(120, 100%, 40%);">+                     found = bts;</span><br><span style="color: hsl(120, 100%, 40%);">+          }</span><br><span style="color: hsl(120, 100%, 40%);">+             if (neighbor_ident_key_match(&entry, search_for, false))</span><br><span style="color: hsl(120, 100%, 40%);">+                  wildcard_match = bts;</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%);">+            return found;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       return wildcard_match;</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_key *bts_ident_key(const struct gsm_bts *bts)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   static struct neighbor_ident_key key;</span><br><span style="color: hsl(120, 100%, 40%);">+ key = (struct neighbor_ident_key){</span><br><span style="color: hsl(120, 100%, 40%);">+            .arfcn = bts->c0->arfcn,</span><br><span style="color: hsl(120, 100%, 40%);">+                .bsic_kind = BSIC_6BIT,</span><br><span style="color: hsl(120, 100%, 40%);">+               .bsic = bts->bsic,</span><br><span style="color: hsl(120, 100%, 40%);">+ };</span><br><span style="color: hsl(120, 100%, 40%);">+    return &key;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static int ho_logic_sig_cb(unsigned int subsys, unsigned int signal,</span><br><span>                           void *handler_data, void *signal_data)</span><br><span> {</span><br><span>diff --git a/src/osmo-bsc/neighbor_ident.c b/src/osmo-bsc/neighbor_ident.c</span><br><span>new file mode 100644</span><br><span>index 0000000..8a7c580</span><br><span>--- /dev/null</span><br><span>+++ b/src/osmo-bsc/neighbor_ident.c</span><br><span>@@ -0,0 +1,296 @@</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%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Measurement reports tell us about neighbor ARFCN and BSIC. If that ARFCN and BSIC is not managed by</span><br><span style="color: hsl(120, 100%, 40%);">+ * this local BSS, we need to tell the MSC a cell identity, like CGI, LAC+CI, etc. -- hence we need a</span><br><span style="color: hsl(120, 100%, 40%);">+ * mapping from ARFCN+BSIC to Cell Identifier List, which needs to be configured by the user.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</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%);">+ *</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/neighbor_ident.h></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%);">+    struct neighbor_ident_key key;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct gsm0808_cell_id_list2 val;</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%);">+#define APPEND_THING(func, args...) do { \</span><br><span style="color: hsl(120, 100%, 40%);">+           int remain = buflen - (pos - buf); \</span><br><span style="color: hsl(120, 100%, 40%);">+          int l = func(pos, remain, ##args); \</span><br><span style="color: hsl(120, 100%, 40%);">+          if (l < 0 || l > remain) \</span><br><span style="color: hsl(120, 100%, 40%);">+                      pos = buf + buflen; \</span><br><span style="color: hsl(120, 100%, 40%);">+         else \</span><br><span style="color: hsl(120, 100%, 40%);">+                        pos += l; \</span><br><span style="color: hsl(120, 100%, 40%);">+   } while(0)</span><br><span style="color: hsl(120, 100%, 40%);">+#define APPEND_STR(fmt, args...) APPEND_THING(snprintf, fmt, ##args)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+const char *_neighbor_ident_key_name(char *buf, size_t buflen, const struct neighbor_ident_key *ni_key)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        char *pos = buf;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    APPEND_STR("BTS ");</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ni_key->from_bts == NEIGHBOR_IDENT_KEY_ANY_BTS)</span><br><span style="color: hsl(120, 100%, 40%);">+                APPEND_STR("*");</span><br><span style="color: hsl(120, 100%, 40%);">+    else if (ni_key->from_bts >= 0 && ni_key->from_bts <= 255)</span><br><span style="color: hsl(120, 100%, 40%);">+                APPEND_STR("%d", ni_key->from_bts);</span><br><span style="color: hsl(120, 100%, 40%);">+      else</span><br><span style="color: hsl(120, 100%, 40%);">+          APPEND_STR("invalid(%d)", ni_key->from_bts);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   APPEND_STR(" to ");</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (ni_key->bsic_kind) {</span><br><span style="color: hsl(120, 100%, 40%);">+       default:</span><br><span style="color: hsl(120, 100%, 40%);">+      case BSIC_NONE:</span><br><span style="color: hsl(120, 100%, 40%);">+               APPEND_STR("ARFCN %u (any BSIC)", ni_key->arfcn);</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case BSIC_6BIT:</span><br><span style="color: hsl(120, 100%, 40%);">+               APPEND_STR("ARFCN %u BSIC %u", ni_key->arfcn, ni_key->bsic & 0x3f);</span><br><span style="color: hsl(120, 100%, 40%);">+               break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case BSIC_9BIT:</span><br><span style="color: hsl(120, 100%, 40%);">+               APPEND_STR("ARFCN %u BSIC %u(9bit)", ni_key->arfcn, ni_key->bsic & 0x1ff);</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%);">+     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%);">+const char *neighbor_ident_key_name(const struct neighbor_ident_key *ni_key)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     static char buf[64];</span><br><span style="color: hsl(120, 100%, 40%);">+  return _neighbor_ident_key_name(buf, sizeof(buf), ni_key);</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%);">+/* Return true when the entry matches the search_for requirements.</span><br><span style="color: hsl(120, 100%, 40%);">+ * If exact_match is false, a BSIC_NONE entry acts as wildcard to match any search_for on that ARFCN,</span><br><span style="color: hsl(120, 100%, 40%);">+ * and a BSIC_NONE in search_for likewise returns any one entry that matches the ARFCN;</span><br><span style="color: hsl(120, 100%, 40%);">+ * also a from_bts == NEIGHBOR_IDENT_KEY_ANY_BTS in either entry or search_for will match.</span><br><span style="color: hsl(120, 100%, 40%);">+ * If exact_match is true, only identical bsic_kind values and identical from_bts values return a match.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Note, typically wildcard BSICs are only in entry, e.g. the user configured list, and search_for</span><br><span style="color: hsl(120, 100%, 40%);">+ * contains a specific BSIC, e.g. as received from a Measurement Report. */</span><br><span style="color: hsl(120, 100%, 40%);">+bool neighbor_ident_key_match(const struct neighbor_ident_key *entry,</span><br><span style="color: hsl(120, 100%, 40%);">+                            const struct neighbor_ident_key *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%);">+    uint16_t bsic_mask;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (exact_match</span><br><span style="color: hsl(120, 100%, 40%);">+           && entry->from_bts != search_for->from_bts)</span><br><span style="color: hsl(120, 100%, 40%);">+         return false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (search_for->from_bts != NEIGHBOR_IDENT_KEY_ANY_BTS</span><br><span style="color: hsl(120, 100%, 40%);">+         && entry->from_bts != NEIGHBOR_IDENT_KEY_ANY_BTS</span><br><span style="color: hsl(120, 100%, 40%);">+           && entry->from_bts != search_for->from_bts)</span><br><span style="color: hsl(120, 100%, 40%);">+         return false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (entry->arfcn != search_for->arfcn)</span><br><span style="color: hsl(120, 100%, 40%);">+          return false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       switch (entry->bsic_kind) {</span><br><span style="color: hsl(120, 100%, 40%);">+        default:</span><br><span style="color: hsl(120, 100%, 40%);">+              return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ case BSIC_NONE:</span><br><span style="color: hsl(120, 100%, 40%);">+               if (!exact_match) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   /* The neighbor identifier list entry matches any BSIC for this ARFCN. */</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%);">+             /* Match exact entry */</span><br><span style="color: hsl(120, 100%, 40%);">+               bsic_mask = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+                break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case BSIC_6BIT:</span><br><span style="color: hsl(120, 100%, 40%);">+               bsic_mask = 0x3f;</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case BSIC_9BIT:</span><br><span style="color: hsl(120, 100%, 40%);">+               bsic_mask = 0x1ff;</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%);">+     if (!exact_match && search_for->bsic_kind == BSIC_NONE) {</span><br><span style="color: hsl(120, 100%, 40%);">+          /* The search is looking only for an ARFCN with any BSIC */</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%);">+     if (search_for->bsic_kind == entry->bsic_kind</span><br><span style="color: hsl(120, 100%, 40%);">+       && (search_for->bsic & bsic_mask) == (entry->bsic & bsic_mask))</span><br><span style="color: hsl(120, 100%, 40%);">+             return true;</span><br><span style="color: hsl(120, 100%, 40%);">+  return false;</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_key *key,</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%);">+        struct neighbor_ident *ni;</span><br><span style="color: hsl(120, 100%, 40%);">+    struct neighbor_ident *wildcard_match = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* Do both exact-bsic and wildcard matching in the same iteration:</span><br><span style="color: hsl(120, 100%, 40%);">+     * Any exact match returns immediately, while for a wildcard match we still go through all</span><br><span style="color: hsl(120, 100%, 40%);">+     * remaining items in case an exact match exists. */</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 (neighbor_ident_key_match(&ni->key, key, true))</span><br><span style="color: hsl(120, 100%, 40%);">+                     return ni;</span><br><span style="color: hsl(120, 100%, 40%);">+            if (!exact_match) {</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (neighbor_ident_key_match(&ni->key, key, false))</span><br><span style="color: hsl(120, 100%, 40%);">+                            wildcard_match = 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%);">+     return wildcard_match;</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%);">+bool neighbor_ident_key_valid(const struct neighbor_ident_key *key)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ if (key->from_bts != NEIGHBOR_IDENT_KEY_ANY_BTS</span><br><span style="color: hsl(120, 100%, 40%);">+        && (key->from_bts < 0 || key->from_bts > 255))</span><br><span style="color: hsl(120, 100%, 40%);">+                return false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       switch (key->bsic_kind) {</span><br><span style="color: hsl(120, 100%, 40%);">+  case BSIC_6BIT:</span><br><span style="color: hsl(120, 100%, 40%);">+               if (key->bsic > 0x3f)</span><br><span style="color: hsl(120, 100%, 40%);">+                   return false;</span><br><span style="color: hsl(120, 100%, 40%);">+         break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case BSIC_9BIT:</span><br><span style="color: hsl(120, 100%, 40%);">+               if (key->bsic > 0x1ff)</span><br><span style="color: hsl(120, 100%, 40%);">+                  return false;</span><br><span style="color: hsl(120, 100%, 40%);">+         break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case BSIC_NONE:</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 false;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</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%);">+/*! Add Cell Identifiers to an ARFCN+BSIC entry.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Exactly one kind of identifier is allowed per ARFCN+BSIC 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, key).</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_key *key,</span><br><span style="color: hsl(120, 100%, 40%);">+                       const struct gsm0808_cell_id_list2 *val)</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%);">+     if (!neighbor_ident_key_valid(key))</span><br><span style="color: hsl(120, 100%, 40%);">+           return -ERANGE;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     ni = _neighbor_ident_get(nil, key, true);</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 = (struct neighbor_ident){</span><br><span style="color: hsl(120, 100%, 40%);">+                        .key = *key,</span><br><span style="color: hsl(120, 100%, 40%);">+                  .val = *val,</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%);">+         return ni->val.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%);">+   rc = gsm0808_cell_id_list_add(&ni->val, val);</span><br><span style="color: hsl(120, 100%, 40%);">+</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->val.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 BTS, ARFCN and BSIC, 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_key *key)</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, key, false);</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->val;</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_key *key)</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, key, true);</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_key *key,</span><br><span style="color: hsl(120, 100%, 40%);">+                                         const struct gsm0808_cell_id_list2 *val,</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->key, &ni->val, 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/osmo-bsc/neighbor_ident_vty.c b/src/osmo-bsc/neighbor_ident_vty.c</span><br><span>new file mode 100644</span><br><span>index 0000000..5b659fd</span><br><span>--- /dev/null</span><br><span>+++ b/src/osmo-bsc/neighbor_ident_vty.c</span><br><span>@@ -0,0 +1,561 @@</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%);">+ *</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/vty.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/neighbor_ident.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/gsm_data.h></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%);">+static struct neighbor_ident_list *g_neighbor_cells = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Parse VTY parameters matching NEIGHBOR_IDENT_VTY_KEY_PARAMS. Pass a pointer so that argv[0] is the</span><br><span style="color: hsl(120, 100%, 40%);">+ * ARFCN value followed by the BSIC keyword and value. vty *must* reference a BTS_NODE. */</span><br><span style="color: hsl(120, 100%, 40%);">+bool neighbor_ident_vty_parse_key_params(struct vty *vty, const char **argv, struct neighbor_ident_key *key)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gsm_bts *bts = vty->index;</span><br><span style="color: hsl(120, 100%, 40%);">+  const char *arfcn_str = argv[0];</span><br><span style="color: hsl(120, 100%, 40%);">+      const char *bsic_kind = argv[1];</span><br><span style="color: hsl(120, 100%, 40%);">+      const char *bsic_str = argv[2];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(vty->node == BTS_NODE && bts);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       *key = (struct neighbor_ident_key){</span><br><span style="color: hsl(120, 100%, 40%);">+           .from_bts = bts->nr,</span><br><span style="color: hsl(120, 100%, 40%);">+               .arfcn = atoi(arfcn_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%);">+  if (!strcmp(bsic_str, "any"))</span><br><span style="color: hsl(120, 100%, 40%);">+               key->bsic_kind = BSIC_NONE;</span><br><span style="color: hsl(120, 100%, 40%);">+        else {</span><br><span style="color: hsl(120, 100%, 40%);">+                key->bsic_kind = (!strcmp(bsic_kind, "bsic9")) ? BSIC_9BIT : BSIC_6BIT;</span><br><span style="color: hsl(120, 100%, 40%);">+          key->bsic = atoi(bsic_str);</span><br><span style="color: hsl(120, 100%, 40%);">+                if (key->bsic_kind == BSIC_6BIT && key->bsic > 0x3f) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       vty_out(vty, "%% Error: BSIC value surpasses 6-bit range: %u, use 'bsic9' instead%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                               key->bsic, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+                   return false;</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 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%);">+#define NEIGHBOR_ADD_CMD "neighbor add "</span><br><span style="color: hsl(120, 100%, 40%);">+#define NEIGHBOR_DEL_CMD "neighbor del "</span><br><span style="color: hsl(120, 100%, 40%);">+#define NEIGHBOR_DOC "Neighbor cell list\n"</span><br><span style="color: hsl(120, 100%, 40%);">+#define NEIGHBOR_ADD_DOC NEIGHBOR_DOC "Add local or remote-BSS neighbor cell\n"</span><br><span style="color: hsl(120, 100%, 40%);">+#define NEIGHBOR_DEL_DOC NEIGHBOR_DOC "Remove local or remote-BSS neighbor cell\n"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct gsm_bts *neighbor_ident_vty_parse_bts_nr(struct vty *vty, const char **argv)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    const char *bts_nr_str = argv[0];</span><br><span style="color: hsl(120, 100%, 40%);">+     struct gsm_bts *bts = gsm_bts_num(g_net, atoi(bts_nr_str));</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!bts)</span><br><span style="color: hsl(120, 100%, 40%);">+             vty_out(vty, "%% No such BTS: nr = %s%s\n", bts_nr_str, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+       return bts;</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 gsm_bts *bts_by_cell_id(struct vty *vty, 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 gsm_bts *bts = gsm_bts_by_cell_id(g_net, cell_id);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!bts)</span><br><span style="color: hsl(120, 100%, 40%);">+             vty_out(vty, "%% No such BTS: %s%s\n", gsm0808_cell_id_name(cell_id), VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+ return bts;</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(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_local_bts(struct vty *vty, struct gsm_bts *neigh)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct gsm_bts *bts = vty->index;</span><br><span style="color: hsl(120, 100%, 40%);">+  if (vty->node != BTS_NODE) {</span><br><span style="color: hsl(120, 100%, 40%);">+               vty_out(vty, "%% Error: cannot add local BTS neighbor, not on BTS node%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                  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%);">+     if (!bts) {</span><br><span style="color: hsl(120, 100%, 40%);">+           vty_out(vty, "%% Error: cannot add local BTS neighbor, no BTS on this node%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                      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%);">+     if (!neigh) {</span><br><span style="color: hsl(120, 100%, 40%);">+         vty_out(vty, "%% Error: cannot add local BTS neighbor to BTS %u, no such neighbor BTS%s"</span><br><span style="color: hsl(120, 100%, 40%);">+                    "%% (To add remote-BSS neighbors, pass full ARFCN and BSIC as well)%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                     bts->nr, VTY_NEWLINE, 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%);">+     rc = gsm_bts_local_neighbor_add(bts, neigh);</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 local BTS %u as neighbor to BTS %u: %s%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                       neigh->nr, bts->nr, 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%);">+   } else</span><br><span style="color: hsl(120, 100%, 40%);">+                vty_out(vty, "%% BTS %u %s local neighbor BTS %u with LAC %u CI %u and ARFCN %u BSIC %u%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                 bts->nr, rc? "now has" : "already had",</span><br><span style="color: hsl(120, 100%, 40%);">+                        neigh->nr, neigh->location_area_code, neigh->cell_identity,</span><br><span style="color: hsl(120, 100%, 40%);">+                  neigh->c0->arfcn, neigh->bsic, VTY_NEWLINE);</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 del_local_bts(struct vty *vty, struct gsm_bts *neigh)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct gsm_bts *bts = vty->index;</span><br><span style="color: hsl(120, 100%, 40%);">+  if (vty->node != BTS_NODE) {</span><br><span style="color: hsl(120, 100%, 40%);">+               vty_out(vty, "%% Error: cannot remove local BTS neighbor, not on BTS node%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                       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%);">+     if (!bts) {</span><br><span style="color: hsl(120, 100%, 40%);">+           vty_out(vty, "%% Error: cannot remove local BTS neighbor, no BTS on this node%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                   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%);">+     if (!neigh) {</span><br><span style="color: hsl(120, 100%, 40%);">+         vty_out(vty, "%% Error: cannot remove local BTS neighbor from BTS %u, no such neighbor BTS%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                      bts->nr, 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%);">+     rc = gsm_bts_local_neighbor_del(bts, neigh);</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 remove local BTS %u neighbor from BTS %u: %s%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                     neigh->nr, bts->nr, 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%);">+     if (rc == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+          vty_out(vty, "%% BTS %u is no neighbor of BTS %u%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                        neigh->nr, bts->nr, VTY_NEWLINE);</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_neighbor_add_bts_nr, cfg_neighbor_add_bts_nr_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+ NEIGHBOR_ADD_CMD "bts <0-255>",</span><br><span style="color: hsl(120, 100%, 40%);">+       NEIGHBOR_ADD_DOC "Neighbor cell by local BTS number\n" "BTS number\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ return add_local_bts(vty, neighbor_ident_vty_parse_bts_nr(vty, argv));</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, cfg_neighbor_add_lac_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+    NEIGHBOR_ADD_CMD "lac <0-65535>",</span><br><span style="color: hsl(120, 100%, 40%);">+     NEIGHBOR_ADD_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%);">+     return add_local_bts(vty, bts_by_cell_id(vty, neighbor_ident_vty_parse_lac(vty, argv)));</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, cfg_neighbor_add_lac_ci_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+    NEIGHBOR_ADD_CMD "lac-ci <0-65535> <0-255>",</span><br><span style="color: hsl(120, 100%, 40%);">+    NEIGHBOR_ADD_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%);">+     return add_local_bts(vty, bts_by_cell_id(vty, neighbor_ident_vty_parse_lac_ci(vty, argv)));</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_key_matches_bts(const struct neighbor_ident_key *key, struct gsm_bts *bts)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!bts || !key)</span><br><span style="color: hsl(120, 100%, 40%);">+             return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ return key->arfcn == bts->c0->arfcn</span><br><span style="color: hsl(120, 100%, 40%);">+          && (key->bsic_kind == BSIC_NONE || key->bsic == bts->bsic);</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_remote_or_local_bts(struct vty *vty, const struct gsm0808_cell_id *cell_id,</span><br><span style="color: hsl(120, 100%, 40%);">+                            const struct neighbor_ident_key *key)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct gsm_bts *local_neigh;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct gsm0808_cell_id_list2 cil;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct gsm_bts *bts = vty->index;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        if (vty->node != BTS_NODE) {</span><br><span style="color: hsl(120, 100%, 40%);">+               vty_out(vty, "%% Error: cannot add BTS neighbor, not on BTS node%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                        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%);">+     if (!bts) {</span><br><span style="color: hsl(120, 100%, 40%);">+           vty_out(vty, "%% Error: cannot add BTS neighbor, no BTS on this node%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                    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%);">+   /* Is there a local BTS that matches the cell_id? */</span><br><span style="color: hsl(120, 100%, 40%);">+  local_neigh = gsm_bts_by_cell_id(g_net, cell_id);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (local_neigh) {</span><br><span style="color: hsl(120, 100%, 40%);">+            /* But do the advertised ARFCN and BSIC match as intended?</span><br><span style="color: hsl(120, 100%, 40%);">+             * The user may omit ARFCN and BSIC for local cells, but if they are provided,</span><br><span style="color: hsl(120, 100%, 40%);">+                 * they need to match. */</span><br><span style="color: hsl(120, 100%, 40%);">+             if (!neighbor_ident_key_matches_bts(key, local_neigh)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      vty_out(vty, "%% Error: bts %u: neighbor cell id %s indicates local BTS %u,"</span><br><span style="color: hsl(120, 100%, 40%);">+                                " but it does not match ARFCN+BSIC %s%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                           bts->nr, gsm0808_cell_id_name(cell_id), local_neigh->nr,</span><br><span style="color: hsl(120, 100%, 40%);">+                                neighbor_ident_key_name(key), VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+                   /* TODO: error out fatally for non-interactive VTY? */</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 add_local_bts(vty, local_neigh);</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%);">+   /* The cell_id is not known in this BSS, so it must be a remote cell. */</span><br><span style="color: hsl(120, 100%, 40%);">+      gsm0808_cell_id_to_list(&cil, cell_id);</span><br><span style="color: hsl(120, 100%, 40%);">+   rc = neighbor_ident_add(g_neighbor_cells, key, &cil);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              const char *reason;</span><br><span style="color: hsl(120, 100%, 40%);">+           switch (rc) {</span><br><span style="color: hsl(120, 100%, 40%);">+         case -EINVAL:</span><br><span style="color: hsl(120, 100%, 40%);">+                 reason = ": mismatching type between current and newly added cell identifier";</span><br><span style="color: hsl(120, 100%, 40%);">+                      break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case -ENOSPC:</span><br><span style="color: hsl(120, 100%, 40%);">+                 reason = ": list is full";</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%);">+                      reason = "";</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%);">+           vty_out(vty, "%% Error adding neighbor-BSS Cell Identifier %s%s%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                 gsm0808_cell_id_name(cell_id), reason, 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%);">+   vty_out(vty, "%% %s now has %d remote BSS Cell Identifier List %s%s",</span><br><span style="color: hsl(120, 100%, 40%);">+               neighbor_ident_key_name(key), rc, rc == 1? "entry" : "entries", VTY_NEWLINE);</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 del_by_key(struct vty *vty, const struct neighbor_ident_key *key)</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%);">+      int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct gsm_bts *bts = vty->index;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct gsm_bts_ref *neigh, *safe;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (vty->node != BTS_NODE) {</span><br><span style="color: hsl(120, 100%, 40%);">+               vty_out(vty, "%% Error: cannot remove BTS neighbor, not on BTS node%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                     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%);">+     if (!bts) {</span><br><span style="color: hsl(120, 100%, 40%);">+           vty_out(vty, "%% Error: cannot remove BTS neighbor, no BTS on this node%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                 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%);">+   /* Is there a local BTS that matches the key? */</span><br><span style="color: hsl(120, 100%, 40%);">+      llist_for_each_entry_safe(neigh, safe, &bts->local_neighbors, entry) {</span><br><span style="color: hsl(120, 100%, 40%);">+         struct gsm_bts *neigh_bts = neigh->bts;</span><br><span style="color: hsl(120, 100%, 40%);">+            if (!neighbor_ident_key_matches_bts(key, neigh->bts))</span><br><span style="color: hsl(120, 100%, 40%);">+                      continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             rc = gsm_bts_local_neighbor_del(bts, neigh->bts);</span><br><span style="color: hsl(120, 100%, 40%);">+          if (rc > 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      vty_out(vty, "%% Removed local neighbor bts %u to bts %u%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                                bts->nr, neigh_bts->nr, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+                   removed += rc;</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 (neighbor_ident_del(g_neighbor_cells, key)) {</span><br><span style="color: hsl(120, 100%, 40%);">+              vty_out(vty, "%% Removed remote BSS neighbor %s%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                 neighbor_ident_key_name(key), VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+           removed ++;</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_key_name(key), 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%);">+DEFUN(cfg_neighbor_add_lac_arfcn_bsic, cfg_neighbor_add_lac_arfcn_bsic_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+ NEIGHBOR_ADD_CMD "lac <0-65535> " NEIGHBOR_IDENT_VTY_KEY_PARAMS,</span><br><span style="color: hsl(120, 100%, 40%);">+      NEIGHBOR_ADD_DOC "Neighbor cell by lac\n" "lac\n" NEIGHBOR_IDENT_VTY_KEY_DOC)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct neighbor_ident_key nik;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct gsm0808_cell_id *cell_id = neighbor_ident_vty_parse_lac(vty, argv);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!cell_id)</span><br><span style="color: hsl(120, 100%, 40%);">+         return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!neighbor_ident_vty_parse_key_params(vty, argv + 1, &nik))</span><br><span style="color: hsl(120, 100%, 40%);">+            return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   return add_remote_or_local_bts(vty, cell_id, &nik);</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_arfcn_bsic, cfg_neighbor_add_lac_ci_arfcn_bsic_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+       NEIGHBOR_ADD_CMD "lac-ci <0-65535> <0-255> " NEIGHBOR_IDENT_VTY_KEY_PARAMS,</span><br><span style="color: hsl(120, 100%, 40%);">+     NEIGHBOR_ADD_DOC "Neighbor cell by LAC and CI\n" "LAC\n" "CI\n" NEIGHBOR_IDENT_VTY_KEY_DOC)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  struct neighbor_ident_key nik;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct gsm0808_cell_id *cell_id = neighbor_ident_vty_parse_lac_ci(vty, argv);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!cell_id)</span><br><span style="color: hsl(120, 100%, 40%);">+         return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!neighbor_ident_vty_parse_key_params(vty, argv + 2, &nik))</span><br><span style="color: hsl(120, 100%, 40%);">+            return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   return add_remote_or_local_bts(vty, cell_id, &nik);</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_arfcn_bsic, cfg_neighbor_add_cgi_arfcn_bsic_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+     NEIGHBOR_ADD_CMD "cgi <0-999> <0-999> <0-65535> <0-255> " NEIGHBOR_IDENT_VTY_KEY_PARAMS,</span><br><span style="color: hsl(120, 100%, 40%);">+    NEIGHBOR_ADD_DOC "Neighbor cell by cgi\n" "MCC\n" "MNC\n" "LAC\n" "CI\n" NEIGHBOR_IDENT_VTY_KEY_DOC)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct neighbor_ident_key nik;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct gsm0808_cell_id *cell_id = neighbor_ident_vty_parse_cgi(vty, argv);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!cell_id)</span><br><span style="color: hsl(120, 100%, 40%);">+         return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!neighbor_ident_vty_parse_key_params(vty, argv + 4, &nik))</span><br><span style="color: hsl(120, 100%, 40%);">+            return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   return add_remote_or_local_bts(vty, cell_id, &nik);</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_del_bts_nr, cfg_neighbor_del_bts_nr_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+     NEIGHBOR_DEL_CMD "bts <0-255>",</span><br><span style="color: hsl(120, 100%, 40%);">+       NEIGHBOR_DEL_DOC "Neighbor cell by local BTS number\n" "BTS number\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ return del_local_bts(vty, neighbor_ident_vty_parse_bts_nr(vty, argv));</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_del_arfcn_bsic, cfg_neighbor_del_arfcn_bsic_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      NEIGHBOR_DEL_CMD NEIGHBOR_IDENT_VTY_KEY_PARAMS,</span><br><span style="color: hsl(120, 100%, 40%);">+       NEIGHBOR_DEL_DOC NEIGHBOR_IDENT_VTY_KEY_DOC)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct neighbor_ident_key key;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!neighbor_ident_vty_parse_key_params(vty, argv, &key))</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 del_by_key(vty, &key);</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 write_neighbor_ident_entry_data {</span><br><span style="color: hsl(120, 100%, 40%);">+      struct vty *vty;</span><br><span style="color: hsl(120, 100%, 40%);">+      const char *indent;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct gsm_bts *bts;</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 bool write_neighbor_ident_list(const struct neighbor_ident_key *key,</span><br><span style="color: hsl(120, 100%, 40%);">+                                     const struct gsm0808_cell_id_list2 *val,</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 write_neighbor_ident_entry_data *d = cb_data;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct vty *vty = d->vty;</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%);">+      if (d->bts) {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (d->bts->nr != key->from_bts)</span><br><span style="color: hsl(120, 100%, 40%);">+                     return true;</span><br><span style="color: hsl(120, 100%, 40%);">+  } else if (key->from_bts != NEIGHBOR_IDENT_KEY_ANY_BTS)</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%);">+#define NEIGH_BSS_WRITE(fmt, args...) do { \</span><br><span style="color: hsl(120, 100%, 40%);">+          vty_out(vty, "%sneighbor add " fmt " arfcn %u ", d->indent, ## args, key->arfcn); \</span><br><span style="color: hsl(120, 100%, 40%);">+         switch (key->bsic_kind) { \</span><br><span style="color: hsl(120, 100%, 40%);">+                default: \</span><br><span style="color: hsl(120, 100%, 40%);">+            case BSIC_NONE: \</span><br><span style="color: hsl(120, 100%, 40%);">+                     vty_out(vty, "bsic any"); \</span><br><span style="color: hsl(120, 100%, 40%);">+                 break; \</span><br><span style="color: hsl(120, 100%, 40%);">+              case BSIC_6BIT: \</span><br><span style="color: hsl(120, 100%, 40%);">+                     vty_out(vty, "bsic %u", key->bsic & 0x3f); \</span><br><span style="color: hsl(120, 100%, 40%);">+                 break; \</span><br><span style="color: hsl(120, 100%, 40%);">+              case BSIC_9BIT: \</span><br><span style="color: hsl(120, 100%, 40%);">+                     vty_out(vty, "bsic9 %u", key->bsic & 0x1ff); \</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%);">+           vty_out(vty, "%s", VTY_NEWLINE); \</span><br><span style="color: hsl(120, 100%, 40%);">+  } while(0)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  switch (val->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 < val->id_list_len; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        NEIGH_BSS_WRITE("lac %u", val->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 < val->id_list_len; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        NEIGH_BSS_WRITE("lac-ci %u %u",</span><br><span style="color: hsl(120, 100%, 40%);">+                                     val->id_list[i].lac_and_ci.lac,</span><br><span style="color: hsl(120, 100%, 40%);">+                                    val->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 < val->id_list_len; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        const struct osmo_cell_global_id *cgi = &val->id_list[i].global;</span><br><span style="color: hsl(120, 100%, 40%);">+                       NEIGH_BSS_WRITE("cgi %s %s %u %u",</span><br><span style="color: hsl(120, 100%, 40%);">+                                  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%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+#undef NEIGH_BSS_WRITE</span><br><span style="color: hsl(120, 100%, 40%);">+</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_vty_write_remote_bss(struct vty *vty, const char *indent, struct gsm_bts *bts)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct write_neighbor_ident_entry_data d = {</span><br><span style="color: hsl(120, 100%, 40%);">+          .vty = vty,</span><br><span style="color: hsl(120, 100%, 40%);">+           .indent = indent,</span><br><span style="color: hsl(120, 100%, 40%);">+             .bts = bts,</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%);">+  neighbor_ident_iter(g_neighbor_cells, write_neighbor_ident_list, &d);</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_local_neighbors(struct vty *vty, const char *indent, struct gsm_bts *bts)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct gsm_bts_ref *neigh;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  llist_for_each_entry(neigh, &bts->local_neighbors, entry) {</span><br><span style="color: hsl(120, 100%, 40%);">+            vty_out(vty, "%sneighbor add lac-ci %u %u%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                       indent, neigh->bts->location_area_code, neigh->bts->cell_identity,</span><br><span style="color: hsl(120, 100%, 40%);">+                        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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void neighbor_ident_vty_write(struct vty *vty, const char *indent, struct gsm_bts *bts)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    neighbor_ident_vty_write_local_neighbors(vty, indent, bts);</span><br><span style="color: hsl(120, 100%, 40%);">+   neighbor_ident_vty_write_remote_bss(vty, indent, bts);</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_resolve, cfg_neighbor_resolve_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      "neighbor resolve " NEIGHBOR_IDENT_VTY_KEY_PARAMS,</span><br><span style="color: hsl(120, 100%, 40%);">+      NEIGHBOR_DOC</span><br><span style="color: hsl(120, 100%, 40%);">+      "Query which cell would be the target for this neighbor ARFCN+BSIC\n"</span><br><span style="color: hsl(120, 100%, 40%);">+      NEIGHBOR_IDENT_VTY_KEY_DOC)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       int found = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct neighbor_ident_key key;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct gsm_bts_ref *neigh;</span><br><span style="color: hsl(120, 100%, 40%);">+    const struct gsm0808_cell_id_list2 *res;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gsm_bts *bts = vty->index;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct write_neighbor_ident_entry_data d = {</span><br><span style="color: hsl(120, 100%, 40%);">+          .vty = vty,</span><br><span style="color: hsl(120, 100%, 40%);">+           .indent = "% ",</span><br><span style="color: hsl(120, 100%, 40%);">+             .bts = bts,</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 (vty->node != BTS_NODE) {</span><br><span style="color: hsl(120, 100%, 40%);">+               vty_out(vty, "%% Error: cannot query BTS neighbor, not on BTS node%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                      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%);">+     if (!bts) {</span><br><span style="color: hsl(120, 100%, 40%);">+           vty_out(vty, "%% Error: cannot query BTS neighbor, no BTS on this node%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                  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_vty_parse_key_params(vty, argv, &key))</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%);">+ /* Is there a local BTS that matches the key? */</span><br><span style="color: hsl(120, 100%, 40%);">+      llist_for_each_entry(neigh, &bts->local_neighbors, entry) {</span><br><span style="color: hsl(120, 100%, 40%);">+            if (!neighbor_ident_key_matches_bts(&key, neigh->bts))</span><br><span style="color: hsl(120, 100%, 40%);">+                 continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             vty_out(vty, "%% %s resolves to local BTS %u lac-ci %u %u%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                       neighbor_ident_key_name(&key), neigh->bts->nr, neigh->bts->location_area_code,</span><br><span style="color: hsl(120, 100%, 40%);">+                        neigh->bts->cell_identity, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+                found++;</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%);">+   res = neighbor_ident_get(g_neighbor_cells, &key);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (res) {</span><br><span style="color: hsl(120, 100%, 40%);">+            write_neighbor_ident_list(&key, res, &d);</span><br><span style="color: hsl(120, 100%, 40%);">+             found++;</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", neighbor_ident_key_name(&key), 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, struct neighbor_ident_list *nil)</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_neighbor_cells = nil;</span><br><span style="color: hsl(120, 100%, 40%);">+       install_element(BTS_NODE, &cfg_neighbor_add_bts_nr_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+  install_element(BTS_NODE, &cfg_neighbor_add_lac_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+     install_element(BTS_NODE, &cfg_neighbor_add_lac_ci_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+  install_element(BTS_NODE, &cfg_neighbor_add_lac_arfcn_bsic_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+  install_element(BTS_NODE, &cfg_neighbor_add_lac_ci_arfcn_bsic_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+       install_element(BTS_NODE, &cfg_neighbor_add_cgi_arfcn_bsic_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+  install_element(BTS_NODE, &cfg_neighbor_del_bts_nr_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+  install_element(BTS_NODE, &cfg_neighbor_del_arfcn_bsic_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+      install_element(BTS_NODE, &cfg_neighbor_resolve_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/osmo-bsc/net_init.c b/src/osmo-bsc/net_init.c</span><br><span>index 3ee35fe..db3d01c 100644</span><br><span>--- a/src/osmo-bsc/net_init.c</span><br><span>+++ b/src/osmo-bsc/net_init.c</span><br><span>@@ -22,6 +22,7 @@</span><br><span> #include <osmocom/bsc/gsm_04_08_utils.h></span><br><span> #include <osmocom/bsc/handover_cfg.h></span><br><span> #include <osmocom/bsc/chan_alloc.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/neighbor_ident.h></span><br><span> </span><br><span> /* Initialize the bare minimum of struct gsm_network, minimizing required dependencies.</span><br><span>  * This part is shared among the thin programs in osmo-bsc/src/utils/.</span><br><span>diff --git a/src/osmo-bsc/system_information.c b/src/osmo-bsc/system_information.c</span><br><span>index d99153f..071baba 100644</span><br><span>--- a/src/osmo-bsc/system_information.c</span><br><span>+++ b/src/osmo-bsc/system_information.c</span><br><span>@@ -40,6 +40,9 @@</span><br><span> #include <osmocom/bsc/arfcn_range_encode.h></span><br><span> #include <osmocom/bsc/gsm_04_08_utils.h></span><br><span> #include <osmocom/bsc/acc_ramp.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/neighbor_ident.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct gsm0808_cell_id_list2;</span><br><span> </span><br><span> /*</span><br><span>  * DCS1800 and PCS1900 have overlapping ARFCNs. We would need to set the</span><br><span>@@ -588,6 +591,25 @@</span><br><span>  return bitvec2freq_list(chan_list, bv, bts, false, false);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct generate_bcch_chan_list__ni_iter_data {</span><br><span style="color: hsl(120, 100%, 40%);">+   struct gsm_bts *bts;</span><br><span style="color: hsl(120, 100%, 40%);">+  struct bitvec *bv;</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 bool generate_bcch_chan_list__ni_iter_cb(const struct neighbor_ident_key *key,</span><br><span style="color: hsl(120, 100%, 40%);">+                                               const struct gsm0808_cell_id_list2 *val,</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 generate_bcch_chan_list__ni_iter_data *data = cb_data;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (key->from_bts != NEIGHBOR_IDENT_KEY_ANY_BTS</span><br><span style="color: hsl(120, 100%, 40%);">+        && key->from_bts != data->bts->nr)</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%);">+        bitvec_set_bit_pos(data->bv, key->arfcn, 1);</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> /*! generate a cell channel list as per Section 10.5.2.22 of 04.08</span><br><span>  *  \param[out] chan_list caller-provided output buffer</span><br><span>  *  \param[in] bts BTS descriptor used for input data</span><br><span>@@ -602,6 +624,7 @@</span><br><span>    struct bitvec *bv;</span><br><span>   int rc;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+   /* first we generate a bitvec of the BCCH ARFCN's in our BSC */</span><br><span>  if (si5 && bts->neigh_list_manual_mode == NL_MODE_MANUAL_SI5SEP)</span><br><span>          bv = &bts->si_common.si5_neigh_list;</span><br><span>  else</span><br><span>@@ -612,11 +635,29 @@</span><br><span>                 /* Zero-initialize the bit-vector */</span><br><span>                 memset(bv->data, 0, bv->data_len);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-            /* first we generate a bitvec of the BCCH ARFCN's in our BSC */</span><br><span style="color: hsl(0, 100%, 40%);">-             llist_for_each_entry(cur_bts, &bts->network->bts_list, list) {</span><br><span style="color: hsl(0, 100%, 40%);">-                        if (cur_bts == bts)</span><br><span style="color: hsl(0, 100%, 40%);">-                             continue;</span><br><span style="color: hsl(0, 100%, 40%);">-                       bitvec_set_bit_pos(bv, cur_bts->c0->arfcn, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+          if (llist_empty(&bts->local_neighbors)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      /* There are no explicit neighbors, assume all BTS are. */</span><br><span style="color: hsl(120, 100%, 40%);">+                    llist_for_each_entry(cur_bts, &bts->network->bts_list, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+                              if (cur_bts == bts)</span><br><span style="color: hsl(120, 100%, 40%);">+                                   continue;</span><br><span style="color: hsl(120, 100%, 40%);">+                             bitvec_set_bit_pos(bv, cur_bts->c0->arfcn, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+                  }</span><br><span style="color: hsl(120, 100%, 40%);">+             } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      /* Only add explicit neighbor cells */</span><br><span style="color: hsl(120, 100%, 40%);">+                        struct gsm_bts_ref *neigh;</span><br><span style="color: hsl(120, 100%, 40%);">+                    llist_for_each_entry(neigh, &bts->local_neighbors, entry) {</span><br><span style="color: hsl(120, 100%, 40%);">+                            bitvec_set_bit_pos(bv, neigh->bts->c0->arfcn, 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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           /* Also add neighboring BSS cells' ARFCNs */</span><br><span style="color: hsl(120, 100%, 40%);">+              {</span><br><span style="color: hsl(120, 100%, 40%);">+                     struct generate_bcch_chan_list__ni_iter_data data = {</span><br><span style="color: hsl(120, 100%, 40%);">+                         .bv = bv,</span><br><span style="color: hsl(120, 100%, 40%);">+                             .bts = bts,</span><br><span style="color: hsl(120, 100%, 40%);">+                   };</span><br><span style="color: hsl(120, 100%, 40%);">+                    neighbor_ident_iter(bts->network->neighbor_bss_cells,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       generate_bcch_chan_list__ni_iter_cb, &data);</span><br><span>                 }</span><br><span>    }</span><br><span> </span><br><span>diff --git a/tests/bsc/Makefile.am b/tests/bsc/Makefile.am</span><br><span>index a930629..2e34d79 100644</span><br><span>--- a/tests/bsc/Makefile.am</span><br><span>+++ b/tests/bsc/Makefile.am</span><br><span>@@ -45,6 +45,7 @@</span><br><span>   $(top_builddir)/src/osmo-bsc/gsm_data.o \</span><br><span>    $(top_builddir)/src/osmo-bsc/handover_cfg.o \</span><br><span>        $(top_builddir)/src/osmo-bsc/handover_logic.o \</span><br><span style="color: hsl(120, 100%, 40%);">+       $(top_builddir)/src/osmo-bsc/neighbor_ident.o \</span><br><span>      $(top_builddir)/src/osmo-bsc/net_init.o \</span><br><span>    $(top_builddir)/src/osmo-bsc/paging.o \</span><br><span>      $(top_builddir)/src/osmo-bsc/pcu_sock.o \</span><br><span>diff --git a/tests/gsm0408/Makefile.am b/tests/gsm0408/Makefile.am</span><br><span>index 6d10b9f..3eb47f6 100644</span><br><span>--- a/tests/gsm0408/Makefile.am</span><br><span>+++ b/tests/gsm0408/Makefile.am</span><br><span>@@ -28,6 +28,7 @@</span><br><span>       $(top_builddir)/src/osmo-bsc/net_init.o \</span><br><span>    $(top_builddir)/src/osmo-bsc/rest_octets.o \</span><br><span>         $(top_builddir)/src/osmo-bsc/system_information.o \</span><br><span style="color: hsl(120, 100%, 40%);">+   $(top_builddir)/src/osmo-bsc/neighbor_ident.o \</span><br><span>      $(LIBOSMOCORE_LIBS) \</span><br><span>        $(LIBOSMOGSM_LIBS) \</span><br><span>         $(LIBOSMOABIS_LIBS) \</span><br><span>diff --git a/tests/handover/Makefile.am b/tests/handover/Makefile.am</span><br><span>index 07491d5..2f84d7a 100644</span><br><span>--- a/tests/handover/Makefile.am</span><br><span>+++ b/tests/handover/Makefile.am</span><br><span>@@ -23,6 +23,7 @@</span><br><span> </span><br><span> noinst_PROGRAMS = \</span><br><span>    handover_test \</span><br><span style="color: hsl(120, 100%, 40%);">+       neighbor_ident_test \</span><br><span>        $(NULL)</span><br><span> </span><br><span> handover_test_SOURCES = \</span><br><span>@@ -56,6 +57,7 @@</span><br><span>         $(top_builddir)/src/osmo-bsc/handover_decision_2.o \</span><br><span>         $(top_builddir)/src/osmo-bsc/handover_logic.o \</span><br><span>      $(top_builddir)/src/osmo-bsc/meas_rep.o \</span><br><span style="color: hsl(120, 100%, 40%);">+     $(top_builddir)/src/osmo-bsc/neighbor_ident.o \</span><br><span>      $(top_builddir)/src/osmo-bsc/osmo_bsc_lcls.o \</span><br><span>       $(top_builddir)/src/osmo-bsc/net_init.o \</span><br><span>    $(top_builddir)/src/osmo-bsc/paging.o \</span><br><span>@@ -69,3 +71,17 @@</span><br><span>         $(LIBOSMOSIGTRAN_LIBS) \</span><br><span>     $(LIBOSMOMGCPCLIENT_LIBS) \</span><br><span>  $(NULL)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+neighbor_ident_test_SOURCES = \</span><br><span style="color: hsl(120, 100%, 40%);">+    neighbor_ident_test.c \</span><br><span style="color: hsl(120, 100%, 40%);">+       $(NULL)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+neighbor_ident_test_LDADD = \</span><br><span style="color: hsl(120, 100%, 40%);">+      $(top_builddir)/src/osmo-bsc/neighbor_ident.o \</span><br><span style="color: hsl(120, 100%, 40%);">+       $(LIBOSMOCORE_LIBS) \</span><br><span style="color: hsl(120, 100%, 40%);">+ $(LIBOSMOGSM_LIBS) \</span><br><span style="color: hsl(120, 100%, 40%);">+  $(NULL)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+.PHONY: update_exp</span><br><span style="color: hsl(120, 100%, 40%);">+update_exp:</span><br><span style="color: hsl(120, 100%, 40%);">+    $(builddir)/neighbor_ident_test >$(srcdir)/neighbor_ident_test.ok 2>$(srcdir)/neighbor_ident_test.err</span><br><span>diff --git a/tests/handover/neighbor_ident_test.c b/tests/handover/neighbor_ident_test.c</span><br><span>new file mode 100644</span><br><span>index 0000000..b67219c</span><br><span>--- /dev/null</span><br><span>+++ b/tests/handover/neighbor_ident_test.c</span><br><span>@@ -0,0 +1,278 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* Test the neighbor_ident.h API */</span><br><span style="color: hsl(120, 100%, 40%);">+/*</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%);">+ * 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%);">+ *</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 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 <talloc.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdio.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/gsm/gsm0808.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/neighbor_ident.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct neighbor_ident_list *nil;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct neighbor_ident_key *k(int from_bts, uint16_t arfcn, enum bsic_kind kind, uint16_t bsic)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    static struct neighbor_ident_key key;</span><br><span style="color: hsl(120, 100%, 40%);">+ key = (struct neighbor_ident_key){</span><br><span style="color: hsl(120, 100%, 40%);">+            .from_bts = from_bts,</span><br><span style="color: hsl(120, 100%, 40%);">+         .arfcn = arfcn,</span><br><span style="color: hsl(120, 100%, 40%);">+               .bsic_kind = kind,</span><br><span style="color: hsl(120, 100%, 40%);">+            .bsic = bsic,</span><br><span style="color: hsl(120, 100%, 40%);">+ };</span><br><span style="color: hsl(120, 100%, 40%);">+    return &key;</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 const struct gsm0808_cell_id_list2 cgi1 = {</span><br><span style="color: hsl(120, 100%, 40%);">+     .id_discr = CELL_IDENT_WHOLE_GLOBAL,</span><br><span style="color: hsl(120, 100%, 40%);">+  .id_list_len = 1,</span><br><span style="color: hsl(120, 100%, 40%);">+     .id_list = {</span><br><span style="color: hsl(120, 100%, 40%);">+          {</span><br><span style="color: hsl(120, 100%, 40%);">+                     .global = {</span><br><span style="color: hsl(120, 100%, 40%);">+                           .lai = {</span><br><span style="color: hsl(120, 100%, 40%);">+                                      .plmn = { .mcc = 1, .mnc = 2, .mnc_3_digits = false },</span><br><span style="color: hsl(120, 100%, 40%);">+                                        .lac = 3,</span><br><span style="color: hsl(120, 100%, 40%);">+                             },</span><br><span style="color: hsl(120, 100%, 40%);">+                            .cell_identity = 4,</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%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct gsm0808_cell_id_list2 cgi2 = {</span><br><span style="color: hsl(120, 100%, 40%);">+  .id_discr = CELL_IDENT_WHOLE_GLOBAL,</span><br><span style="color: hsl(120, 100%, 40%);">+  .id_list_len = 2,</span><br><span style="color: hsl(120, 100%, 40%);">+     .id_list = {</span><br><span style="color: hsl(120, 100%, 40%);">+          {</span><br><span style="color: hsl(120, 100%, 40%);">+                     .global = {</span><br><span style="color: hsl(120, 100%, 40%);">+                           .lai = {</span><br><span style="color: hsl(120, 100%, 40%);">+                                      .plmn = { .mcc = 1, .mnc = 2, .mnc_3_digits = false },</span><br><span style="color: hsl(120, 100%, 40%);">+                                        .lac = 3,</span><br><span style="color: hsl(120, 100%, 40%);">+                             },</span><br><span style="color: hsl(120, 100%, 40%);">+                            .cell_identity = 4,</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%);">+                     .global = {</span><br><span style="color: hsl(120, 100%, 40%);">+                           .lai = {</span><br><span style="color: hsl(120, 100%, 40%);">+                                      .plmn = { .mcc = 5, .mnc = 6, .mnc_3_digits = true },</span><br><span style="color: hsl(120, 100%, 40%);">+                                 .lac = 7,</span><br><span style="color: hsl(120, 100%, 40%);">+                             },</span><br><span style="color: hsl(120, 100%, 40%);">+                            .cell_identity = 8,</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%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct gsm0808_cell_id_list2 lac1 = {</span><br><span style="color: hsl(120, 100%, 40%);">+  .id_discr = CELL_IDENT_LAC,</span><br><span style="color: hsl(120, 100%, 40%);">+   .id_list_len = 1,</span><br><span style="color: hsl(120, 100%, 40%);">+     .id_list = {</span><br><span style="color: hsl(120, 100%, 40%);">+          {</span><br><span style="color: hsl(120, 100%, 40%);">+                     .lac = 123</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct gsm0808_cell_id_list2 lac2 = {</span><br><span style="color: hsl(120, 100%, 40%);">+  .id_discr = CELL_IDENT_LAC,</span><br><span style="color: hsl(120, 100%, 40%);">+   .id_list_len = 2,</span><br><span style="color: hsl(120, 100%, 40%);">+     .id_list = {</span><br><span style="color: hsl(120, 100%, 40%);">+          {</span><br><span style="color: hsl(120, 100%, 40%);">+                     .lac = 456</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%);">+                     .lac = 789</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void print_cil(const struct gsm0808_cell_id_list2 *cil)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!cil) {</span><br><span style="color: hsl(120, 100%, 40%);">+           printf("     cell_id_list == NULL\n");</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%);">+     switch (cil->id_discr) {</span><br><span style="color: hsl(120, 100%, 40%);">+   case CELL_IDENT_WHOLE_GLOBAL:</span><br><span style="color: hsl(120, 100%, 40%);">+         printf("     cell_id_list cgi[%u] = {\n", cil->id_list_len);</span><br><span style="color: hsl(120, 100%, 40%);">+             for (i = 0; i < cil->id_list_len; i++)</span><br><span style="color: hsl(120, 100%, 40%);">+                  printf("       %2d: %s\n", i, osmo_cgi_name(&cil->id_list[i].global));</span><br><span style="color: hsl(120, 100%, 40%);">+               printf("     }\n");</span><br><span style="color: hsl(120, 100%, 40%);">+         break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case CELL_IDENT_LAC:</span><br><span style="color: hsl(120, 100%, 40%);">+          printf("     cell_id_list lac[%u] = {\n", cil->id_list_len);</span><br><span style="color: hsl(120, 100%, 40%);">+             for (i = 0; i < cil->id_list_len; i++)</span><br><span style="color: hsl(120, 100%, 40%);">+                  printf("      %2d: %u\n", i, cil->id_list[i].lac);</span><br><span style="color: hsl(120, 100%, 40%);">+               printf("     }\n");</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%);">+              printf("     Unimplemented id_disc\n");</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%);">+static int print_nil_i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+bool nil_cb(const struct neighbor_ident_key *key, const struct gsm0808_cell_id_list2 *val,</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%);">+ printf(" %2d: %s\n", print_nil_i++, neighbor_ident_key_name(key));</span><br><span style="color: hsl(120, 100%, 40%);">+  print_cil(val);</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 print_nil()</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        print_nil_i = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+      neighbor_ident_iter(nil, nil_cb, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!print_nil_i)</span><br><span style="color: hsl(120, 100%, 40%);">+             printf("     (empty)\n");</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%);">+#define check_add(key, val, expect_rc) \</span><br><span style="color: hsl(120, 100%, 40%);">+    do { \</span><br><span style="color: hsl(120, 100%, 40%);">+                int rc; \</span><br><span style="color: hsl(120, 100%, 40%);">+             rc = neighbor_ident_add(nil, key, val); \</span><br><span style="color: hsl(120, 100%, 40%);">+             printf("neighbor_ident_add(" #key ", " #val ") --> expect rc=" #expect_rc ", got %d\n", rc); \</span><br><span style="color: hsl(120, 100%, 40%);">+             if (rc != expect_rc) \</span><br><span style="color: hsl(120, 100%, 40%);">+                        printf("ERROR\n"); \</span><br><span style="color: hsl(120, 100%, 40%);">+                print_nil(); \</span><br><span style="color: hsl(120, 100%, 40%);">+        } while(0)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define check_del(key, expect_rc) \</span><br><span style="color: hsl(120, 100%, 40%);">+     do { \</span><br><span style="color: hsl(120, 100%, 40%);">+                bool rc; \</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = neighbor_ident_del(nil, key); \</span><br><span style="color: hsl(120, 100%, 40%);">+          printf("neighbor_ident_del(" #key ") --> %s\n", rc ? "entry deleted" : "nothing deleted"); \</span><br><span style="color: hsl(120, 100%, 40%);">+               if (rc != expect_rc) \</span><br><span style="color: hsl(120, 100%, 40%);">+                        printf("ERROR: expected: %s\n", expect_rc ? "entry deleted" : "nothing deleted"); \</span><br><span style="color: hsl(120, 100%, 40%);">+             print_nil(); \</span><br><span style="color: hsl(120, 100%, 40%);">+        } while(0)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define check_get(key, expect_rc) \</span><br><span style="color: hsl(120, 100%, 40%);">+     do { \</span><br><span style="color: hsl(120, 100%, 40%);">+                const struct gsm0808_cell_id_list2 *rc; \</span><br><span style="color: hsl(120, 100%, 40%);">+             rc = neighbor_ident_get(nil, key); \</span><br><span style="color: hsl(120, 100%, 40%);">+          printf("neighbor_ident_get(" #key ") --> %s\n", \</span><br><span style="color: hsl(120, 100%, 40%);">+                     rc ? "entry returned" : "NULL"); \</span><br><span style="color: hsl(120, 100%, 40%);">+         if (((bool)expect_rc) != ((bool) rc)) \</span><br><span style="color: hsl(120, 100%, 40%);">+                       printf("ERROR: expected %s\n", expect_rc ? "an entry" : "NULL"); \</span><br><span style="color: hsl(120, 100%, 40%);">+              if (rc) \</span><br><span style="color: hsl(120, 100%, 40%);">+                     print_cil(rc); \</span><br><span style="color: hsl(120, 100%, 40%);">+      } while(0)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int main(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       void *ctx = talloc_named_const(NULL, 0, "neighbor_ident_test");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   printf("\n--- testing NULL neighbor_ident_list\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ nil = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+   check_add(k(0, 1, BSIC_6BIT, 2), &cgi1, -ENOMEM);</span><br><span style="color: hsl(120, 100%, 40%);">+ check_get(k(0, 1, BSIC_6BIT, 2), false);</span><br><span style="color: hsl(120, 100%, 40%);">+      check_del(k(0, 1, BSIC_6BIT, 2), false);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    printf("\n--- adding entries, test that no two identical entries are added\n");</span><br><span style="color: hsl(120, 100%, 40%);">+     nil = neighbor_ident_init(ctx);</span><br><span style="color: hsl(120, 100%, 40%);">+       check_add(k(0, 1, BSIC_6BIT, 2), &cgi1, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+       check_get(k(0, 1, BSIC_6BIT, 2), true);</span><br><span style="color: hsl(120, 100%, 40%);">+       check_add(k(0, 1, BSIC_6BIT, 2), &cgi1, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+       check_add(k(0, 1, BSIC_6BIT, 2), &cgi2, 2);</span><br><span style="color: hsl(120, 100%, 40%);">+       check_add(k(0, 1, BSIC_6BIT, 2), &cgi2, 2);</span><br><span style="color: hsl(120, 100%, 40%);">+       check_del(k(0, 1, BSIC_6BIT, 2), true);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     printf("\n--- Cannot mix cell identifier types for one entry\n");</span><br><span style="color: hsl(120, 100%, 40%);">+   check_add(k(0, 1, BSIC_6BIT, 2), &cgi1, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+       check_add(k(0, 1, BSIC_6BIT, 2), &lac1, -EINVAL);</span><br><span style="color: hsl(120, 100%, 40%);">+ check_del(k(0, 1, BSIC_6BIT, 2), true);</span><br><span style="color: hsl(120, 100%, 40%);">+       neighbor_ident_free(nil);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   printf("\n--- BTS matching: specific BTS is stronger\n");</span><br><span style="color: hsl(120, 100%, 40%);">+   nil = neighbor_ident_init(ctx);</span><br><span style="color: hsl(120, 100%, 40%);">+       check_add(k(NEIGHBOR_IDENT_KEY_ANY_BTS, 1, BSIC_6BIT, 2), &lac1, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+      check_add(k(3, 1, BSIC_6BIT, 2), &lac2, 2);</span><br><span style="color: hsl(120, 100%, 40%);">+       check_get(k(2, 1, BSIC_6BIT, 2), true);</span><br><span style="color: hsl(120, 100%, 40%);">+       check_get(k(3, 1, BSIC_6BIT, 2), true);</span><br><span style="color: hsl(120, 100%, 40%);">+       check_get(k(4, 1, BSIC_6BIT, 2), true);</span><br><span style="color: hsl(120, 100%, 40%);">+       check_get(k(NEIGHBOR_IDENT_KEY_ANY_BTS, 1, BSIC_6BIT, 2), true);</span><br><span style="color: hsl(120, 100%, 40%);">+      neighbor_ident_free(nil);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   printf("\n--- BSIC matching: 6bit and 9bit are different realms, and wildcard match is weaker\n");</span><br><span style="color: hsl(120, 100%, 40%);">+  nil = neighbor_ident_init(ctx);</span><br><span style="color: hsl(120, 100%, 40%);">+       check_add(k(0, 1, BSIC_NONE, 0), &cgi1, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+       check_add(k(0, 1, BSIC_6BIT, 2), &lac1, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+       check_add(k(0, 1, BSIC_9BIT, 2), &lac2, 2);</span><br><span style="color: hsl(120, 100%, 40%);">+       check_get(k(0, 1, BSIC_6BIT, 2), true);</span><br><span style="color: hsl(120, 100%, 40%);">+       check_get(k(0, 1, BSIC_9BIT, 2), true);</span><br><span style="color: hsl(120, 100%, 40%);">+       printf("--- wildcard matches both 6bit and 9bit BSIC regardless:\n");</span><br><span style="color: hsl(120, 100%, 40%);">+       check_get(k(0, 1, BSIC_6BIT, 23), true);</span><br><span style="color: hsl(120, 100%, 40%);">+      check_get(k(0, 1, BSIC_9BIT, 23), true);</span><br><span style="color: hsl(120, 100%, 40%);">+      neighbor_ident_free(nil);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   printf("\n--- Value ranges\n");</span><br><span style="color: hsl(120, 100%, 40%);">+     nil = neighbor_ident_init(ctx);</span><br><span style="color: hsl(120, 100%, 40%);">+       check_add(k(0, 6, BSIC_6BIT, 1 << 6), &lac1, -ERANGE);</span><br><span style="color: hsl(120, 100%, 40%);">+      check_add(k(0, 9, BSIC_9BIT, 1 << 9), &lac1, -ERANGE);</span><br><span style="color: hsl(120, 100%, 40%);">+      check_add(k(0, 6, BSIC_6BIT, -1), &lac1, -ERANGE);</span><br><span style="color: hsl(120, 100%, 40%);">+        check_add(k(0, 9, BSIC_9BIT, -1), &lac1, -ERANGE);</span><br><span style="color: hsl(120, 100%, 40%);">+        check_add(k(NEIGHBOR_IDENT_KEY_ANY_BTS - 1, 1, BSIC_NONE, 1), &cgi2, -ERANGE);</span><br><span style="color: hsl(120, 100%, 40%);">+    check_add(k(256, 1, BSIC_NONE, 1), &cgi2, -ERANGE);</span><br><span style="color: hsl(120, 100%, 40%);">+       check_add(k(0, 0, BSIC_NONE, 0), &cgi1, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+       check_add(k(255, 65535, BSIC_NONE, 65535), &lac1, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+     check_add(k(0, 0, BSIC_6BIT, 0), &cgi2, 2);</span><br><span style="color: hsl(120, 100%, 40%);">+       check_add(k(255, 65535, BSIC_6BIT, 0x3f), &lac2, 2);</span><br><span style="color: hsl(120, 100%, 40%);">+      check_add(k(0, 0, BSIC_9BIT, 0), &cgi1, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+       check_add(k(255, 65535, BSIC_9BIT, 0x1ff), &cgi2, 2);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   neighbor_ident_free(nil);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   printf("\n--- size limits\n");</span><br><span style="color: hsl(120, 100%, 40%);">+      {</span><br><span style="color: hsl(120, 100%, 40%);">+             int i;</span><br><span style="color: hsl(120, 100%, 40%);">+                struct gsm0808_cell_id_list2 a = { .id_discr = CELL_IDENT_LAC };</span><br><span style="color: hsl(120, 100%, 40%);">+              struct gsm0808_cell_id_list2 b = {</span><br><span style="color: hsl(120, 100%, 40%);">+                    .id_discr = CELL_IDENT_LAC,</span><br><span style="color: hsl(120, 100%, 40%);">+                   .id_list = {</span><br><span style="color: hsl(120, 100%, 40%);">+                          { .lac = 423 }</span><br><span style="color: hsl(120, 100%, 40%);">+                        },</span><br><span style="color: hsl(120, 100%, 40%);">+                    .id_list_len = 1,</span><br><span style="color: hsl(120, 100%, 40%);">+             };</span><br><span style="color: hsl(120, 100%, 40%);">+            for (i = 0; i < ARRAY_SIZE(a.id_list); i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      a.id_list[a.id_list_len ++].lac = i;</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%);">+           nil = neighbor_ident_init(ctx);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+             i = neighbor_ident_add(nil, k(0, 1, BSIC_6BIT, 2), &a);</span><br><span style="color: hsl(120, 100%, 40%);">+           printf("Added first cell identifier list (added %u) --> rc = %d\n", a.id_list_len, i);</span><br><span style="color: hsl(120, 100%, 40%);">+           i = neighbor_ident_add(nil, k(0, 1, BSIC_6BIT, 2), &b);</span><br><span style="color: hsl(120, 100%, 40%);">+           printf("Added second cell identifier list (tried to add %u) --> rc = %d\n", b.id_list_len, i);</span><br><span style="color: hsl(120, 100%, 40%);">+           if (i != -ENOSPC)</span><br><span style="color: hsl(120, 100%, 40%);">+                     printf("ERROR: expected rc=%d\n", -ENOSPC);</span><br><span style="color: hsl(120, 100%, 40%);">+         neighbor_ident_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%);">+   OSMO_ASSERT(talloc_total_blocks(ctx) == 1);</span><br><span style="color: hsl(120, 100%, 40%);">+   talloc_free(ctx);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/tests/handover/neighbor_ident_test.err b/tests/handover/neighbor_ident_test.err</span><br><span>new file mode 100644</span><br><span>index 0000000..e69de29</span><br><span>--- /dev/null</span><br><span>+++ b/tests/handover/neighbor_ident_test.err</span><br><span>diff --git a/tests/handover/neighbor_ident_test.ok b/tests/handover/neighbor_ident_test.ok</span><br><span>new file mode 100644</span><br><span>index 0000000..280b6f2</span><br><span>--- /dev/null</span><br><span>+++ b/tests/handover/neighbor_ident_test.ok</span><br><span>@@ -0,0 +1,249 @@</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+--- testing NULL neighbor_ident_list</span><br><span style="color: hsl(120, 100%, 40%);">+neighbor_ident_add(k(0, 1, BSIC_6BIT, 2), &cgi1) --> expect rc=-ENOMEM, got -12</span><br><span style="color: hsl(120, 100%, 40%);">+     (empty)</span><br><span style="color: hsl(120, 100%, 40%);">+neighbor_ident_get(k(0, 1, BSIC_6BIT, 2)) --> NULL</span><br><span style="color: hsl(120, 100%, 40%);">+neighbor_ident_del(k(0, 1, BSIC_6BIT, 2)) --> nothing deleted</span><br><span style="color: hsl(120, 100%, 40%);">+     (empty)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+--- adding entries, test that no two identical entries are added</span><br><span style="color: hsl(120, 100%, 40%);">+neighbor_ident_add(k(0, 1, BSIC_6BIT, 2), &cgi1) --> expect rc=1, got 1</span><br><span style="color: hsl(120, 100%, 40%);">+  0: BTS 0 to ARFCN 1 BSIC 2</span><br><span style="color: hsl(120, 100%, 40%);">+     cell_id_list cgi[1] = {</span><br><span style="color: hsl(120, 100%, 40%);">+        0: 001-02-3-4</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+neighbor_ident_get(k(0, 1, BSIC_6BIT, 2)) --> entry returned</span><br><span style="color: hsl(120, 100%, 40%);">+     cell_id_list cgi[1] = {</span><br><span style="color: hsl(120, 100%, 40%);">+        0: 001-02-3-4</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+neighbor_ident_add(k(0, 1, BSIC_6BIT, 2), &cgi1) --> expect rc=1, got 1</span><br><span style="color: hsl(120, 100%, 40%);">+  0: BTS 0 to ARFCN 1 BSIC 2</span><br><span style="color: hsl(120, 100%, 40%);">+     cell_id_list cgi[1] = {</span><br><span style="color: hsl(120, 100%, 40%);">+        0: 001-02-3-4</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+neighbor_ident_add(k(0, 1, BSIC_6BIT, 2), &cgi2) --> expect rc=2, got 2</span><br><span style="color: hsl(120, 100%, 40%);">+  0: BTS 0 to ARFCN 1 BSIC 2</span><br><span style="color: hsl(120, 100%, 40%);">+     cell_id_list cgi[2] = {</span><br><span style="color: hsl(120, 100%, 40%);">+        0: 001-02-3-4</span><br><span style="color: hsl(120, 100%, 40%);">+        1: 005-006-7-8</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+neighbor_ident_add(k(0, 1, BSIC_6BIT, 2), &cgi2) --> expect rc=2, got 2</span><br><span style="color: hsl(120, 100%, 40%);">+  0: BTS 0 to ARFCN 1 BSIC 2</span><br><span style="color: hsl(120, 100%, 40%);">+     cell_id_list cgi[2] = {</span><br><span style="color: hsl(120, 100%, 40%);">+        0: 001-02-3-4</span><br><span style="color: hsl(120, 100%, 40%);">+        1: 005-006-7-8</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+neighbor_ident_del(k(0, 1, BSIC_6BIT, 2)) --> entry deleted</span><br><span style="color: hsl(120, 100%, 40%);">+     (empty)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+--- Cannot mix cell identifier types for one entry</span><br><span style="color: hsl(120, 100%, 40%);">+neighbor_ident_add(k(0, 1, BSIC_6BIT, 2), &cgi1) --> expect rc=1, got 1</span><br><span style="color: hsl(120, 100%, 40%);">+  0: BTS 0 to ARFCN 1 BSIC 2</span><br><span style="color: hsl(120, 100%, 40%);">+     cell_id_list cgi[1] = {</span><br><span style="color: hsl(120, 100%, 40%);">+        0: 001-02-3-4</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+neighbor_ident_add(k(0, 1, BSIC_6BIT, 2), &lac1) --> expect rc=-EINVAL, got -22</span><br><span style="color: hsl(120, 100%, 40%);">+  0: BTS 0 to ARFCN 1 BSIC 2</span><br><span style="color: hsl(120, 100%, 40%);">+     cell_id_list cgi[1] = {</span><br><span style="color: hsl(120, 100%, 40%);">+        0: 001-02-3-4</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+neighbor_ident_del(k(0, 1, BSIC_6BIT, 2)) --> entry deleted</span><br><span style="color: hsl(120, 100%, 40%);">+     (empty)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+--- BTS matching: specific BTS is stronger</span><br><span style="color: hsl(120, 100%, 40%);">+neighbor_ident_add(k(NEIGHBOR_IDENT_KEY_ANY_BTS, 1, BSIC_6BIT, 2), &lac1) --> expect rc=1, got 1</span><br><span style="color: hsl(120, 100%, 40%);">+  0: BTS * to ARFCN 1 BSIC 2</span><br><span style="color: hsl(120, 100%, 40%);">+     cell_id_list lac[1] = {</span><br><span style="color: hsl(120, 100%, 40%);">+       0: 123</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+neighbor_ident_add(k(3, 1, BSIC_6BIT, 2), &lac2) --> expect rc=2, got 2</span><br><span style="color: hsl(120, 100%, 40%);">+  0: BTS * to ARFCN 1 BSIC 2</span><br><span style="color: hsl(120, 100%, 40%);">+     cell_id_list lac[1] = {</span><br><span style="color: hsl(120, 100%, 40%);">+       0: 123</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+  1: BTS 3 to ARFCN 1 BSIC 2</span><br><span style="color: hsl(120, 100%, 40%);">+     cell_id_list lac[2] = {</span><br><span style="color: hsl(120, 100%, 40%);">+       0: 456</span><br><span style="color: hsl(120, 100%, 40%);">+       1: 789</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+neighbor_ident_get(k(2, 1, BSIC_6BIT, 2)) --> entry returned</span><br><span style="color: hsl(120, 100%, 40%);">+     cell_id_list lac[1] = {</span><br><span style="color: hsl(120, 100%, 40%);">+       0: 123</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+neighbor_ident_get(k(3, 1, BSIC_6BIT, 2)) --> entry returned</span><br><span style="color: hsl(120, 100%, 40%);">+     cell_id_list lac[2] = {</span><br><span style="color: hsl(120, 100%, 40%);">+       0: 456</span><br><span style="color: hsl(120, 100%, 40%);">+       1: 789</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+neighbor_ident_get(k(4, 1, BSIC_6BIT, 2)) --> entry returned</span><br><span style="color: hsl(120, 100%, 40%);">+     cell_id_list lac[1] = {</span><br><span style="color: hsl(120, 100%, 40%);">+       0: 123</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+neighbor_ident_get(k(NEIGHBOR_IDENT_KEY_ANY_BTS, 1, BSIC_6BIT, 2)) --> entry returned</span><br><span style="color: hsl(120, 100%, 40%);">+     cell_id_list lac[1] = {</span><br><span style="color: hsl(120, 100%, 40%);">+       0: 123</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%);">+--- BSIC matching: 6bit and 9bit are different realms, and wildcard match is weaker</span><br><span style="color: hsl(120, 100%, 40%);">+neighbor_ident_add(k(0, 1, BSIC_NONE, 0), &cgi1) --> expect rc=1, got 1</span><br><span style="color: hsl(120, 100%, 40%);">+  0: BTS 0 to ARFCN 1 (any BSIC)</span><br><span style="color: hsl(120, 100%, 40%);">+     cell_id_list cgi[1] = {</span><br><span style="color: hsl(120, 100%, 40%);">+        0: 001-02-3-4</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+neighbor_ident_add(k(0, 1, BSIC_6BIT, 2), &lac1) --> expect rc=1, got 1</span><br><span style="color: hsl(120, 100%, 40%);">+  0: BTS 0 to ARFCN 1 (any BSIC)</span><br><span style="color: hsl(120, 100%, 40%);">+     cell_id_list cgi[1] = {</span><br><span style="color: hsl(120, 100%, 40%);">+        0: 001-02-3-4</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+  1: BTS 0 to ARFCN 1 BSIC 2</span><br><span style="color: hsl(120, 100%, 40%);">+     cell_id_list lac[1] = {</span><br><span style="color: hsl(120, 100%, 40%);">+       0: 123</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+neighbor_ident_add(k(0, 1, BSIC_9BIT, 2), &lac2) --> expect rc=2, got 2</span><br><span style="color: hsl(120, 100%, 40%);">+  0: BTS 0 to ARFCN 1 (any BSIC)</span><br><span style="color: hsl(120, 100%, 40%);">+     cell_id_list cgi[1] = {</span><br><span style="color: hsl(120, 100%, 40%);">+        0: 001-02-3-4</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+  1: BTS 0 to ARFCN 1 BSIC 2</span><br><span style="color: hsl(120, 100%, 40%);">+     cell_id_list lac[1] = {</span><br><span style="color: hsl(120, 100%, 40%);">+       0: 123</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+  2: BTS 0 to ARFCN 1 BSIC 2(9bit)</span><br><span style="color: hsl(120, 100%, 40%);">+     cell_id_list lac[2] = {</span><br><span style="color: hsl(120, 100%, 40%);">+       0: 456</span><br><span style="color: hsl(120, 100%, 40%);">+       1: 789</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+neighbor_ident_get(k(0, 1, BSIC_6BIT, 2)) --> entry returned</span><br><span style="color: hsl(120, 100%, 40%);">+     cell_id_list lac[1] = {</span><br><span style="color: hsl(120, 100%, 40%);">+       0: 123</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+neighbor_ident_get(k(0, 1, BSIC_9BIT, 2)) --> entry returned</span><br><span style="color: hsl(120, 100%, 40%);">+     cell_id_list lac[2] = {</span><br><span style="color: hsl(120, 100%, 40%);">+       0: 456</span><br><span style="color: hsl(120, 100%, 40%);">+       1: 789</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+--- wildcard matches both 6bit and 9bit BSIC regardless:</span><br><span style="color: hsl(120, 100%, 40%);">+neighbor_ident_get(k(0, 1, BSIC_6BIT, 23)) --> entry returned</span><br><span style="color: hsl(120, 100%, 40%);">+     cell_id_list cgi[1] = {</span><br><span style="color: hsl(120, 100%, 40%);">+        0: 001-02-3-4</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+neighbor_ident_get(k(0, 1, BSIC_9BIT, 23)) --> entry returned</span><br><span style="color: hsl(120, 100%, 40%);">+     cell_id_list cgi[1] = {</span><br><span style="color: hsl(120, 100%, 40%);">+        0: 001-02-3-4</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%);">+--- Value ranges</span><br><span style="color: hsl(120, 100%, 40%);">+neighbor_ident_add(k(0, 6, BSIC_6BIT, 1 << 6), &lac1) --> expect rc=-ERANGE, got -34</span><br><span style="color: hsl(120, 100%, 40%);">+     (empty)</span><br><span style="color: hsl(120, 100%, 40%);">+neighbor_ident_add(k(0, 9, BSIC_9BIT, 1 << 9), &lac1) --> expect rc=-ERANGE, got -34</span><br><span style="color: hsl(120, 100%, 40%);">+     (empty)</span><br><span style="color: hsl(120, 100%, 40%);">+neighbor_ident_add(k(0, 6, BSIC_6BIT, -1), &lac1) --> expect rc=-ERANGE, got -34</span><br><span style="color: hsl(120, 100%, 40%);">+     (empty)</span><br><span style="color: hsl(120, 100%, 40%);">+neighbor_ident_add(k(0, 9, BSIC_9BIT, -1), &lac1) --> expect rc=-ERANGE, got -34</span><br><span style="color: hsl(120, 100%, 40%);">+     (empty)</span><br><span style="color: hsl(120, 100%, 40%);">+neighbor_ident_add(k(NEIGHBOR_IDENT_KEY_ANY_BTS - 1, 1, BSIC_NONE, 1), &cgi2) --> expect rc=-ERANGE, got -34</span><br><span style="color: hsl(120, 100%, 40%);">+     (empty)</span><br><span style="color: hsl(120, 100%, 40%);">+neighbor_ident_add(k(256, 1, BSIC_NONE, 1), &cgi2) --> expect rc=-ERANGE, got -34</span><br><span style="color: hsl(120, 100%, 40%);">+     (empty)</span><br><span style="color: hsl(120, 100%, 40%);">+neighbor_ident_add(k(0, 0, BSIC_NONE, 0), &cgi1) --> expect rc=1, got 1</span><br><span style="color: hsl(120, 100%, 40%);">+  0: BTS 0 to ARFCN 0 (any BSIC)</span><br><span style="color: hsl(120, 100%, 40%);">+     cell_id_list cgi[1] = {</span><br><span style="color: hsl(120, 100%, 40%);">+        0: 001-02-3-4</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+neighbor_ident_add(k(255, 65535, BSIC_NONE, 65535), &lac1) --> expect rc=1, got 1</span><br><span style="color: hsl(120, 100%, 40%);">+  0: BTS 0 to ARFCN 0 (any BSIC)</span><br><span style="color: hsl(120, 100%, 40%);">+     cell_id_list cgi[1] = {</span><br><span style="color: hsl(120, 100%, 40%);">+        0: 001-02-3-4</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+  1: BTS 255 to ARFCN 65535 (any BSIC)</span><br><span style="color: hsl(120, 100%, 40%);">+     cell_id_list lac[1] = {</span><br><span style="color: hsl(120, 100%, 40%);">+       0: 123</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+neighbor_ident_add(k(0, 0, BSIC_6BIT, 0), &cgi2) --> expect rc=2, got 2</span><br><span style="color: hsl(120, 100%, 40%);">+  0: BTS 0 to ARFCN 0 (any BSIC)</span><br><span style="color: hsl(120, 100%, 40%);">+     cell_id_list cgi[1] = {</span><br><span style="color: hsl(120, 100%, 40%);">+        0: 001-02-3-4</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+  1: BTS 255 to ARFCN 65535 (any BSIC)</span><br><span style="color: hsl(120, 100%, 40%);">+     cell_id_list lac[1] = {</span><br><span style="color: hsl(120, 100%, 40%);">+       0: 123</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+  2: BTS 0 to ARFCN 0 BSIC 0</span><br><span style="color: hsl(120, 100%, 40%);">+     cell_id_list cgi[2] = {</span><br><span style="color: hsl(120, 100%, 40%);">+        0: 001-02-3-4</span><br><span style="color: hsl(120, 100%, 40%);">+        1: 005-006-7-8</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+neighbor_ident_add(k(255, 65535, BSIC_6BIT, 0x3f), &lac2) --> expect rc=2, got 2</span><br><span style="color: hsl(120, 100%, 40%);">+  0: BTS 0 to ARFCN 0 (any BSIC)</span><br><span style="color: hsl(120, 100%, 40%);">+     cell_id_list cgi[1] = {</span><br><span style="color: hsl(120, 100%, 40%);">+        0: 001-02-3-4</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+  1: BTS 255 to ARFCN 65535 (any BSIC)</span><br><span style="color: hsl(120, 100%, 40%);">+     cell_id_list lac[1] = {</span><br><span style="color: hsl(120, 100%, 40%);">+       0: 123</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+  2: BTS 0 to ARFCN 0 BSIC 0</span><br><span style="color: hsl(120, 100%, 40%);">+     cell_id_list cgi[2] = {</span><br><span style="color: hsl(120, 100%, 40%);">+        0: 001-02-3-4</span><br><span style="color: hsl(120, 100%, 40%);">+        1: 005-006-7-8</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+  3: BTS 255 to ARFCN 65535 BSIC 63</span><br><span style="color: hsl(120, 100%, 40%);">+     cell_id_list lac[2] = {</span><br><span style="color: hsl(120, 100%, 40%);">+       0: 456</span><br><span style="color: hsl(120, 100%, 40%);">+       1: 789</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+neighbor_ident_add(k(0, 0, BSIC_9BIT, 0), &cgi1) --> expect rc=1, got 1</span><br><span style="color: hsl(120, 100%, 40%);">+  0: BTS 0 to ARFCN 0 (any BSIC)</span><br><span style="color: hsl(120, 100%, 40%);">+     cell_id_list cgi[1] = {</span><br><span style="color: hsl(120, 100%, 40%);">+        0: 001-02-3-4</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+  1: BTS 255 to ARFCN 65535 (any BSIC)</span><br><span style="color: hsl(120, 100%, 40%);">+     cell_id_list lac[1] = {</span><br><span style="color: hsl(120, 100%, 40%);">+       0: 123</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+  2: BTS 0 to ARFCN 0 BSIC 0</span><br><span style="color: hsl(120, 100%, 40%);">+     cell_id_list cgi[2] = {</span><br><span style="color: hsl(120, 100%, 40%);">+        0: 001-02-3-4</span><br><span style="color: hsl(120, 100%, 40%);">+        1: 005-006-7-8</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+  3: BTS 255 to ARFCN 65535 BSIC 63</span><br><span style="color: hsl(120, 100%, 40%);">+     cell_id_list lac[2] = {</span><br><span style="color: hsl(120, 100%, 40%);">+       0: 456</span><br><span style="color: hsl(120, 100%, 40%);">+       1: 789</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+  4: BTS 0 to ARFCN 0 BSIC 0(9bit)</span><br><span style="color: hsl(120, 100%, 40%);">+     cell_id_list cgi[1] = {</span><br><span style="color: hsl(120, 100%, 40%);">+        0: 001-02-3-4</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+neighbor_ident_add(k(255, 65535, BSIC_9BIT, 0x1ff), &cgi2) --> expect rc=2, got 2</span><br><span style="color: hsl(120, 100%, 40%);">+  0: BTS 0 to ARFCN 0 (any BSIC)</span><br><span style="color: hsl(120, 100%, 40%);">+     cell_id_list cgi[1] = {</span><br><span style="color: hsl(120, 100%, 40%);">+        0: 001-02-3-4</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+  1: BTS 255 to ARFCN 65535 (any BSIC)</span><br><span style="color: hsl(120, 100%, 40%);">+     cell_id_list lac[1] = {</span><br><span style="color: hsl(120, 100%, 40%);">+       0: 123</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+  2: BTS 0 to ARFCN 0 BSIC 0</span><br><span style="color: hsl(120, 100%, 40%);">+     cell_id_list cgi[2] = {</span><br><span style="color: hsl(120, 100%, 40%);">+        0: 001-02-3-4</span><br><span style="color: hsl(120, 100%, 40%);">+        1: 005-006-7-8</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+  3: BTS 255 to ARFCN 65535 BSIC 63</span><br><span style="color: hsl(120, 100%, 40%);">+     cell_id_list lac[2] = {</span><br><span style="color: hsl(120, 100%, 40%);">+       0: 456</span><br><span style="color: hsl(120, 100%, 40%);">+       1: 789</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+  4: BTS 0 to ARFCN 0 BSIC 0(9bit)</span><br><span style="color: hsl(120, 100%, 40%);">+     cell_id_list cgi[1] = {</span><br><span style="color: hsl(120, 100%, 40%);">+        0: 001-02-3-4</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+  5: BTS 255 to ARFCN 65535 BSIC 511(9bit)</span><br><span style="color: hsl(120, 100%, 40%);">+     cell_id_list cgi[2] = {</span><br><span style="color: hsl(120, 100%, 40%);">+        0: 001-02-3-4</span><br><span style="color: hsl(120, 100%, 40%);">+        1: 005-006-7-8</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%);">+--- size limits</span><br><span style="color: hsl(120, 100%, 40%);">+Added first cell identifier list (added 127) --> rc = 127</span><br><span style="color: hsl(120, 100%, 40%);">+Added second cell identifier list (tried to add 1) --> rc = -28</span><br><span>diff --git a/tests/neighbor_ident.vty b/tests/neighbor_ident.vty</span><br><span>new file mode 100644</span><br><span>index 0000000..505eb72</span><br><span>--- /dev/null</span><br><span>+++ b/tests/neighbor_ident.vty</span><br><span>@@ -0,0 +1,251 @@</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC> ### Neighbor-BSS Cell Identifier List config</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC> enable</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC# configure terminal</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config)# network</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net)# bts 0</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# type sysmobts</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# base_station_id_code 10</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# location_area_code 20</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# cell_identity 30</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# trx 0</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts-trx)# arfcn 40</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts-trx)# exit</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# exit</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net)# bts 1</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# type sysmobts</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# base_station_id_code 11</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# location_area_code 21</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# cell_identity 31</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# trx 0</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts-trx)# arfcn 41</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts-trx)# exit</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# exit</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net)# bts 2</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# type sysmobts</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# base_station_id_code 12</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# location_area_code 22</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# cell_identity 32</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# trx 0</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts-trx)# arfcn 42</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts-trx)# exit</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# exit</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net)# show running-config</span><br><span style="color: hsl(120, 100%, 40%);">+...</span><br><span style="color: hsl(120, 100%, 40%);">+ bts 0</span><br><span style="color: hsl(120, 100%, 40%);">+...</span><br><span style="color: hsl(120, 100%, 40%);">+  cell_identity 30</span><br><span style="color: hsl(120, 100%, 40%);">+  location_area_code 20</span><br><span style="color: hsl(120, 100%, 40%);">+  base_station_id_code 10</span><br><span style="color: hsl(120, 100%, 40%);">+...</span><br><span style="color: hsl(120, 100%, 40%);">+  trx 0</span><br><span style="color: hsl(120, 100%, 40%);">+...</span><br><span style="color: hsl(120, 100%, 40%);">+   arfcn 40</span><br><span style="color: hsl(120, 100%, 40%);">+...</span><br><span style="color: hsl(120, 100%, 40%);">+ bts 1</span><br><span style="color: hsl(120, 100%, 40%);">+...</span><br><span style="color: hsl(120, 100%, 40%);">+  cell_identity 31</span><br><span style="color: hsl(120, 100%, 40%);">+  location_area_code 21</span><br><span style="color: hsl(120, 100%, 40%);">+  base_station_id_code 11</span><br><span style="color: hsl(120, 100%, 40%);">+...</span><br><span style="color: hsl(120, 100%, 40%);">+  trx 0</span><br><span style="color: hsl(120, 100%, 40%);">+...</span><br><span style="color: hsl(120, 100%, 40%);">+   arfcn 41</span><br><span style="color: hsl(120, 100%, 40%);">+...</span><br><span style="color: hsl(120, 100%, 40%);">+ bts 2</span><br><span style="color: hsl(120, 100%, 40%);">+...</span><br><span style="color: hsl(120, 100%, 40%);">+  cell_identity 32</span><br><span style="color: hsl(120, 100%, 40%);">+  location_area_code 22</span><br><span style="color: hsl(120, 100%, 40%);">+  base_station_id_code 12</span><br><span style="color: hsl(120, 100%, 40%);">+...</span><br><span style="color: hsl(120, 100%, 40%);">+  trx 0</span><br><span style="color: hsl(120, 100%, 40%);">+...</span><br><span style="color: hsl(120, 100%, 40%);">+   arfcn 42</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%);">+OsmoBSC(config-net)# bts 0</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# list</span><br><span style="color: hsl(120, 100%, 40%);">+...</span><br><span style="color: hsl(120, 100%, 40%);">+  neighbor add bts <0-255></span><br><span style="color: hsl(120, 100%, 40%);">+  neighbor add lac <0-65535></span><br><span style="color: hsl(120, 100%, 40%);">+  neighbor add lac-ci <0-65535> <0-255></span><br><span style="color: hsl(120, 100%, 40%);">+  neighbor add lac <0-65535> arfcn <0-1023> (bsic|bsic9) (<0-511>|any)</span><br><span style="color: hsl(120, 100%, 40%);">+  neighbor add lac-ci <0-65535> <0-255> arfcn <0-1023> (bsic|bsic9) (<0-511>|any)</span><br><span style="color: hsl(120, 100%, 40%);">+  neighbor add cgi <0-999> <0-999> <0-65535> <0-255> arfcn <0-1023> (bsic|bsic9) (<0-511>|any)</span><br><span style="color: hsl(120, 100%, 40%);">+  neighbor del bts <0-255></span><br><span style="color: hsl(120, 100%, 40%);">+  neighbor del arfcn <0-1023> (bsic|bsic9) (<0-511>|any)</span><br><span style="color: hsl(120, 100%, 40%);">+  neighbor resolve arfcn <0-1023> (bsic|bsic9) (<0-511>|any)</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%);">+OsmoBSC(config-net-bts)# show running-config</span><br><span style="color: hsl(120, 100%, 40%);">+... !neighbor add</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# neighbor add cgi 23 42 423 5 arfcn 23 bsic 64</span><br><span style="color: hsl(120, 100%, 40%);">+% Error: BSIC value surpasses 6-bit range: 64, use 'bsic9' instead</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# neighbor add bts 0</span><br><span style="color: hsl(120, 100%, 40%);">+% Error: cannot add local BTS 0 as neighbor to BTS 0: Invalid argument</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# show running-config</span><br><span style="color: hsl(120, 100%, 40%);">+... !neighbor add</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# neighbor add bts 1</span><br><span style="color: hsl(120, 100%, 40%);">+% BTS 0 now has local neighbor BTS 1 with LAC 21 CI 31 and ARFCN 41 BSIC 11</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# neighbor add lac 22</span><br><span style="color: hsl(120, 100%, 40%);">+% BTS 0 now has local neighbor BTS 2 with LAC 22 CI 32 and ARFCN 42 BSIC 12</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# neighbor add cgi 23 42 423 5 arfcn 23 bsic 42</span><br><span style="color: hsl(120, 100%, 40%);">+% BTS 0 to ARFCN 23 BSIC 42 now has 1 remote BSS Cell Identifier List entry</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# ### adding the same entry again results in no change</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# neighbor add bts 1</span><br><span style="color: hsl(120, 100%, 40%);">+% BTS 0 already had local neighbor BTS 1 with LAC 21 CI 31 and ARFCN 41 BSIC 11</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# neighbor add lac-ci 21 31</span><br><span style="color: hsl(120, 100%, 40%);">+% BTS 0 already had local neighbor BTS 1 with LAC 21 CI 31 and ARFCN 41 BSIC 11</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# neighbor add cgi 23 42 423 5 arfcn 23 bsic 42</span><br><span style="color: hsl(120, 100%, 40%);">+% BTS 0 to ARFCN 23 BSIC 42 now has 1 remote BSS Cell Identifier List entry</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# neighbor add cgi 23 42 423 5 arfcn 23 bsic 42</span><br><span style="color: hsl(120, 100%, 40%);">+% BTS 0 to ARFCN 23 BSIC 42 now has 1 remote BSS Cell Identifier List entry</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# neighbor add cgi 23 42 423 5 arfcn 23 bsic 42</span><br><span style="color: hsl(120, 100%, 40%);">+% BTS 0 to ARFCN 23 BSIC 42 now has 1 remote BSS Cell Identifier List entry</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# neighbor add cgi 23 042 423 6 arfcn 23 bsic 42</span><br><span style="color: hsl(120, 100%, 40%);">+% BTS 0 to ARFCN 23 BSIC 42 now has 2 remote BSS Cell Identifier List entries</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# neighbor add lac 456 arfcn 123 bsic 45</span><br><span style="color: hsl(120, 100%, 40%);">+% BTS 0 to ARFCN 123 BSIC 45 now has 1 remote BSS Cell Identifier List entry</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# neighbor add cgi 23 042 234 56 arfcn 23 bsic 42</span><br><span style="color: hsl(120, 100%, 40%);">+% BTS 0 to ARFCN 23 BSIC 42 now has 3 remote BSS Cell Identifier List entries</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# neighbor add lac-ci 789 10 arfcn 423 bsic any</span><br><span style="color: hsl(120, 100%, 40%);">+% BTS 0 to ARFCN 423 (any BSIC) now has 1 remote BSS Cell Identifier List entry</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# neighbor add lac-ci 789 10 arfcn 423 bsic9 511</span><br><span style="color: hsl(120, 100%, 40%);">+% BTS 0 to ARFCN 423 BSIC 511(9bit) now has 1 remote BSS Cell Identifier List entry</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# neighbor add lac-ci 789 10 arfcn 423 bsic9 1</span><br><span style="color: hsl(120, 100%, 40%);">+% BTS 0 to ARFCN 423 BSIC 1(9bit) now has 1 remote BSS Cell Identifier List entry</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# neighbor add lac-ci 789 10 arfcn 423 bsic 1</span><br><span style="color: hsl(120, 100%, 40%);">+% BTS 0 to ARFCN 423 BSIC 1 now has 1 remote BSS Cell Identifier List entry</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# show running-config</span><br><span style="color: hsl(120, 100%, 40%);">+...</span><br><span style="color: hsl(120, 100%, 40%);">+network</span><br><span style="color: hsl(120, 100%, 40%);">+... !neighbor add</span><br><span style="color: hsl(120, 100%, 40%);">+ bts 0</span><br><span style="color: hsl(120, 100%, 40%);">+... !neighbor add</span><br><span style="color: hsl(120, 100%, 40%);">+  neighbor add lac-ci 21 31</span><br><span style="color: hsl(120, 100%, 40%);">+  neighbor add lac-ci 22 32</span><br><span style="color: hsl(120, 100%, 40%);">+  neighbor add cgi 023 42 423 5 arfcn 23 bsic 42</span><br><span style="color: hsl(120, 100%, 40%);">+  neighbor add cgi 023 042 423 6 arfcn 23 bsic 42</span><br><span style="color: hsl(120, 100%, 40%);">+  neighbor add cgi 023 042 234 56 arfcn 23 bsic 42</span><br><span style="color: hsl(120, 100%, 40%);">+  neighbor add lac 456 arfcn 123 bsic 45</span><br><span style="color: hsl(120, 100%, 40%);">+  neighbor add lac-ci 789 10 arfcn 423 bsic any</span><br><span style="color: hsl(120, 100%, 40%);">+  neighbor add lac-ci 789 10 arfcn 423 bsic9 511</span><br><span style="color: hsl(120, 100%, 40%);">+  neighbor add lac-ci 789 10 arfcn 423 bsic9 1</span><br><span style="color: hsl(120, 100%, 40%);">+  neighbor add lac-ci 789 10 arfcn 423 bsic 1</span><br><span style="color: hsl(120, 100%, 40%);">+... !neighbor add</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# neighbor resolve arfcn 99 bsic any</span><br><span style="color: hsl(120, 100%, 40%);">+% No entry for BTS 0 to ARFCN 99 (any BSIC)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# neighbor resolve arfcn 41 bsic any</span><br><span style="color: hsl(120, 100%, 40%);">+% BTS 0 to ARFCN 41 (any BSIC) resolves to local BTS 1 lac-ci 21 31</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# neighbor resolve arfcn 423 bsic 1</span><br><span style="color: hsl(120, 100%, 40%);">+% neighbor add lac-ci 789 10 arfcn 423 bsic 1</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# neighbor resolve arfcn 423 bsic 23</span><br><span style="color: hsl(120, 100%, 40%);">+% neighbor add lac-ci 789 10 arfcn 423 bsic 23</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# neighbor del arfcn 99 bsic 7</span><br><span style="color: hsl(120, 100%, 40%);">+% Cannot remove, no such neighbor: BTS 0 to ARFCN 99 BSIC 7</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# neighbor del arfcn 23 bsic 42</span><br><span style="color: hsl(120, 100%, 40%);">+% Removed remote BSS neighbor BTS 0 to ARFCN 23 BSIC 42</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# show running-config</span><br><span style="color: hsl(120, 100%, 40%);">+... !neighbor add</span><br><span style="color: hsl(120, 100%, 40%);">+  neighbor add lac-ci 21 31</span><br><span style="color: hsl(120, 100%, 40%);">+  neighbor add lac-ci 22 32</span><br><span style="color: hsl(120, 100%, 40%);">+  neighbor add lac 456 arfcn 123 bsic 45</span><br><span style="color: hsl(120, 100%, 40%);">+  neighbor add lac-ci 789 10 arfcn 423 bsic any</span><br><span style="color: hsl(120, 100%, 40%);">+  neighbor add lac-ci 789 10 arfcn 423 bsic9 511</span><br><span style="color: hsl(120, 100%, 40%);">+  neighbor add lac-ci 789 10 arfcn 423 bsic9 1</span><br><span style="color: hsl(120, 100%, 40%);">+  neighbor add lac-ci 789 10 arfcn 423 bsic 1</span><br><span style="color: hsl(120, 100%, 40%);">+... !neighbor add</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# neighbor del arfcn 123 bsic 45</span><br><span style="color: hsl(120, 100%, 40%);">+% Removed remote BSS neighbor BTS 0 to ARFCN 123 BSIC 45</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# show running-config</span><br><span style="color: hsl(120, 100%, 40%);">+... !neighbor add</span><br><span style="color: hsl(120, 100%, 40%);">+  neighbor add lac-ci 21 31</span><br><span style="color: hsl(120, 100%, 40%);">+  neighbor add lac-ci 22 32</span><br><span style="color: hsl(120, 100%, 40%);">+  neighbor add lac-ci 789 10 arfcn 423 bsic any</span><br><span style="color: hsl(120, 100%, 40%);">+  neighbor add lac-ci 789 10 arfcn 423 bsic9 511</span><br><span style="color: hsl(120, 100%, 40%);">+  neighbor add lac-ci 789 10 arfcn 423 bsic9 1</span><br><span style="color: hsl(120, 100%, 40%);">+  neighbor add lac-ci 789 10 arfcn 423 bsic 1</span><br><span style="color: hsl(120, 100%, 40%);">+... !neighbor add</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# neighbor del arfcn 423 bsic any</span><br><span style="color: hsl(120, 100%, 40%);">+% Removed remote BSS neighbor BTS 0 to ARFCN 423 (any BSIC)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# show running-config</span><br><span style="color: hsl(120, 100%, 40%);">+... !neighbor add</span><br><span style="color: hsl(120, 100%, 40%);">+  neighbor add lac-ci 21 31</span><br><span style="color: hsl(120, 100%, 40%);">+  neighbor add lac-ci 22 32</span><br><span style="color: hsl(120, 100%, 40%);">+  neighbor add lac-ci 789 10 arfcn 423 bsic9 511</span><br><span style="color: hsl(120, 100%, 40%);">+  neighbor add lac-ci 789 10 arfcn 423 bsic9 1</span><br><span style="color: hsl(120, 100%, 40%);">+  neighbor add lac-ci 789 10 arfcn 423 bsic 1</span><br><span style="color: hsl(120, 100%, 40%);">+... !neighbor add</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# neighbor del arfcn 423 bsic9 511</span><br><span style="color: hsl(120, 100%, 40%);">+% Removed remote BSS neighbor BTS 0 to ARFCN 423 BSIC 511(9bit)</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# neighbor del arfcn 423 bsic9 1</span><br><span style="color: hsl(120, 100%, 40%);">+% Removed remote BSS neighbor BTS 0 to ARFCN 423 BSIC 1(9bit)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# show running-config</span><br><span style="color: hsl(120, 100%, 40%);">+... !neighbor add</span><br><span style="color: hsl(120, 100%, 40%);">+  neighbor add lac-ci 21 31</span><br><span style="color: hsl(120, 100%, 40%);">+  neighbor add lac-ci 22 32</span><br><span style="color: hsl(120, 100%, 40%);">+  neighbor add lac-ci 789 10 arfcn 423 bsic 1</span><br><span style="color: hsl(120, 100%, 40%);">+... !neighbor add</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# neighbor del arfcn 423 bsic 1</span><br><span style="color: hsl(120, 100%, 40%);">+% Removed remote BSS neighbor BTS 0 to ARFCN 423 BSIC 1</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# show running-config</span><br><span style="color: hsl(120, 100%, 40%);">+... !neighbor add</span><br><span style="color: hsl(120, 100%, 40%);">+  neighbor add lac-ci 21 31</span><br><span style="color: hsl(120, 100%, 40%);">+  neighbor add lac-ci 22 32</span><br><span style="color: hsl(120, 100%, 40%);">+... !neighbor add</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# neighbor del arfcn 41 bsic any</span><br><span style="color: hsl(120, 100%, 40%);">+% Removed local neighbor bts 0 to bts 1</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# show running-config</span><br><span style="color: hsl(120, 100%, 40%);">+... !neighbor add</span><br><span style="color: hsl(120, 100%, 40%);">+  neighbor add lac-ci 22 32</span><br><span style="color: hsl(120, 100%, 40%);">+... !neighbor add</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# neighbor del arfcn 41 bsic any</span><br><span style="color: hsl(120, 100%, 40%);">+% Cannot remove, no such neighbor: BTS 0 to ARFCN 41 (any BSIC)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# show running-config</span><br><span style="color: hsl(120, 100%, 40%);">+... !neighbor add</span><br><span style="color: hsl(120, 100%, 40%);">+  neighbor add lac-ci 22 32</span><br><span style="color: hsl(120, 100%, 40%);">+... !neighbor add</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# neighbor del arfcn 42 bsic 12</span><br><span style="color: hsl(120, 100%, 40%);">+% Removed local neighbor bts 0 to bts 2</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# show running-config</span><br><span style="color: hsl(120, 100%, 40%);">+... !neighbor add</span><br><span>diff --git a/tests/testsuite.at b/tests/testsuite.at</span><br><span>index 515ffa0..aba4a0c 100644</span><br><span>--- a/tests/testsuite.at</span><br><span>+++ b/tests/testsuite.at</span><br><span>@@ -32,6 +32,13 @@</span><br><span> AT_CHECK([$abs_top_builddir/tests/nanobts_omlattr/nanobts_omlattr_test], [], [expout], [ignore])</span><br><span> AT_CLEANUP</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+AT_SETUP([neighbor_ident])</span><br><span style="color: hsl(120, 100%, 40%);">+AT_KEYWORDS([neighbor_ident])</span><br><span style="color: hsl(120, 100%, 40%);">+cat $abs_srcdir/handover/neighbor_ident_test.ok > expout</span><br><span style="color: hsl(120, 100%, 40%);">+cat $abs_srcdir/handover/neighbor_ident_test.err > experr</span><br><span style="color: hsl(120, 100%, 40%);">+AT_CHECK([$abs_top_builddir/tests/handover/neighbor_ident_test], [], [expout], [experr])</span><br><span style="color: hsl(120, 100%, 40%);">+AT_CLEANUP</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> AT_SETUP([handover test 0])</span><br><span> AT_KEYWORDS([handover])</span><br><span> cat $abs_srcdir/handover/handover_test.ok > expout</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/9666">change 9666</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/9666"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmo-bsc </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>
<div style="display:none"> Gerrit-Change-Id: I0153d7069817fba9146ddc11214de2757d7d37bf </div>
<div style="display:none"> Gerrit-Change-Number: 9666 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Neels Hofmeyr <nhofmeyr@sysmocom.de> </div>