aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeels Hofmeyr <neels@hofmeyr.de>2018-10-19 15:13:10 +0200
committerNeels Hofmeyr <neels@hofmeyr.de>2018-11-01 01:14:58 +0100
commit7a9104bfada915bb41a34b862120a4e85b847793 (patch)
treeed809bd4ee2cccb620ad97c0fd9358503af5c206
parent472184cb6286dcb3bca399b21dbb0f31811cf8e6 (diff)
handover: re-enable legacy neighbor configuration
By adding the new 'neighbor' vty config, I actually broke legacy configuration of neighbors by 'neighbor-list': even though the System Information will send out the configured ARFCN+BSIC, when the MS reports a better RXLEV on one of them, we would not actually find this neighbor, since an explicit neighbor mapping is not present. Add a fallback to looking for a matching cell in all local cells, only if no explicit neighbor mappings exist, to still allow legacy neighbor configuration without explicit mappings. Change-Id: I568359e7744a3fe6f835d717229402214bcf5ab4
-rw-r--r--include/osmocom/bsc/handover.h2
-rw-r--r--src/osmo-bsc/handover_fsm.c19
-rw-r--r--src/osmo-bsc/handover_logic.c39
3 files changed, 60 insertions, 0 deletions
diff --git a/include/osmocom/bsc/handover.h b/include/osmocom/bsc/handover.h
index 322913da4..2642840d8 100644
--- a/include/osmocom/bsc/handover.h
+++ b/include/osmocom/bsc/handover.h
@@ -72,6 +72,8 @@ void bsc_tx_bssmap_ho_failure(struct gsm_subscriber_connection *conn);
struct gsm_bts *bts_by_neighbor_ident(const struct gsm_network *net,
const struct neighbor_ident_key *search_for);
+struct gsm_bts *bts_by_arfcn_bsic(const struct gsm_network *net, uint16_t arfcn, uint8_t bsic,
+ unsigned int match_idx);
struct neighbor_ident_key *bts_ident_key(const struct gsm_bts *bts);
void handover_parse_inter_bsc_mt(struct gsm_subscriber_connection *conn,
diff --git a/src/osmo-bsc/handover_fsm.c b/src/osmo-bsc/handover_fsm.c
index 0107ef03c..7a78eef60 100644
--- a/src/osmo-bsc/handover_fsm.c
+++ b/src/osmo-bsc/handover_fsm.c
@@ -313,6 +313,25 @@ void handover_start(struct handover_out_req *req)
return;
}
+ /* There is no matching explicit neighbor cell. This might actually be a legacy config using
+ * 'neighbor-list' configuration instead of the new 'neighbor' relations. For the legacy config,
+ * we need to actually match by ARFCN+BSIC and hopefully get only one match. */
+ bts = bts_by_arfcn_bsic(conn->network, req->target_nik.arfcn, req->target_nik.bsic, 0);
+ if (bts) {
+ struct gsm_bts *bts2 = bts_by_arfcn_bsic(conn->network, req->target_nik.arfcn,
+ req->target_nik.bsic, 1);
+ /* Warn if the ARFCN+BSIC is ambiguous -- but attempt to continue with the first BTS
+ * found. */
+ if (bts2)
+ LOG_HO(conn, LOGL_ERROR, "Ambiguous neighbor ARFCN+BSIC:"
+ " at least BTS %u and BTS %u have the same ARFCN+BSIC=%u+%u."
+ " Rather use explicit neighbor cell relations! See 'neighbor'.\n",
+ bts->nr, bts2->nr, req->target_nik.arfcn, req->target_nik.bsic);
+ ho->new_bts = bts;
+ handover_start_intra_bsc(conn);
+ return;
+ }
+
LOG_HO(conn, LOGL_ERROR, "Cannot handover %s: neighbor unknown\n",
neighbor_ident_key_name(&req->target_nik));
handover_end(conn, HO_RESULT_FAIL_NO_CHANNEL);
diff --git a/src/osmo-bsc/handover_logic.c b/src/osmo-bsc/handover_logic.c
index 5725213ef..57a87c449 100644
--- a/src/osmo-bsc/handover_logic.c
+++ b/src/osmo-bsc/handover_logic.c
@@ -125,6 +125,9 @@ int bts_handover_count(struct gsm_bts *bts, int ho_scopes)
return count;
}
+/* Look for a local BTS that is an explicit neighbor of a given BTS.
+ * The returned BTS pointer is an explicit neighbor of search_for->from_bts.
+ * To look for an ARFCN+BSIC match without the neighbor relation, see bts_by_arfcn_bsic(). */
struct gsm_bts *bts_by_neighbor_ident(const struct gsm_network *net,
const struct neighbor_ident_key *search_for)
{
@@ -157,6 +160,42 @@ struct gsm_bts *bts_by_neighbor_ident(const struct gsm_network *net,
return wildcard_match;
}
+/* Look for a local BTS that matches the given ARFCN+BSIC.
+ * Within a BSS, a given ARFCN+BSIC pair can be re-used; when match_idx is zero, return the first match,
+ * when 1 return the second match etc.. If no such match exists, return NULL. To look for an ARFCN+BSIC
+ * match with explicit neighbor relation, see bts_by_neighbor_ident(). */
+struct gsm_bts *bts_by_arfcn_bsic(const struct gsm_network *net, uint16_t arfcn, uint8_t bsic,
+ unsigned int match_idx)
+{
+ struct gsm_bts *bts;
+
+ llist_for_each_entry(bts, &net->bts_list, list) {
+ struct gsm_bts_trx *trx;
+ bool match;
+ if (bts->bsic != bsic)
+ continue;
+ match = false;
+ llist_for_each_entry(trx, &bts->trx_list, list) {
+ if (trx->arfcn != arfcn)
+ continue;
+ match = true;
+ break;
+ }
+
+ if (!match)
+ continue;
+
+ if (match_idx > 0) {
+ match_idx --;
+ continue;
+ }
+
+ return bts;
+ }
+
+ return NULL;
+}
+
struct neighbor_ident_key *bts_ident_key(const struct gsm_bts *bts)
{
static struct neighbor_ident_key key;