<p>Neels Hofmeyr has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/11128">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">neighbor vty: identify neighbors by gsm0808 cell id<br><br>For deleting neighbor entries and for triggering manual handovers, it is useful<br>to identify neighbors by the gsm0808_cell_id, instead of just by ARFCN+BSIC.<br><br>This is not a hard requirement, since BTS+ARFCN+BSIC fully identifies a<br>neighbor. But consider these contrived examples of the situation before this<br>patch:<br><br> # bts 0<br> # neighbor cgi 001 01 23 42<br> # no neighbor cgi 001 01 23 42<br>   % No such command<br> # no neighbor bts 5<br>   (manually looked up that BTS 5 has above CGI)<br><br> # neighbor lac 42 arfcn 23 bsic 5<br> # do handover any to lac 42<br>   % No such command<br> # do handover any to arfcn 23 bsic 5<br>   (if multiple cells have the same ARFCN+BSIC, the identification is not unique)<br><br>So this fills a gap, if only to help debugging / analyzing handover operations.<br><br>Change-Id: I198fe7055d1e09b128693eb51276e3d8cde1c0ba<br>---<br>M include/osmocom/bsc/gsm_data.h<br>M src/osmo-bsc/Makefile.am<br>M src/osmo-bsc/neighbor_ident_vty.c<br>A src/osmo-bsc/neighbor_iter.c<br>M tests/neighbor_ident.vty<br>5 files changed, 502 insertions(+), 50 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/28/11128/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/osmocom/bsc/gsm_data.h b/include/osmocom/bsc/gsm_data.h</span><br><span>index 33a5a8d..ae65f09 100644</span><br><span>--- a/include/osmocom/bsc/gsm_data.h</span><br><span>+++ b/include/osmocom/bsc/gsm_data.h</span><br><span>@@ -1141,6 +1141,21 @@</span><br><span> int gsm_bts_local_neighbor_add(struct gsm_bts *bts, struct gsm_bts *neighbor);</span><br><span> int gsm_bts_local_neighbor_del(struct gsm_bts *bts, const struct gsm_bts *neighbor);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+typedef bool (*neighbors_find_by_cell_id_cb_t)(struct gsm_bts *from_bts,</span><br><span style="color: hsl(120, 100%, 40%);">+                                             struct gsm_bts *neighbor_bts,</span><br><span style="color: hsl(120, 100%, 40%);">+                                         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%);">+                                              int val_idx,</span><br><span style="color: hsl(120, 100%, 40%);">+                                          void *cb_data);</span><br><span style="color: hsl(120, 100%, 40%);">+int neighbors_find_by_cell_id(struct gsm_network *net,</span><br><span style="color: hsl(120, 100%, 40%);">+                              struct gsm_bts *for_bts,</span><br><span style="color: hsl(120, 100%, 40%);">+                              struct neighbor_ident_list *neighbor_bss_cells,</span><br><span style="color: hsl(120, 100%, 40%);">+                       const struct gsm0808_cell_id *id,</span><br><span style="color: hsl(120, 100%, 40%);">+                             bool remote_neighbors_exact_match,</span><br><span style="color: hsl(120, 100%, 40%);">+                            bool remote_neighbors_all_matches,</span><br><span style="color: hsl(120, 100%, 40%);">+                            neighbors_find_by_cell_id_cb_t cb,</span><br><span style="color: hsl(120, 100%, 40%);">+                            void *cb_data);</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> struct gsm_bts_trx *gsm_bts_trx_num(const struct gsm_bts *bts, int num);</span><br><span> </span><br><span>diff --git a/src/osmo-bsc/Makefile.am b/src/osmo-bsc/Makefile.am</span><br><span>index 364228d..c96ebb5 100644</span><br><span>--- a/src/osmo-bsc/Makefile.am</span><br><span>+++ b/src/osmo-bsc/Makefile.am</span><br><span>@@ -73,6 +73,7 @@</span><br><span>      mgw_endpoint_fsm.c \</span><br><span>         neighbor_ident.c \</span><br><span>   neighbor_ident_vty.c \</span><br><span style="color: hsl(120, 100%, 40%);">+        neighbor_iter.c \</span><br><span>    net_init.c \</span><br><span>         gsm_08_08.c \</span><br><span>        osmo_bsc_bssap.c \</span><br><span>diff --git a/src/osmo-bsc/neighbor_ident_vty.c b/src/osmo-bsc/neighbor_ident_vty.c</span><br><span>index 409153b..1dbced8 100644</span><br><span>--- a/src/osmo-bsc/neighbor_ident_vty.c</span><br><span>+++ b/src/osmo-bsc/neighbor_ident_vty.c</span><br><span>@@ -86,6 +86,13 @@</span><br><span> #define LOCAL_BTS_PARAMS "bts <0-255>"</span><br><span> #define LOCAL_BTS_DOC "Neighbor cell by local BTS number\n" "BTS number\n"</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#define SHOW_BTS_PARAMS "show " LOCAL_BTS_PARAMS</span><br><span style="color: hsl(120, 100%, 40%);">+#define SHOW_BTS_DOC SHOW_STR "Display information about a BTS\n" "BTS number\n"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define SHOW_BTS_NEIGHBOR_PARAMS SHOW_BTS_PARAMS " neighbor"</span><br><span style="color: hsl(120, 100%, 40%);">+#define SHOW_BTS_NEIGHBOR_DOC SHOW_BTS_DOC \</span><br><span style="color: hsl(120, 100%, 40%);">+      "List this cell's neighbors matching the given criteria\n"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static struct gsm_bts *neighbor_ident_vty_parse_bts_nr(struct vty *vty, const char **argv)</span><br><span> {</span><br><span>      const char *bts_nr_str = argv[0];</span><br><span>@@ -186,7 +193,7 @@</span><br><span>      return CMD_SUCCESS;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static int del_local_bts(struct vty *vty, struct gsm_bts *neigh)</span><br><span style="color: hsl(120, 100%, 40%);">+static int del_local_bts_neighbor(struct vty *vty, struct gsm_bts *neigh)</span><br><span> {</span><br><span>         int rc;</span><br><span>      struct gsm_bts *bts = vty->index;</span><br><span>@@ -211,12 +218,123 @@</span><br><span>                        neigh->nr, bts->nr, strerror(-rc), VTY_NEWLINE);</span><br><span>               return CMD_WARNING;</span><br><span>  }</span><br><span style="color: hsl(0, 100%, 40%);">-       if (rc == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+  if (rc == 0) {</span><br><span>               vty_out(vty, "%% BTS %u is no neighbor of BTS %u%s",</span><br><span>                       neigh->nr, 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%);">+     vty_out(vty, "%% Removed from BTS %u local neighbor BTS %u%s", bts->nr, neigh->nr, VTY_NEWLINE);</span><br><span>     return CMD_SUCCESS;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static int del_remote_neighbor(struct vty *vty, 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%);">+    vty_out(vty, "%% Removing remote neighbor: %s %s%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                neighbor_ident_key_name(key),</span><br><span style="color: hsl(120, 100%, 40%);">+         gsm0808_cell_id_list_name(val),</span><br><span style="color: hsl(120, 100%, 40%);">+               VTY_NEWLINE);</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, "%% Error: removing neighbor failed%s", VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+          return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+     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%);">+struct del_local_or_remote_neighbor_iter_data {</span><br><span style="color: hsl(120, 100%, 40%);">+     struct vty *vty;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gsm_bts *bts;</span><br><span style="color: hsl(120, 100%, 40%);">+  const struct gsm0808_cell_id *id;</span><br><span style="color: hsl(120, 100%, 40%);">+     int count_local;</span><br><span style="color: hsl(120, 100%, 40%);">+      int count_remote;</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 del_local_or_remote_neighbor_iter_cb_count(struct gsm_bts *from_bts,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                    struct gsm_bts *neighbor_bts,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                 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%);">+                                                      int val_idx,</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 del_local_or_remote_neighbor_iter_data *d = cb_data;</span><br><span style="color: hsl(120, 100%, 40%);">+   if (neighbor_bts)</span><br><span style="color: hsl(120, 100%, 40%);">+             d->count_local++;</span><br><span style="color: hsl(120, 100%, 40%);">+  else</span><br><span style="color: hsl(120, 100%, 40%);">+          d->count_remote++;</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%);">+static bool del_local_or_remote_neighbor_iter_cb_list(struct gsm_bts *from_bts,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                  struct gsm_bts *neighbor_bts,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                 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%);">+                                                      int val_idx,</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 del_local_or_remote_neighbor_iter_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%);">+  if (neighbor_bts)</span><br><span style="color: hsl(120, 100%, 40%);">+             vty_out(vty, "%% BTS %u has local neighbor BTS %u%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                       d->bts->nr, neighbor_bts->nr, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+  else</span><br><span style="color: hsl(120, 100%, 40%);">+          vty_out(vty, "%% Remote neighbor %s %s%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                  neighbor_ident_key_name(key),</span><br><span style="color: hsl(120, 100%, 40%);">+                 gsm0808_cell_id_list_name(val), VTY_NEWLINE);</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%);">+static bool del_local_or_remote_neighbor_iter_cb_del(struct gsm_bts *from_bts,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                  struct gsm_bts *neighbor_bts,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                 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%);">+                                              int val_idx,</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 del_local_or_remote_neighbor_iter_data *d = cb_data;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (neighbor_bts)</span><br><span style="color: hsl(120, 100%, 40%);">+             del_local_bts_neighbor(d->vty, neighbor_bts);</span><br><span style="color: hsl(120, 100%, 40%);">+      else</span><br><span style="color: hsl(120, 100%, 40%);">+          del_remote_neighbor(d->vty, key, 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%);">+static int del_local_or_remote_neighbor(struct vty *vty, const struct gsm0808_cell_id *id,</span><br><span style="color: hsl(120, 100%, 40%);">+                                 bool allow_multiple_matches)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct del_local_or_remote_neighbor_iter_data d = {</span><br><span style="color: hsl(120, 100%, 40%);">+           .vty = vty,</span><br><span style="color: hsl(120, 100%, 40%);">+           .bts = vty->index,</span><br><span style="color: hsl(120, 100%, 40%);">+         .id = id,</span><br><span style="color: hsl(120, 100%, 40%);">+     };</span><br><span style="color: hsl(120, 100%, 40%);">+    int total;</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%);">+         d.bts = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       neighbors_find_by_cell_id(g_net, d.bts, g_neighbor_cells, id, true, true,</span><br><span style="color: hsl(120, 100%, 40%);">+                               del_local_or_remote_neighbor_iter_cb_count, &d);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      total = d.count_local + d.count_remote;</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!total) {</span><br><span style="color: hsl(120, 100%, 40%);">+         vty_out(vty, "%% No matching neighbor%s", VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+             return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (total > 1 && !allow_multiple_matches) {</span><br><span style="color: hsl(120, 100%, 40%);">+                vty_out(vty, "%% More than one match found:%s", VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+               neighbors_find_by_cell_id(g_net, d.bts, g_neighbor_cells, id, true, true,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       del_local_or_remote_neighbor_iter_cb_list,</span><br><span style="color: hsl(120, 100%, 40%);">+                                    &d);</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%);">+   total = neighbors_find_by_cell_id(g_net, d.bts, g_neighbor_cells, id, true, true,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       del_local_or_remote_neighbor_iter_cb_del, &d);</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%);">+</span><br><span> DEFUN(cfg_neighbor_add_bts_nr, cfg_neighbor_add_bts_nr_cmd,</span><br><span>    NEIGHBOR_ADD_CMD LOCAL_BTS_PARAMS,</span><br><span>   NEIGHBOR_ADD_DOC LOCAL_BTS_DOC)</span><br><span>@@ -342,7 +460,7 @@</span><br><span>                        continue;</span><br><span>            rc = gsm_bts_local_neighbor_del(bts, neigh->bts);</span><br><span>                 if (rc > 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-                        vty_out(vty, "%% Removed local neighbor bts %u to bts %u%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                        vty_out(vty, "%% Removed from BTS %u local neighbor BTS %u%s",</span><br><span>                             bts->nr, neigh_bts->nr, VTY_NEWLINE);</span><br><span>                  removed += rc;</span><br><span>               }</span><br><span>@@ -405,7 +523,7 @@</span><br><span>      NEIGHBOR_DEL_CMD LOCAL_BTS_PARAMS,</span><br><span>   NEIGHBOR_DEL_DOC LOCAL_BTS_DOC)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-    return del_local_bts(vty, neighbor_ident_vty_parse_bts_nr(vty, argv));</span><br><span style="color: hsl(120, 100%, 40%);">+        return del_local_bts_neighbor(vty, neighbor_ident_vty_parse_bts_nr(vty, argv));</span><br><span> }</span><br><span> </span><br><span> DEFUN(cfg_neighbor_del_arfcn_bsic, cfg_neighbor_del_arfcn_bsic_cmd,</span><br><span>@@ -420,12 +538,76 @@</span><br><span>      return del_by_key(vty, &key);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(cfg_neighbor_del_lac, cfg_neighbor_del_lac_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+     NEIGHBOR_DEL_CMD LAC_PARAMS,</span><br><span style="color: hsl(120, 100%, 40%);">+  NEIGHBOR_DEL_DOC LAC_DOC)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  return del_local_or_remote_neighbor(vty, neighbor_ident_vty_parse_lac(vty, argv), 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%);">+DEFUN(cfg_neighbor_del_lac_ci, cfg_neighbor_del_lac_ci_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+   NEIGHBOR_DEL_CMD LAC_CI_PARAMS,</span><br><span style="color: hsl(120, 100%, 40%);">+       NEIGHBOR_DEL_DOC LAC_CI_DOC)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       return del_local_or_remote_neighbor(vty, neighbor_ident_vty_parse_lac(vty, argv), 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%);">+DEFUN(cfg_neighbor_del_cgi, cfg_neighbor_del_cgi_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+ NEIGHBOR_DEL_CMD CGI_PARAMS,</span><br><span style="color: hsl(120, 100%, 40%);">+  NEIGHBOR_DEL_DOC CGI_DOC)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  return del_local_or_remote_neighbor(vty, neighbor_ident_vty_parse_lac(vty, argv), 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> struct write_neighbor_ident_entry_data {</span><br><span>         struct vty *vty;</span><br><span>     const char *indent;</span><br><span>  struct gsm_bts *bts;</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static void write_neighbor_ident_list_entry(struct vty *vty,</span><br><span style="color: hsl(120, 100%, 40%);">+                                      const char *indent,</span><br><span style="color: hsl(120, 100%, 40%);">+                                           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%);">+                                      int idx)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       if (idx >= val->id_list_len)</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%);">+#define NEIGH_BSS_WRITE(fmt, args...) do { \</span><br><span style="color: hsl(120, 100%, 40%);">+               vty_out(vty, "%sneighbor " fmt " arfcn %u ", indent, ## args, key->arfcn); \</span><br><span style="color: hsl(120, 100%, 40%);">+           if (key->bsic == BSIC_ANY) \</span><br><span style="color: hsl(120, 100%, 40%);">+                       vty_out(vty, "bsic any"); \</span><br><span style="color: hsl(120, 100%, 40%);">+         else \</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%);">+         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%);">+          NEIGH_BSS_WRITE("lac %u", val->id_list[idx].lac);</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%);">+           NEIGH_BSS_WRITE("lac-ci %u %u",</span><br><span style="color: hsl(120, 100%, 40%);">+                             val->id_list[idx].lac_and_ci.lac,</span><br><span style="color: hsl(120, 100%, 40%);">+                          val->id_list[idx].lac_and_ci.ci);</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%);">+         {</span><br><span style="color: hsl(120, 100%, 40%);">+                     const struct osmo_cell_global_id *cgi = &val->id_list[idx].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 type: %d%s", val->id_discr, 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%);">+</span><br><span> static bool write_neighbor_ident_list(const struct neighbor_ident_key *key,</span><br><span>                                      const struct gsm0808_cell_id_list2 *val,</span><br><span>                                     void *cb_data)</span><br><span>@@ -440,42 +622,9 @@</span><br><span>  } else if (key->from_bts != NEIGHBOR_IDENT_KEY_ANY_BTS)</span><br><span>                   return true;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-#define NEIGH_BSS_WRITE(fmt, args...) do { \</span><br><span style="color: hsl(0, 100%, 40%);">-            vty_out(vty, "%sneighbor " fmt " arfcn %u ", d->indent, ## args, key->arfcn); \</span><br><span style="color: hsl(0, 100%, 40%);">-               if (key->bsic == BSIC_ANY) \</span><br><span style="color: hsl(0, 100%, 40%);">-                 vty_out(vty, "bsic any"); \</span><br><span style="color: hsl(0, 100%, 40%);">-           else \</span><br><span style="color: hsl(0, 100%, 40%);">-                  vty_out(vty, "bsic %u", key->bsic & 0x3f); \</span><br><span style="color: hsl(0, 100%, 40%);">-           vty_out(vty, "%s", VTY_NEWLINE); \</span><br><span style="color: hsl(0, 100%, 40%);">-    } while(0)</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-      switch (val->id_discr) {</span><br><span style="color: hsl(0, 100%, 40%);">-     case CELL_IDENT_LAC:</span><br><span style="color: hsl(0, 100%, 40%);">-            for (i = 0; i < val->id_list_len; i++) {</span><br><span style="color: hsl(0, 100%, 40%);">-                  NEIGH_BSS_WRITE("lac %u", val->id_list[i].lac);</span><br><span style="color: hsl(0, 100%, 40%);">-            }</span><br><span style="color: hsl(0, 100%, 40%);">-               break;</span><br><span style="color: hsl(0, 100%, 40%);">-  case CELL_IDENT_LAC_AND_CI:</span><br><span style="color: hsl(0, 100%, 40%);">-             for (i = 0; i < val->id_list_len; i++) {</span><br><span style="color: hsl(0, 100%, 40%);">-                  NEIGH_BSS_WRITE("lac-ci %u %u",</span><br><span style="color: hsl(0, 100%, 40%);">-                                       val->id_list[i].lac_and_ci.lac,</span><br><span style="color: hsl(0, 100%, 40%);">-                                      val->id_list[i].lac_and_ci.ci);</span><br><span style="color: hsl(0, 100%, 40%);">-              }</span><br><span style="color: hsl(0, 100%, 40%);">-               break;</span><br><span style="color: hsl(0, 100%, 40%);">-  case CELL_IDENT_WHOLE_GLOBAL:</span><br><span style="color: hsl(0, 100%, 40%);">-           for (i = 0; i < val->id_list_len; i++) {</span><br><span style="color: hsl(0, 100%, 40%);">-                  const struct osmo_cell_global_id *cgi = &val->id_list[i].global;</span><br><span style="color: hsl(0, 100%, 40%);">-                 NEIGH_BSS_WRITE("cgi %s %s %u %u",</span><br><span style="color: hsl(0, 100%, 40%);">-                                    osmo_mcc_name(cgi->lai.plmn.mcc),</span><br><span style="color: hsl(0, 100%, 40%);">-                                    osmo_mnc_name(cgi->lai.plmn.mnc, cgi->lai.plmn.mnc_3_digits),</span><br><span style="color: hsl(0, 100%, 40%);">-                                     cgi->lai.lac, cgi->cell_identity);</span><br><span style="color: hsl(0, 100%, 40%);">-                }</span><br><span style="color: hsl(0, 100%, 40%);">-               break;</span><br><span style="color: hsl(0, 100%, 40%);">-  default:</span><br><span style="color: hsl(0, 100%, 40%);">-                vty_out(vty, "%% Unsupported Cell Identity%s", VTY_NEWLINE);</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%);">+                write_neighbor_ident_list_entry(vty, d->indent, key, val, i);</span><br><span>     }</span><br><span style="color: hsl(0, 100%, 40%);">-#undef NEIGH_BSS_WRITE</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>      return true;</span><br><span> }</span><br><span> </span><br><span>@@ -490,12 +639,17 @@</span><br><span>        neighbor_ident_iter(g_neighbor_cells, write_neighbor_ident_list, &d);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+void neighbor_ident_vty_write_local_neighbor(struct vty *vty, const char *indent, struct gsm_bts *neighbor_bts)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        vty_out(vty, "%sneighbor bts %u%s", indent, neighbor_bts->nr, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> void neighbor_ident_vty_write_local_neighbors(struct vty *vty, const char *indent, struct gsm_bts *bts)</span><br><span> {</span><br><span>        struct gsm_bts_ref *neigh;</span><br><span> </span><br><span>       llist_for_each_entry(neigh, &bts->local_neighbors, entry) {</span><br><span style="color: hsl(0, 100%, 40%);">-              vty_out(vty, "%sneighbor bts %u%s", indent, neigh->bts->nr, VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+             neighbor_ident_vty_write_local_neighbor(vty, indent, neigh->bts);</span><br><span>         }</span><br><span> }</span><br><span> </span><br><span>@@ -505,11 +659,25 @@</span><br><span>   neighbor_ident_vty_write_remote_bss(vty, indent, bts);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-DEFUN(show_bts_neighbor, show_bts_neighbor_cmd,</span><br><span style="color: hsl(0, 100%, 40%);">-      "show bts <0-255> neighbor " NEIGHBOR_IDENT_VTY_KEY_PARAMS,</span><br><span style="color: hsl(0, 100%, 40%);">-      SHOW_STR "Display information about a BTS\n" "BTS number\n"</span><br><span style="color: hsl(0, 100%, 40%);">-      "Query which cell would be the target for this neighbor ARFCN+BSIC\n"</span><br><span style="color: hsl(0, 100%, 40%);">-      NEIGHBOR_IDENT_VTY_KEY_DOC)</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(show_bts_neighbor_all, show_bts_neighbor_all_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      SHOW_BTS_NEIGHBOR_PARAMS " all",</span><br><span style="color: hsl(120, 100%, 40%);">+      SHOW_BTS_NEIGHBOR_DOC "List all neighbors\n")</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct gsm_bts *bts = gsm_bts_num(g_net, atoi(argv[0]));</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 find BTS '%s'%s", argv[0],</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%);">+   neighbor_ident_vty_write(vty, "% ", bts);</span><br><span style="color: hsl(120, 100%, 40%);">+   return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(show_bts_neighbor_arfcn, show_bts_neighbor_arfcn_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      SHOW_BTS_NEIGHBOR_PARAMS " " NEIGHBOR_IDENT_VTY_KEY_PARAMS,</span><br><span style="color: hsl(120, 100%, 40%);">+      SHOW_BTS_NEIGHBOR_DOC NEIGHBOR_IDENT_VTY_KEY_DOC)</span><br><span> {</span><br><span>     int found = 0;</span><br><span>       struct neighbor_ident_key key;</span><br><span>@@ -553,6 +721,57 @@</span><br><span>        return CMD_SUCCESS;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static bool show_neighbor_by_cell_id_cb(struct gsm_bts *from_bts,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       struct gsm_bts *neighbor_bts,</span><br><span style="color: hsl(120, 100%, 40%);">+                                 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%);">+                                      int val_idx,</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 vty *vty = cb_data;</span><br><span style="color: hsl(120, 100%, 40%);">+    if (neighbor_bts)</span><br><span style="color: hsl(120, 100%, 40%);">+             neighbor_ident_vty_write_local_neighbor(vty, "% ", neighbor_bts);</span><br><span style="color: hsl(120, 100%, 40%);">+   else</span><br><span style="color: hsl(120, 100%, 40%);">+          write_neighbor_ident_list_entry(vty, "% ", key, val, val_idx);</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%);">+static int show_neighbor_by_cell_id(struct vty *vty, const char **argv, const struct gsm0808_cell_id *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_num(g_net, atoi(argv[0]));</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 find BTS '%s'%s", argv[0],</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%);">+   neighbors_find_by_cell_id(g_net, bts, g_neighbor_cells, id, false, true,</span><br><span style="color: hsl(120, 100%, 40%);">+                                show_neighbor_by_cell_id_cb, vty);</span><br><span style="color: hsl(120, 100%, 40%);">+  return CMD_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(show_bts_neighbor_lac, show_bts_neighbor_lac_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      SHOW_BTS_NEIGHBOR_PARAMS " " LAC_PARAMS,</span><br><span style="color: hsl(120, 100%, 40%);">+      SHOW_BTS_NEIGHBOR_DOC LAC_DOC)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  return show_neighbor_by_cell_id(vty, argv, neighbor_ident_vty_parse_lac(vty, &argv[1]));</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(show_bts_neighbor_lac_ci, show_bts_neighbor_lac_ci_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      SHOW_BTS_NEIGHBOR_PARAMS " " LAC_CI_PARAMS,</span><br><span style="color: hsl(120, 100%, 40%);">+      SHOW_BTS_NEIGHBOR_DOC LAC_CI_DOC)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     return show_neighbor_by_cell_id(vty, argv, neighbor_ident_vty_parse_lac_ci(vty, &argv[1]));</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+DEFUN(show_bts_neighbor_cgi, show_bts_neighbor_cgi_cmd,</span><br><span style="color: hsl(120, 100%, 40%);">+      SHOW_BTS_NEIGHBOR_PARAMS " " CGI_PARAMS,</span><br><span style="color: hsl(120, 100%, 40%);">+      SHOW_BTS_NEIGHBOR_DOC CGI_DOC)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      return show_neighbor_by_cell_id(vty, argv, neighbor_ident_vty_parse_cgi(vty, &argv[1]));</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> void neighbor_ident_vty_init(struct gsm_network *net, struct neighbor_ident_list *nil)</span><br><span> {</span><br><span>     g_net = net;</span><br><span>@@ -566,5 +785,12 @@</span><br><span>  install_element(BTS_NODE, &cfg_neighbor_add_cgi_arfcn_bsic_cmd);</span><br><span>         install_element(BTS_NODE, &cfg_neighbor_del_bts_nr_cmd);</span><br><span>         install_element(BTS_NODE, &cfg_neighbor_del_arfcn_bsic_cmd);</span><br><span style="color: hsl(0, 100%, 40%);">-        install_element_ve(&show_bts_neighbor_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+       install_element(BTS_NODE, &cfg_neighbor_del_lac_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+     install_element(BTS_NODE, &cfg_neighbor_del_lac_ci_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+  install_element(BTS_NODE, &cfg_neighbor_del_cgi_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+     install_element_ve(&show_bts_neighbor_all_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+   install_element_ve(&show_bts_neighbor_arfcn_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+ install_element_ve(&show_bts_neighbor_lac_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+   install_element_ve(&show_bts_neighbor_lac_ci_cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+        install_element_ve(&show_bts_neighbor_cgi_cmd);</span><br><span> }</span><br><span>diff --git a/src/osmo-bsc/neighbor_iter.c b/src/osmo-bsc/neighbor_iter.c</span><br><span>new file mode 100644</span><br><span>index 0000000..7980773</span><br><span>--- /dev/null</span><br><span>+++ b/src/osmo-bsc/neighbor_iter.c</span><br><span>@@ -0,0 +1,152 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* Copyright (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 <neels@hofmeyr.de></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%);">+ * 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%);">+/* This file implements iteration of both local and remote neighbors, which has dependencies to both</span><br><span style="color: hsl(120, 100%, 40%);">+ * gsm_data.c as well as neighbor_ident.c. Placing this in gsm_data.c would require various tools to</span><br><span style="color: hsl(120, 100%, 40%);">+ * include the neighbor_ident.c implementations. In turn, neighbor_ident.c is gsm_data.c agnostic. */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/gsm_data.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%);">+static int bts_local_neighbors_find_by_cell_id(struct gsm_bts *for_bts,</span><br><span style="color: hsl(120, 100%, 40%);">+                                          const struct gsm0808_cell_id *id,</span><br><span style="color: hsl(120, 100%, 40%);">+                                             neighbors_find_by_cell_id_cb_t cb,</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%);">+      int count = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct gsm_bts_ref *ref, *ref_next;</span><br><span style="color: hsl(120, 100%, 40%);">+   llist_for_each_entry_safe(ref, ref_next, &for_bts->local_neighbors, entry) {</span><br><span style="color: hsl(120, 100%, 40%);">+           if (!id || gsm_bts_matches_cell_id(ref->bts, id)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        if (cb)</span><br><span style="color: hsl(120, 100%, 40%);">+                               cb(for_bts, ref->bts, NULL, NULL, -1, cb_data);</span><br><span style="color: hsl(120, 100%, 40%);">+                    count ++;</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 count;</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 all_local_neighbors_find_by_cell_id(struct gsm_network *net,</span><br><span style="color: hsl(120, 100%, 40%);">+                                          const struct gsm0808_cell_id *id,</span><br><span style="color: hsl(120, 100%, 40%);">+                                             neighbors_find_by_cell_id_cb_t cb,</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 gsm_bts *bts, *bts_next;</span><br><span style="color: hsl(120, 100%, 40%);">+       int count = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+        llist_for_each_entry_safe(bts, bts_next, &net->bts_list, list) {</span><br><span style="color: hsl(120, 100%, 40%);">+               count += bts_local_neighbors_find_by_cell_id(bts, id, cb, cb_data);</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+     return count;</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 neighbors_find_by_cell_id_iter_cb_data {</span><br><span style="color: hsl(120, 100%, 40%);">+   struct gsm_network *net;</span><br><span style="color: hsl(120, 100%, 40%);">+      const struct gsm0808_cell_id *id;</span><br><span style="color: hsl(120, 100%, 40%);">+     bool all_matches;</span><br><span style="color: hsl(120, 100%, 40%);">+     neighbors_find_by_cell_id_cb_t cb;</span><br><span style="color: hsl(120, 100%, 40%);">+    void *cb_data;</span><br><span style="color: hsl(120, 100%, 40%);">+        int count;</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 neighbors_find_by_cell_id_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 neighbors_find_by_cell_id_iter_cb_data *d = cb_data;</span><br><span style="color: hsl(120, 100%, 40%);">+   unsigned int match_nr;</span><br><span style="color: hsl(120, 100%, 40%);">+        int match_idx;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      for (match_nr = 0; ; match_nr ++) {</span><br><span style="color: hsl(120, 100%, 40%);">+           /* On mismatch, just continue iterating. */</span><br><span style="color: hsl(120, 100%, 40%);">+           match_idx = gsm0808_cell_id_matches_list(d->id, val, match_nr);</span><br><span style="color: hsl(120, 100%, 40%);">+            if (match_idx < 0)</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! */</span><br><span style="color: hsl(120, 100%, 40%);">+          if (d->cb)</span><br><span style="color: hsl(120, 100%, 40%);">+                 d->cb(d->net ? gsm_bts_num(d->net, key->from_bts) : NULL,</span><br><span style="color: hsl(120, 100%, 40%);">+                       NULL,</span><br><span style="color: hsl(120, 100%, 40%);">+                         key, val,</span><br><span style="color: hsl(120, 100%, 40%);">+                             match_idx,</span><br><span style="color: hsl(120, 100%, 40%);">+                            d->cb_data);</span><br><span style="color: hsl(120, 100%, 40%);">+         d->count ++;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+             /* If neighbors_find_by_cell_id() was invoked with remote_neighbors_all_matches == false,</span><br><span style="color: hsl(120, 100%, 40%);">+              * stop looking after the first match in this list. */</span><br><span style="color: hsl(120, 100%, 40%);">+                if (!d->all_matches)</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%);">+     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%);">+/* Find all neighbors that match a given Cell Identifier.</span><br><span style="color: hsl(120, 100%, 40%);">+ * If 'for_bts' is given, only neighbors for that cell are returned; NULL matches all cells' neighbors.</span><br><span style="color: hsl(120, 100%, 40%);">+ * If 'neighbor_bss_cells' is NULL, no remote neighbors are returned.</span><br><span style="color: hsl(120, 100%, 40%);">+ * If 'id' is NULL, all neighbors are returned. The id restricts the matches, where a CGI type is most</span><br><span style="color: hsl(120, 100%, 40%);">+ * restrictive, and a LAC type might still match a neighbor with LAC+CI or a neighbor with full CGI that</span><br><span style="color: hsl(120, 100%, 40%);">+ * contains this LAC.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Results are returned by calling the cb(). If cb() returns false, further iteration is stopped.</span><br><span style="color: hsl(120, 100%, 40%);">+ * It is safe to remove any neighbor entries, except the neighbor entry *following* the one passed to</span><br><span style="color: hsl(120, 100%, 40%);">+ * cb(), i.e. you may remove the neighbor passed to cb(), but not the adjacent following llist entry.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * With remote_neighbors_exact_match == true, ignore remote-BSS neighbors with a cell id list that have a</span><br><span style="color: hsl(120, 100%, 40%);">+ * CELL_IDENT that differs from the id->id_discr. With false, any matching cell id item counts, e.g. a</span><br><span style="color: hsl(120, 100%, 40%);">+ * LAC of 23 matches a CGI that contains a LAC = 23.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * With remote_neighbors_all_matches == false, return only the first match in each cell id list of a</span><br><span style="color: hsl(120, 100%, 40%);">+ * remote neighbor. With true, cb() will be invoked for each matching val_idx in the given cell id list.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int neighbors_find_by_cell_id(struct gsm_network *net,</span><br><span style="color: hsl(120, 100%, 40%);">+                         struct gsm_bts *for_bts,</span><br><span style="color: hsl(120, 100%, 40%);">+                              struct neighbor_ident_list *neighbor_bss_cells,</span><br><span style="color: hsl(120, 100%, 40%);">+                       const struct gsm0808_cell_id *id,</span><br><span style="color: hsl(120, 100%, 40%);">+                             bool remote_neighbors_exact_match,</span><br><span style="color: hsl(120, 100%, 40%);">+                            bool remote_neighbors_all_matches,</span><br><span style="color: hsl(120, 100%, 40%);">+                            neighbors_find_by_cell_id_cb_t cb,</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%);">+       int count = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* Local neighbors */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (for_bts) {</span><br><span style="color: hsl(120, 100%, 40%);">+                count += bts_local_neighbors_find_by_cell_id(for_bts, id, cb, cb_data);</span><br><span style="color: hsl(120, 100%, 40%);">+               if (!net)</span><br><span style="color: hsl(120, 100%, 40%);">+                     net = for_bts->network;</span><br><span style="color: hsl(120, 100%, 40%);">+    } else if (net)</span><br><span style="color: hsl(120, 100%, 40%);">+               count += all_local_neighbors_find_by_cell_id(net, id, cb, cb_data);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Remote neighbors */</span><br><span style="color: hsl(120, 100%, 40%);">+        if (neighbor_bss_cells) {</span><br><span style="color: hsl(120, 100%, 40%);">+             struct neighbors_find_by_cell_id_iter_cb_data d = {</span><br><span style="color: hsl(120, 100%, 40%);">+                   .net = net,</span><br><span style="color: hsl(120, 100%, 40%);">+                   .id = id,</span><br><span style="color: hsl(120, 100%, 40%);">+                     .all_matches = remote_neighbors_all_matches,</span><br><span style="color: hsl(120, 100%, 40%);">+                  .cb = cb,</span><br><span style="color: hsl(120, 100%, 40%);">+                     .cb_data = cb_data,</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(neighbor_bss_cells,</span><br><span style="color: hsl(120, 100%, 40%);">+                                   neighbors_find_by_cell_id_iter_cb,</span><br><span style="color: hsl(120, 100%, 40%);">+                                    &d);</span><br><span style="color: hsl(120, 100%, 40%);">+          count += d.count;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     return count;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/tests/neighbor_ident.vty b/tests/neighbor_ident.vty</span><br><span>index 4f86383..9e2b100 100644</span><br><span>--- a/tests/neighbor_ident.vty</span><br><span>+++ b/tests/neighbor_ident.vty</span><br><span>@@ -162,8 +162,11 @@</span><br><span>   neighbor  Remove local or remote-BSS neighbor cell</span><br><span> </span><br><span> OsmoBSC(config-net-bts)# no neighbor ?</span><br><span style="color: hsl(0, 100%, 40%);">-  bts    Neighbor cell by local BTS number</span><br><span style="color: hsl(0, 100%, 40%);">-  arfcn  ARFCN of neighbor cell</span><br><span style="color: hsl(120, 100%, 40%);">+  bts     Neighbor cell by local BTS number</span><br><span style="color: hsl(120, 100%, 40%);">+  arfcn   ARFCN of neighbor cell</span><br><span style="color: hsl(120, 100%, 40%);">+  lac     Neighbor cell by LAC</span><br><span style="color: hsl(120, 100%, 40%);">+  lac-ci  Neighbor cell by LAC and CI</span><br><span style="color: hsl(120, 100%, 40%);">+  cgi     Neighbor cell by cgi</span><br><span> </span><br><span> OsmoBSC(config-net-bts)# no neighbor bts ?</span><br><span>   <0-255>  BTS number</span><br><span>@@ -195,10 +198,31 @@</span><br><span> </span><br><span> OsmoBSC(config-net-bts)# neighbor bts 1</span><br><span> % 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%);">+OsmoBSC(config-net-bts)# no neighbor bts 1</span><br><span style="color: hsl(120, 100%, 40%);">+% Removed from BTS 0 local neighbor BTS 1</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# neighbor lac 21</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%);">+OsmoBSC(config-net-bts)# no neighbor lac 21</span><br><span style="color: hsl(120, 100%, 40%);">+% Removed from BTS 0 local neighbor BTS 1</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# neighbor lac-ci 21 31</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%);">+OsmoBSC(config-net-bts)# no neighbor lac-ci 21 31</span><br><span style="color: hsl(120, 100%, 40%);">+% Removed from BTS 0 local neighbor BTS 1</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# neighbor cgi 901 70 21 31</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%);">+OsmoBSC(config-net-bts)# no neighbor cgi 901 70 21 31</span><br><span style="color: hsl(120, 100%, 40%);">+% No matching neighbor</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# neighbor 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> </span><br><span> OsmoBSC(config-net-bts)# neighbor lac 22</span><br><span> % BTS 0 now has local neighbor BTS 2 with LAC 22 CI 65535 and ARFCN 42 BSIC 12</span><br><span> OsmoBSC(config-net-bts)# no neighbor bts 2</span><br><span style="color: hsl(120, 100%, 40%);">+% Removed from BTS 0 local neighbor BTS 2</span><br><span> OsmoBSC(config-net-bts)# neighbor cgi 901 70 22 65535</span><br><span> % BTS 0 now has local neighbor BTS 2 with LAC 22 CI 65535 and ARFCN 42 BSIC 12</span><br><span> </span><br><span>@@ -264,6 +288,40 @@</span><br><span> OsmoBSC(config-net-bts)# do show bts 0 neighbor arfcn 423 bsic 23</span><br><span> % neighbor lac-ci 789 10 arfcn 423 bsic 23</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+OsmoBSC(config-net-bts)# do show bts 0 neighbor all</span><br><span style="color: hsl(120, 100%, 40%);">+% neighbor bts 1</span><br><span style="color: hsl(120, 100%, 40%);">+% neighbor bts 2</span><br><span style="color: hsl(120, 100%, 40%);">+% neighbor cgi 023 42 423 5 arfcn 23 bsic 42</span><br><span style="color: hsl(120, 100%, 40%);">+% neighbor cgi 023 042 423 6 arfcn 23 bsic 42</span><br><span style="color: hsl(120, 100%, 40%);">+% neighbor cgi 023 042 234 56 arfcn 23 bsic 42</span><br><span style="color: hsl(120, 100%, 40%);">+% neighbor lac 456 arfcn 123 bsic 45</span><br><span style="color: hsl(120, 100%, 40%);">+% neighbor lac-ci 789 10 arfcn 423 bsic any</span><br><span style="color: hsl(120, 100%, 40%);">+% neighbor lac-ci 789 10 arfcn 423 bsic 63</span><br><span style="color: hsl(120, 100%, 40%);">+% neighbor 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)# do show bts 0 neighbor cgi 23 42 423 5</span><br><span style="color: hsl(120, 100%, 40%);">+% neighbor cgi 023 42 423 5 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)# do show bts 0 neighbor lac 456</span><br><span style="color: hsl(120, 100%, 40%);">+% neighbor lac 456 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)# do show bts 0 neighbor lac-ci 789 10</span><br><span style="color: hsl(120, 100%, 40%);">+% neighbor lac-ci 789 10 arfcn 423 bsic any</span><br><span style="color: hsl(120, 100%, 40%);">+% neighbor lac-ci 789 10 arfcn 423 bsic 63</span><br><span style="color: hsl(120, 100%, 40%);">+% neighbor 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)# do show bts 0 neighbor lac 789</span><br><span style="color: hsl(120, 100%, 40%);">+% neighbor lac-ci 789 10 arfcn 423 bsic any</span><br><span style="color: hsl(120, 100%, 40%);">+% neighbor lac-ci 789 10 arfcn 423 bsic 63</span><br><span style="color: hsl(120, 100%, 40%);">+% neighbor 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)# do show bts 0 neighbor lac 423</span><br><span style="color: hsl(120, 100%, 40%);">+% neighbor cgi 023 42 423 5 arfcn 23 bsic 42</span><br><span style="color: hsl(120, 100%, 40%);">+% neighbor cgi 023 042 423 6 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)# do show bts 0 neighbor lac-ci 423 6</span><br><span style="color: hsl(120, 100%, 40%);">+% neighbor cgi 023 042 423 6 arfcn 23 bsic 42</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> OsmoBSC(config-net-bts)# no neighbor arfcn 99 bsic 7</span><br><span> % Cannot remove, no such neighbor: BTS 0 to ARFCN 99 BSIC 7</span><br><span> </span><br><span>@@ -323,7 +381,7 @@</span><br><span> ... !neighbor </span><br><span> </span><br><span> OsmoBSC(config-net-bts)# no neighbor arfcn 41 bsic any</span><br><span style="color: hsl(0, 100%, 40%);">-% Removed local neighbor bts 0 to bts 1</span><br><span style="color: hsl(120, 100%, 40%);">+% Removed from BTS 0 local neighbor BTS 1</span><br><span> </span><br><span> OsmoBSC(config-net-bts)# show running-config</span><br><span> ... !neighbor </span><br><span>@@ -339,7 +397,7 @@</span><br><span> ... !neighbor </span><br><span> </span><br><span> OsmoBSC(config-net-bts)# no neighbor arfcn 42 bsic 12</span><br><span style="color: hsl(0, 100%, 40%);">-% Removed local neighbor bts 0 to bts 2</span><br><span style="color: hsl(120, 100%, 40%);">+% Removed from BTS 0 local neighbor BTS 2</span><br><span> </span><br><span> OsmoBSC(config-net-bts)# show running-config</span><br><span> ... !neighbor </span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/11128">change 11128</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/11128"/><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: I198fe7055d1e09b128693eb51276e3d8cde1c0ba </div>
<div style="display:none"> Gerrit-Change-Number: 11128 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Neels Hofmeyr <nhofmeyr@sysmocom.de> </div>