<p>neels has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/osmo-bsc/+/14769">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">neighbor config: allow re-using ARFCN+BSIC pairs<br><br>Fix neighbor config to match OsmoBSC manual: implement the plan for neighbor<br>configuration that was so far only described in the manual without actually<br>being in operation.<br><br>This first allows re-using ARFCN+BSIC pairs in and across BSS.<br><br>So far the handover_start() code always looked for handover target cells across<br>*all* local cells, even if they were not listed as neighbors to a source cell.<br>Imply all cells as neighbors only as long as there are no explicit neighbors<br>configured. As soon as the first 'neighbor' line appears in a 'bts' config,<br>only the listed neighbors are regarded as handover target cells. (The<br>'neighbor-list' commands are not related to this, only the relatively new<br>'neighbor (bts|lac|cgi|...)' commands affect actual handover procedures.)<br><br>TTCN3 tests TC_ho_neighbor_config_1 thru _7 play through the various aspects of<br>neighbor configuration: both the legacy implicit all-cells-are-neighbors as<br>well as allowing only explicit neighbors by config.<br><br>Related: OS#4056<br>Related: osmo-ttcn3-hacks Ia4ba0e75abd3d45a3422b2525e5f938cdc5a04cc<br>Change-Id: I29bca59ab232eddc74e0d4698efb9c9992443983<br>---<br>M include/osmocom/bsc/handover.h<br>M include/osmocom/bsc/handover_fsm.h<br>M include/osmocom/bsc/neighbor_ident.h<br>M src/osmo-bsc/handover_decision_2.c<br>M src/osmo-bsc/handover_fsm.c<br>M src/osmo-bsc/handover_logic.c<br>M src/osmo-bsc/neighbor_ident_vty.c<br>M tests/bsc/bsc_test.c<br>8 files changed, 244 insertions(+), 62 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/69/14769/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/osmocom/bsc/handover.h b/include/osmocom/bsc/handover.h</span><br><span>index 322913d..b00ee60 100644</span><br><span>--- a/include/osmocom/bsc/handover.h</span><br><span>+++ b/include/osmocom/bsc/handover.h</span><br><span>@@ -10,6 +10,15 @@</span><br><span> #include <osmocom/bsc/neighbor_ident.h></span><br><span> #include <osmocom/bsc/gsm_data.h></span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#define LOG_HO(conn, level, fmt, args...) do { \</span><br><span style="color: hsl(120, 100%, 40%);">+ if (conn->ho.fi) \</span><br><span style="color: hsl(120, 100%, 40%);">+         LOGPFSML(conn->ho.fi, level, "%s: " fmt, \</span><br><span style="color: hsl(120, 100%, 40%);">+                        handover_status(conn), ## args); \</span><br><span style="color: hsl(120, 100%, 40%);">+   else \</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGP(DHODEC, level, "%s: " fmt, \</span><br><span style="color: hsl(120, 100%, 40%);">+                handover_status(conn), ## args); \</span><br><span style="color: hsl(120, 100%, 40%);">+       } while(0)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> struct gsm_network;</span><br><span> struct gsm_lchan;</span><br><span> struct gsm_bts;</span><br><span>@@ -25,6 +34,8 @@</span><br><span>      HO_RESULT_ERROR,</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+const char *handover_status(struct gsm_subscriber_connection *conn);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> extern const struct value_string handover_result_names[];</span><br><span> inline static const char *handover_result_name(enum handover_result val)</span><br><span> { return get_value_string(handover_result_names, val); }</span><br><span>@@ -70,8 +81,11 @@</span><br><span>                                                struct gsm_lchan *lchan);</span><br><span> void bsc_tx_bssmap_ho_failure(struct gsm_subscriber_connection *conn);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-struct gsm_bts *bts_by_neighbor_ident(const struct gsm_network *net,</span><br><span style="color: hsl(0, 100%, 40%);">-                                    const struct neighbor_ident_key *search_for);</span><br><span style="color: hsl(120, 100%, 40%);">+int find_handover_target_cell(struct gsm_bts **local_target_cell_p,</span><br><span style="color: hsl(120, 100%, 40%);">+                            const struct gsm0808_cell_id_list2 **remote_target_cell_p,</span><br><span style="color: hsl(120, 100%, 40%);">+                            struct gsm_subscriber_connection *conn, const struct neighbor_ident_key *search_for,</span><br><span style="color: hsl(120, 100%, 40%);">+                          bool log_errors);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> struct neighbor_ident_key *bts_ident_key(const struct gsm_bts *bts);</span><br><span> </span><br><span> void handover_parse_inter_bsc_mt(struct gsm_subscriber_connection *conn,</span><br><span>diff --git a/include/osmocom/bsc/handover_fsm.h b/include/osmocom/bsc/handover_fsm.h</span><br><span>index 7c2145e..1628d8f 100644</span><br><span>--- a/include/osmocom/bsc/handover_fsm.h</span><br><span>+++ b/include/osmocom/bsc/handover_fsm.h</span><br><span>@@ -4,18 +4,6 @@</span><br><span> #include <osmocom/bsc/debug.h></span><br><span> #include <osmocom/bsc/handover.h></span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-const char *handover_status(struct gsm_subscriber_connection *conn);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-/* This macro automatically includes a final \n, if omitted. */</span><br><span style="color: hsl(0, 100%, 40%);">-#define LOG_HO(conn, level, fmt, args...) do { \</span><br><span style="color: hsl(0, 100%, 40%);">-     if (conn->ho.fi) \</span><br><span style="color: hsl(0, 100%, 40%);">-           LOGPFSML(conn->ho.fi, level, "%s: " fmt, \</span><br><span style="color: hsl(0, 100%, 40%);">-                  handover_status(conn), ## args); \</span><br><span style="color: hsl(0, 100%, 40%);">-     else \</span><br><span style="color: hsl(0, 100%, 40%);">-          LOGP(DHODEC, level, "%s: " fmt, \</span><br><span style="color: hsl(0, 100%, 40%);">-                  handover_status(conn), ## args); \</span><br><span style="color: hsl(0, 100%, 40%);">- } while(0)</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> /* Terminology:</span><br><span>  * Intra-Cell: stays within one BTS, this should actually be an Assignment.</span><br><span>  * Intra-BSC: stays within one BSC, but moves between BTSes.</span><br><span>diff --git a/include/osmocom/bsc/neighbor_ident.h b/include/osmocom/bsc/neighbor_ident.h</span><br><span>index 17bffbc..aa38276 100644</span><br><span>--- a/include/osmocom/bsc/neighbor_ident.h</span><br><span>+++ b/include/osmocom/bsc/neighbor_ident.h</span><br><span>@@ -47,6 +47,8 @@</span><br><span> void neighbor_ident_vty_init(struct gsm_network *net, struct neighbor_ident_list *nil);</span><br><span> void neighbor_ident_vty_write(struct vty *vty, const char *indent, struct gsm_bts *bts);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+bool neighbor_ident_bts_entry_exists(uint8_t from_bts);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #define NEIGHBOR_IDENT_VTY_KEY_PARAMS "arfcn <0-1023> bsic (<0-63>|any)"</span><br><span> #define NEIGHBOR_IDENT_VTY_KEY_DOC \</span><br><span>        "ARFCN of neighbor cell\n" "ARFCN value\n" \</span><br><span>diff --git a/src/osmo-bsc/handover_decision_2.c b/src/osmo-bsc/handover_decision_2.c</span><br><span>index a8fff63..0e24c0d 100644</span><br><span>--- a/src/osmo-bsc/handover_decision_2.c</span><br><span>+++ b/src/osmo-bsc/handover_decision_2.c</span><br><span>@@ -900,18 +900,8 @@</span><br><span>                 return;</span><br><span>      }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   neighbor_bts = bts_by_neighbor_ident(bts->network, &ni);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- neighbor_cil = neighbor_ident_get(bts->network->neighbor_bss_cells, &ni);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-     if (neighbor_bts && neighbor_cil) {</span><br><span style="color: hsl(0, 100%, 40%);">-             LOGPHOBTS(bts, LOGL_ERROR, "Configuration error: %s exists as both local"</span><br><span style="color: hsl(0, 100%, 40%);">-                       " neighbor (bts %u) and remote-BSS neighbor (%s). Will consider only"</span><br><span style="color: hsl(0, 100%, 40%);">-                         " the local-BSS neighbor.\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                         neighbor_ident_key_name(&ni),</span><br><span style="color: hsl(0, 100%, 40%);">-                       neighbor_bts->nr, gsm0808_cell_id_list_name(neighbor_cil));</span><br><span style="color: hsl(0, 100%, 40%);">-                neighbor_cil = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-    }</span><br><span style="color: hsl(120, 100%, 40%);">+     find_handover_target_cell(&neighbor_bts, &neighbor_cil,</span><br><span style="color: hsl(120, 100%, 40%);">+                                 lchan->conn, &ni, false);</span><br><span> </span><br><span>       if (!neighbor_bts && !neighbor_cil) {</span><br><span>                LOGPHOBTS(bts, LOGL_DEBUG, "no neighbor ARFCN %u BSIC %u configured for this cell\n",</span><br><span>diff --git a/src/osmo-bsc/handover_fsm.c b/src/osmo-bsc/handover_fsm.c</span><br><span>index 6d0c2d4..d159347 100644</span><br><span>--- a/src/osmo-bsc/handover_fsm.c</span><br><span>+++ b/src/osmo-bsc/handover_fsm.c</span><br><span>@@ -31,6 +31,7 @@</span><br><span> #include <osmocom/bsc/bsc_subscriber.h></span><br><span> </span><br><span> #include <osmocom/bsc/handover_fsm.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/bsc/handover_cfg.h></span><br><span> #include <osmocom/bsc/bsc_subscr_conn_fsm.h></span><br><span> #include <osmocom/bsc/lchan_select.h></span><br><span> #include <osmocom/bsc/lchan_fsm.h></span><br><span>@@ -200,6 +201,9 @@</span><br><span>         conn = req->old_lchan->conn;</span><br><span>   OSMO_ASSERT(conn && conn->fi);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* Make sure the handover target neighbor_ident_key contains the correct source bts nr */</span><br><span style="color: hsl(120, 100%, 40%);">+     req->target_nik.from_bts = req->old_lchan->ts->trx->bts->nr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>     /* To make sure we're allowed to start a handover, go through a gscon event dispatch. If that is accepted, the</span><br><span>    * same req is passed to handover_start(). */</span><br><span>        osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_HANDOVER_START, req);</span><br><span>@@ -285,9 +289,10 @@</span><br><span> </span><br><span>        OSMO_ASSERT(req && req->old_lchan && req->old_lchan->conn);</span><br><span>         struct gsm_subscriber_connection *conn = req->old_lchan->conn;</span><br><span style="color: hsl(120, 100%, 40%);">+  const struct neighbor_ident_key *search_for = &req->target_nik;</span><br><span>       struct handover *ho = &conn->ho;</span><br><span style="color: hsl(0, 100%, 40%);">- struct gsm_bts *bts;</span><br><span style="color: hsl(0, 100%, 40%);">-    const struct gsm0808_cell_id_list2 *cil;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct gsm_bts *local_target_cell = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+     const struct gsm0808_cell_id_list2 *remote_target_cell = NULL;</span><br><span> </span><br><span>   if (conn->ho.fi) {</span><br><span>                LOG_HO(conn, LOGL_ERROR, "Handover requested while another handover is ongoing; Ignore\n");</span><br><span>@@ -295,6 +300,9 @@</span><br><span>  }</span><br><span>    handover_reset(conn);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+     /* When handover_start() is invoked by the gscon, it expects a HANDOVER_END event. The best way to ensure this</span><br><span style="color: hsl(120, 100%, 40%);">+         * is to always create a handover_fsm instance, even if the target cell is not resolved yet. Any failure should</span><br><span style="color: hsl(120, 100%, 40%);">+        * then call handover_end(), which ensures that the conn snaps back to a valid state. */</span><br><span>     handover_fsm_alloc(conn);</span><br><span> </span><br><span>        ho->from_hodec_id = req->from_hodec_id;</span><br><span>@@ -302,21 +310,25 @@</span><br><span>                req->old_lchan->type : req->new_lchan_type;</span><br><span>         ho->target_cell = req->target_nik;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    bts = bts_by_neighbor_ident(conn->network, &req->target_nik);</span><br><span style="color: hsl(0, 100%, 40%);">- if (bts) {</span><br><span style="color: hsl(0, 100%, 40%);">-              ho->new_bts = bts;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (find_handover_target_cell(&local_target_cell, &remote_target_cell,</span><br><span style="color: hsl(120, 100%, 40%);">+                                      conn, search_for, true))</span><br><span style="color: hsl(120, 100%, 40%);">+                goto no_handover;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (local_target_cell) {</span><br><span style="color: hsl(120, 100%, 40%);">+              ho->new_bts = local_target_cell;</span><br><span>          handover_start_intra_bsc(conn);</span><br><span>              return;</span><br><span>      }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   cil = neighbor_ident_get(conn->network->neighbor_bss_cells, &req->target_nik);</span><br><span style="color: hsl(0, 100%, 40%);">-     if (cil) {</span><br><span style="color: hsl(0, 100%, 40%);">-              handover_start_inter_bsc_out(conn, cil);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (remote_target_cell) {</span><br><span style="color: hsl(120, 100%, 40%);">+             handover_start_inter_bsc_out(conn, remote_target_cell);</span><br><span>              return;</span><br><span>      }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   LOG_HO(conn, LOGL_ERROR, "Cannot handover %s: neighbor unknown\n",</span><br><span style="color: hsl(0, 100%, 40%);">-           neighbor_ident_key_name(&req->target_nik));</span><br><span style="color: hsl(120, 100%, 40%);">+     /* should never reach this, because find_handover_target_cell() would have returned error. */</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(false);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+no_handover:</span><br><span>  handover_end(conn, HO_RESULT_FAIL_NO_CHANNEL);</span><br><span> }</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 5725213..5be8383 100644</span><br><span>--- a/src/osmo-bsc/handover_logic.c</span><br><span>+++ b/src/osmo-bsc/handover_logic.c</span><br><span>@@ -125,42 +125,205 @@</span><br><span>    return count;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-struct gsm_bts *bts_by_neighbor_ident(const struct gsm_network *net,</span><br><span style="color: hsl(0, 100%, 40%);">-                                    const struct neighbor_ident_key *search_for)</span><br><span style="color: hsl(120, 100%, 40%);">+/* Find out a handover target cell for the given neighbor_ident_key,</span><br><span style="color: hsl(120, 100%, 40%);">+ * and make sure there are no ambiguous matches.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Given a source BTS and a target ARFCN+BSIC, find which cell is the right handover target.</span><br><span style="color: hsl(120, 100%, 40%);">+ * ARFCN+BSIC may be re-used within and/or across BSS, so make sure that only those cells that are explicitly</span><br><span style="color: hsl(120, 100%, 40%);">+ * listed as neighbor of the source cell are viable handover targets.</span><br><span style="color: hsl(120, 100%, 40%);">+ * The (legacy) default configuration is that, when no explicit neighbors are listed, that all local cells are</span><br><span style="color: hsl(120, 100%, 40%);">+ * neighbors, in which case each ARFCN+BSIC must exist at most once.</span><br><span style="color: hsl(120, 100%, 40%);">+ * If there is more than one viable handover target cell found for the given ARFCN+BSIC, that constitutes a</span><br><span style="color: hsl(120, 100%, 40%);">+ * configuration error and should not result in handover, so that the system's misconfiguration is more likely</span><br><span style="color: hsl(120, 100%, 40%);">+ * to be found.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int find_handover_target_cell(struct gsm_bts **local_target_cell_p,</span><br><span style="color: hsl(120, 100%, 40%);">+                            const struct gsm0808_cell_id_list2 **remote_target_cell_p,</span><br><span style="color: hsl(120, 100%, 40%);">+                            struct gsm_subscriber_connection *conn, const struct neighbor_ident_key *search_for,</span><br><span style="color: hsl(120, 100%, 40%);">+                          bool log_errors)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-     struct gsm_bts *found = NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-   struct gsm_bts *bts;</span><br><span style="color: hsl(0, 100%, 40%);">-    struct gsm_bts *wildcard_match = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct gsm_network *net = conn->network;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct gsm_bts *from_bts;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct gsm_bts *local_target_cell = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+     const struct gsm0808_cell_id_list2 *remote_target_cell = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct gsm_bts_ref *neigh;</span><br><span style="color: hsl(120, 100%, 40%);">+    bool ho_active;</span><br><span style="color: hsl(120, 100%, 40%);">+       bool as_active;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     llist_for_each_entry(bts, &net->bts_list, list) {</span><br><span style="color: hsl(0, 100%, 40%);">-                struct neighbor_ident_key entry = {</span><br><span style="color: hsl(0, 100%, 40%);">-                     .from_bts = NEIGHBOR_IDENT_KEY_ANY_BTS,</span><br><span style="color: hsl(0, 100%, 40%);">-                 .arfcn = bts->c0->arfcn,</span><br><span style="color: hsl(0, 100%, 40%);">-                  .bsic = bts->bsic,</span><br><span style="color: hsl(0, 100%, 40%);">-           };</span><br><span style="color: hsl(0, 100%, 40%);">-              if (neighbor_ident_key_match(&entry, search_for, true)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                   if (found) {</span><br><span style="color: hsl(0, 100%, 40%);">-                            LOGP(DHO, LOGL_ERROR, "CONFIG ERROR: Multiple BTS match %s: %d and %d\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                                  neighbor_ident_key_name(search_for),</span><br><span style="color: hsl(0, 100%, 40%);">-                                    found->nr, bts->nr);</span><br><span style="color: hsl(0, 100%, 40%);">-                         return found;</span><br><span style="color: hsl(0, 100%, 40%);">-                   }</span><br><span style="color: hsl(0, 100%, 40%);">-                       found = bts;</span><br><span style="color: hsl(0, 100%, 40%);">-            }</span><br><span style="color: hsl(0, 100%, 40%);">-               if (neighbor_ident_key_match(&entry, search_for, false))</span><br><span style="color: hsl(0, 100%, 40%);">-                    wildcard_match = bts;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (local_target_cell_p)</span><br><span style="color: hsl(120, 100%, 40%);">+              *local_target_cell_p = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+  if (remote_target_cell_p)</span><br><span style="color: hsl(120, 100%, 40%);">+             *remote_target_cell_p = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!search_for) {</span><br><span style="color: hsl(120, 100%, 40%);">+            if (log_errors)</span><br><span style="color: hsl(120, 100%, 40%);">+                       LOG_HO(conn, LOGL_ERROR, "Handover without target cell\n");</span><br><span style="color: hsl(120, 100%, 40%);">+         return -EINVAL;</span><br><span>      }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   if (found)</span><br><span style="color: hsl(0, 100%, 40%);">-              return found;</span><br><span style="color: hsl(120, 100%, 40%);">+ from_bts = gsm_bts_num(net, search_for->from_bts);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!from_bts) {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (log_errors)</span><br><span style="color: hsl(120, 100%, 40%);">+                       LOG_HO(conn, LOGL_ERROR, "Handover without source cell\n");</span><br><span style="color: hsl(120, 100%, 40%);">+         return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   return wildcard_match;</span><br><span style="color: hsl(120, 100%, 40%);">+        ho_active = ho_get_ho_active(from_bts->ho);</span><br><span style="color: hsl(120, 100%, 40%);">+        as_active = (ho_get_algorithm(from_bts->ho) == 2)</span><br><span style="color: hsl(120, 100%, 40%);">+          && ho_get_hodec2_as_active(from_bts->ho);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!ho_active && !as_active) {</span><br><span style="color: hsl(120, 100%, 40%);">+               if (log_errors)</span><br><span style="color: hsl(120, 100%, 40%);">+                       LOG_HO(conn, LOGL_ERROR, "Cannot start Handover: Handover and Assignment disabled for this source cell (%s)\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%);">+          return -EINVAL;</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 (llist_empty(&from_bts->local_neighbors)</span><br><span style="color: hsl(120, 100%, 40%);">+        && !neighbor_ident_bts_entry_exists(from_bts->nr)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           /* No explicit neighbor entries exist for this BTS. Hence apply the legacy default behavior that all</span><br><span style="color: hsl(120, 100%, 40%);">+           * local cells are neighbors. */</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%);">+              LOG_HO(conn, LOGL_DEBUG, "No explicit neighbors, regarding all local cells as neighbors\n");</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 bts_key = *bts_ident_key(bts);</span><br><span style="color: hsl(120, 100%, 40%);">+                      if (neighbor_ident_key_match(&bts_key, search_for, true)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                               if (local_target_cell) {</span><br><span style="color: hsl(120, 100%, 40%);">+                                      if (log_errors)</span><br><span style="color: hsl(120, 100%, 40%);">+                                               LOG_HO(conn, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                     "NEIGHBOR CONFIGURATION ERROR: Multiple local cells match %s"</span><br><span style="color: hsl(120, 100%, 40%);">+                                                       " (BTS %d and BTS %d)."</span><br><span style="color: hsl(120, 100%, 40%);">+                                                     " Aborting Handover because of ambiguous network topology.\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%);">+                                                  local_target_cell->nr, bts->nr);</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%);">+                             local_target_cell = bts;</span><br><span style="color: hsl(120, 100%, 40%);">+                      }</span><br><span style="color: hsl(120, 100%, 40%);">+                     if (neighbor_ident_key_match(&bts_key, 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 (!local_target_cell)</span><br><span style="color: hsl(120, 100%, 40%);">+                       local_target_cell = wildcard_match;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         if (!local_target_cell) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     if (log_errors)</span><br><span style="color: hsl(120, 100%, 40%);">+                               LOG_HO(conn, LOGL_ERROR, "Cannot Handover, no cell matches %s\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%);">+                  return -EINVAL;</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 (local_target_cell == from_bts && !as_active) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    if (log_errors)</span><br><span style="color: hsl(120, 100%, 40%);">+                               LOG_HO(conn, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                                     "Cannot start re-assignment, Assignment disabled for this cell (%s)\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%);">+                  return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+               }</span><br><span style="color: hsl(120, 100%, 40%);">+             if (local_target_cell != from_bts && !ho_active) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    if (log_errors)</span><br><span style="color: hsl(120, 100%, 40%);">+                               LOG_HO(conn, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                                     "Cannot start Handover, Handover disabled for this cell (%s)\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%);">+                  return -EINVAL;</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 (local_target_cell_p)</span><br><span style="color: hsl(120, 100%, 40%);">+                      *local_target_cell_p = local_target_cell;</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* One or more local- or remote-BSS cell neighbors are configured. Find a match among those, but also detect</span><br><span style="color: hsl(120, 100%, 40%);">+   * ambiguous matches (if multiple cells match, it is a configuration error). */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     LOG_HO(conn, LOGL_DEBUG, "There are explicit neighbors configured for this cell\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* Iterate explicit local neighbor cells */</span><br><span style="color: hsl(120, 100%, 40%);">+   llist_for_each_entry(neigh, &from_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%);">+            struct neighbor_ident_key neigh_bts_key = *bts_ident_key(neigh_bts);</span><br><span style="color: hsl(120, 100%, 40%);">+          neigh_bts_key.from_bts = from_bts->nr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           LOG_HO(conn, LOGL_DEBUG, "Local neighbor %s\n", neighbor_ident_key_name(&neigh_bts_key));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+             if (!neighbor_ident_key_match(&neigh_bts_key, search_for, true)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        LOG_HO(conn, LOGL_DEBUG, "Doesn't match %s\n", neighbor_ident_key_name(search_for));</span><br><span style="color: hsl(120, 100%, 40%);">+                    continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           if (local_target_cell) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      if (log_errors)</span><br><span style="color: hsl(120, 100%, 40%);">+                               LOG_HO(conn, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                                     "NEIGHBOR CONFIGURATION ERROR: Multiple BTS match %s (BTS %d and BTS %d)."</span><br><span style="color: hsl(120, 100%, 40%);">+                                  " Aborting Handover because of ambiguous network topology.\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                      neighbor_ident_key_name(search_for), local_target_cell->nr, neigh_bts->nr);</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           local_target_cell = neigh_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%);">+   /* Any matching remote-BSS neighbor cell? */</span><br><span style="color: hsl(120, 100%, 40%);">+  remote_target_cell = neighbor_ident_get(net->neighbor_bss_cells, search_for);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (remote_target_cell)</span><br><span style="color: hsl(120, 100%, 40%);">+               LOG_HO(conn, LOGL_DEBUG, "Found remote target cell %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                  gsm0808_cell_id_list_name(remote_target_cell));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (local_target_cell && remote_target_cell) {</span><br><span style="color: hsl(120, 100%, 40%);">+                if (log_errors)</span><br><span style="color: hsl(120, 100%, 40%);">+                       LOG_HO(conn, LOGL_ERROR, "NEIGHBOR CONFIGURATION ERROR: Both a local and a remote-BSS cell match %s"</span><br><span style="color: hsl(120, 100%, 40%);">+                               " (BTS %d and remote %s)."</span><br><span style="color: hsl(120, 100%, 40%);">+                          " Aborting Handover because of ambiguous network topology.\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                              neighbor_ident_key_name(search_for), local_target_cell->nr,</span><br><span style="color: hsl(120, 100%, 40%);">+                        gsm0808_cell_id_list_name(remote_target_cell));</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (local_target_cell == from_bts && !as_active) {</span><br><span style="color: hsl(120, 100%, 40%);">+            if (log_errors)</span><br><span style="color: hsl(120, 100%, 40%);">+                       LOG_HO(conn, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                             "Cannot start re-assignment, Assignment disabled for this cell (%s)\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%);">+          return -EINVAL;</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 (((local_target_cell && local_target_cell != from_bts)</span><br><span style="color: hsl(120, 100%, 40%);">+          || remote_target_cell)</span><br><span style="color: hsl(120, 100%, 40%);">+       && !ho_active) {</span><br><span style="color: hsl(120, 100%, 40%);">+          if (log_errors)</span><br><span style="color: hsl(120, 100%, 40%);">+                       LOG_HO(conn, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                             "Cannot start Handover, Handover disabled for this cell (%s)\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%);">+          return -EINVAL;</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 (local_target_cell) {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (local_target_cell_p)</span><br><span style="color: hsl(120, 100%, 40%);">+                      *local_target_cell_p = local_target_cell;</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (remote_target_cell) {</span><br><span style="color: hsl(120, 100%, 40%);">+             if (remote_target_cell_p)</span><br><span style="color: hsl(120, 100%, 40%);">+                     *remote_target_cell_p = remote_target_cell;</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (log_errors)</span><br><span style="color: hsl(120, 100%, 40%);">+               LOG_HO(conn, LOGL_ERROR, "Cannot handover %s: neighbor unknown\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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return -ENODEV;</span><br><span> }</span><br><span> </span><br><span> struct neighbor_ident_key *bts_ident_key(const struct gsm_bts *bts)</span><br><span> {</span><br><span>         static struct neighbor_ident_key key;</span><br><span>        key = (struct neighbor_ident_key){</span><br><span style="color: hsl(120, 100%, 40%);">+            .from_bts = NEIGHBOR_IDENT_KEY_ANY_BTS,</span><br><span>              .arfcn = bts->c0->arfcn,</span><br><span>               .bsic = bts->bsic,</span><br><span>        };</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 715ee8b..f4b6407 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>@@ -389,6 +389,15 @@</span><br><span>   return true;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+bool neighbor_ident_bts_entry_exists(uint8_t from_bts)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct nil_match_bts_data d = {</span><br><span style="color: hsl(120, 100%, 40%);">+               .bts_nr = from_bts,</span><br><span style="color: hsl(120, 100%, 40%);">+   };</span><br><span style="color: hsl(120, 100%, 40%);">+    neighbor_ident_iter(g_neighbor_cells, nil_match_bts, &d);</span><br><span style="color: hsl(120, 100%, 40%);">+ return (bool)d.found;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static int del_all(struct vty *vty)</span><br><span> {</span><br><span>       int rc;</span><br><span>@@ -428,7 +437,9 @@</span><br><span>        /* Remove all remote-BSS neighbors */</span><br><span>        while (1) {</span><br><span>          struct neighbor_ident_key k;</span><br><span style="color: hsl(0, 100%, 40%);">-            struct nil_match_bts_data d = {};</span><br><span style="color: hsl(120, 100%, 40%);">+             struct nil_match_bts_data d = {</span><br><span style="color: hsl(120, 100%, 40%);">+                       .bts_nr = bts->nr,</span><br><span style="color: hsl(120, 100%, 40%);">+         };</span><br><span>           neighbor_ident_iter(g_neighbor_cells, nil_match_bts, &d);</span><br><span>                if (!d.found)</span><br><span>                        break;</span><br><span>diff --git a/tests/bsc/bsc_test.c b/tests/bsc/bsc_test.c</span><br><span>index 492f0c5..103e0bb 100644</span><br><span>--- a/tests/bsc/bsc_test.c</span><br><span>+++ b/tests/bsc/bsc_test.c</span><br><span>@@ -250,3 +250,5 @@</span><br><span>                       struct msgb *msg, int link_id, int allow_sacch) {}</span><br><span> void ts_fsm_alloc(struct gsm_bts_trx_ts *ts) {}</span><br><span> void lchan_activate(struct gsm_lchan *lchan, void *info) {}</span><br><span style="color: hsl(120, 100%, 40%);">+bool neighbor_ident_bts_entry_exists(uint8_t from_bts) { return false; }</span><br><span style="color: hsl(120, 100%, 40%);">+const char *handover_status(struct gsm_subscriber_connection *conn) { return "x"; }</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-bsc/+/14769">change 14769</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/c/osmo-bsc/+/14769"/><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-Change-Id: I29bca59ab232eddc74e0d4698efb9c9992443983 </div>
<div style="display:none"> Gerrit-Change-Number: 14769 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: neels <nhofmeyr@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>