diff options
Diffstat (limited to 'src/osmo-bsc/handover_fsm.c')
-rw-r--r-- | src/osmo-bsc/handover_fsm.c | 32 |
1 files changed, 22 insertions, 10 deletions
diff --git a/src/osmo-bsc/handover_fsm.c b/src/osmo-bsc/handover_fsm.c index 6d0c2d47e..d1593470b 100644 --- a/src/osmo-bsc/handover_fsm.c +++ b/src/osmo-bsc/handover_fsm.c @@ -31,6 +31,7 @@ #include <osmocom/bsc/bsc_subscriber.h> #include <osmocom/bsc/handover_fsm.h> +#include <osmocom/bsc/handover_cfg.h> #include <osmocom/bsc/bsc_subscr_conn_fsm.h> #include <osmocom/bsc/lchan_select.h> #include <osmocom/bsc/lchan_fsm.h> @@ -200,6 +201,9 @@ void handover_request(struct handover_out_req *req) conn = req->old_lchan->conn; OSMO_ASSERT(conn && conn->fi); + /* Make sure the handover target neighbor_ident_key contains the correct source bts nr */ + req->target_nik.from_bts = req->old_lchan->ts->trx->bts->nr; + /* To make sure we're allowed to start a handover, go through a gscon event dispatch. If that is accepted, the * same req is passed to handover_start(). */ osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_HANDOVER_START, req); @@ -285,9 +289,10 @@ void handover_start(struct handover_out_req *req) OSMO_ASSERT(req && req->old_lchan && req->old_lchan->conn); struct gsm_subscriber_connection *conn = req->old_lchan->conn; + const struct neighbor_ident_key *search_for = &req->target_nik; struct handover *ho = &conn->ho; - struct gsm_bts *bts; - const struct gsm0808_cell_id_list2 *cil; + struct gsm_bts *local_target_cell = NULL; + const struct gsm0808_cell_id_list2 *remote_target_cell = NULL; if (conn->ho.fi) { LOG_HO(conn, LOGL_ERROR, "Handover requested while another handover is ongoing; Ignore\n"); @@ -295,6 +300,9 @@ void handover_start(struct handover_out_req *req) } handover_reset(conn); + /* When handover_start() is invoked by the gscon, it expects a HANDOVER_END event. The best way to ensure this + * is to always create a handover_fsm instance, even if the target cell is not resolved yet. Any failure should + * then call handover_end(), which ensures that the conn snaps back to a valid state. */ handover_fsm_alloc(conn); ho->from_hodec_id = req->from_hodec_id; @@ -302,21 +310,25 @@ void handover_start(struct handover_out_req *req) req->old_lchan->type : req->new_lchan_type; ho->target_cell = req->target_nik; - bts = bts_by_neighbor_ident(conn->network, &req->target_nik); - if (bts) { - ho->new_bts = bts; + if (find_handover_target_cell(&local_target_cell, &remote_target_cell, + conn, search_for, true)) + goto no_handover; + + if (local_target_cell) { + ho->new_bts = local_target_cell; handover_start_intra_bsc(conn); return; } - cil = neighbor_ident_get(conn->network->neighbor_bss_cells, &req->target_nik); - if (cil) { - handover_start_inter_bsc_out(conn, cil); + if (remote_target_cell) { + handover_start_inter_bsc_out(conn, remote_target_cell); return; } - LOG_HO(conn, LOGL_ERROR, "Cannot handover %s: neighbor unknown\n", - neighbor_ident_key_name(&req->target_nik)); + /* should never reach this, because find_handover_target_cell() would have returned error. */ + OSMO_ASSERT(false); + +no_handover: handover_end(conn, HO_RESULT_FAIL_NO_CHANNEL); } |