aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeels Hofmeyr <neels@hofmeyr.de>2019-03-14 04:36:40 +0100
committerNeels Hofmeyr <neels@hofmeyr.de>2019-04-08 16:26:28 +0200
commit94c9324fe07cd0ba1277278270c8979d949e49ec (patch)
treebd52fac575de74ba93d67de8ba95bf7a595c552b
parentc15f6cd640bef63d8d52eaf4a187645ca95d0765 (diff)
fix inter-BSC-HO-incoming for AoIP (1/2)
Move the HO_ST_WAIT_MGW_ENDPOINT_TO_MSC state up to right after the lchan is done establishing. For AoIP, the local RTP address towards the MSC already needs to be known before the Handover Request Acknowledge is sent, so the AoIP Transport Layer Address IE can be included. This patch only modifies the handover FSM, a subsequent patch adds the IE. Change-Id: I4a5acdb2d4a0b947cc0c62067a67be88a3d467ff
-rw-r--r--include/osmocom/bsc/handover_fsm.h6
-rw-r--r--src/osmo-bsc/handover_fsm.c183
2 files changed, 105 insertions, 84 deletions
diff --git a/include/osmocom/bsc/handover_fsm.h b/include/osmocom/bsc/handover_fsm.h
index 4db0890..7c2145e 100644
--- a/include/osmocom/bsc/handover_fsm.h
+++ b/include/osmocom/bsc/handover_fsm.h
@@ -28,10 +28,10 @@ enum handover_fsm_state {
HO_ST_NOT_STARTED,
HO_ST_WAIT_LCHAN_ACTIVE,
+ HO_ST_WAIT_MGW_ENDPOINT_TO_MSC,
HO_ST_WAIT_RR_HO_DETECT,
HO_ST_WAIT_RR_HO_COMPLETE,
HO_ST_WAIT_LCHAN_ESTABLISHED,
- HO_ST_WAIT_MGW_ENDPOINT_TO_MSC,
/* The inter-BSC Outgoing Handover FSM has completely separate states, but since it makes sense for it
* to also live in conn->ho.fi, it should share the same event enum. From there it is merely
@@ -46,11 +46,11 @@ enum handover_fsm_event {
HO_EV_LCHAN_ACTIVE,
HO_EV_LCHAN_ESTABLISHED,
HO_EV_LCHAN_ERROR,
+ HO_EV_MSC_MGW_OK,
+ HO_EV_MSC_MGW_FAIL,
HO_EV_RR_HO_DETECT,
HO_EV_RR_HO_COMPLETE,
HO_EV_RR_HO_FAIL,
- HO_EV_MSC_MGW_OK,
- HO_EV_MSC_MGW_FAIL,
HO_EV_CONN_RELEASING,
HO_OUT_EV_BSSMAP_HO_COMMAND,
diff --git a/src/osmo-bsc/handover_fsm.c b/src/osmo-bsc/handover_fsm.c
index 421c32e..3b5a660 100644
--- a/src/osmo-bsc/handover_fsm.c
+++ b/src/osmo-bsc/handover_fsm.c
@@ -161,10 +161,10 @@ struct gsm_subscriber_connection *ho_fi_conn(struct osmo_fsm_inst *fi)
static const struct state_timeout ho_fsm_timeouts[32] = {
[HO_ST_WAIT_LCHAN_ACTIVE] = { .T = 23042 },
+ [HO_ST_WAIT_MGW_ENDPOINT_TO_MSC] = { .T = 23042 },
[HO_ST_WAIT_RR_HO_DETECT] = { .T = 23042 },
[HO_ST_WAIT_RR_HO_COMPLETE] = { .T = 23042 },
[HO_ST_WAIT_LCHAN_ESTABLISHED] = { .T = 23042 },
- [HO_ST_WAIT_MGW_ENDPOINT_TO_MSC] = { .T = 23042 },
[HO_OUT_ST_WAIT_HO_COMMAND] = { .T = 7 },
[HO_OUT_ST_WAIT_CLEAR] = { .T = 8 },
};
@@ -876,10 +876,24 @@ void handover_end(struct gsm_subscriber_connection *conn, enum handover_result r
static void ho_fsm_wait_lchan_active(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
struct gsm_subscriber_connection *conn = ho_fi_conn(fi);
+ struct handover *ho = &conn->ho;
switch (event) {
case HO_EV_LCHAN_ACTIVE:
- ho_fsm_state_chg(HO_ST_WAIT_RR_HO_DETECT);
+ /* - If the lchan is voiceless, no need to even think about the MGW.
+ * - If this is an intra-BSC Handover, we already have an RTP stream towards the MSC and aren't
+ * touching it.
+ * - If we're on SCCPlite, the MSC manages the MGW endpoint, all we do is the BTS side CI, so we can
+ * skip the part that would CRCX towards the MSC.
+ * So create an MSC side endpoint CI only if a voice lchan is established for an incoming inter-BSC
+ * handover on AoIP. Otherwise go on to send a Handover Command and wait for the Detect.
+ */
+ if (ho->new_lchan->activate.info.requires_voice_stream
+ && (ho->scope & HO_INTER_BSC_IN)
+ && gscon_is_aoip(conn))
+ ho_fsm_state_chg(HO_ST_WAIT_MGW_ENDPOINT_TO_MSC);
+ else
+ ho_fsm_state_chg(HO_ST_WAIT_RR_HO_DETECT);
return;
case HO_EV_LCHAN_ERROR:
@@ -892,6 +906,76 @@ static void ho_fsm_wait_lchan_active(struct osmo_fsm_inst *fi, uint32_t event, v
}
}
+/* Only for voice, only for inter-BSC Handover into this BSC, and only for AoIP:
+ *
+ * Establish the MGW endpoint CI that points towards the MSC. This needs to happen after the lchan (lchan_rtp_fsm) has
+ * created an MGW endpoint with the first CRCX, so that an endpoint is available, and before sending the Handover
+ * Request Acknowledge, so that the RTP address and port established towards the MSC can be included in the Handover
+ * Request Acknowledge message.
+ * (For SCCPlite, the MSC manages the CN side endpoint CI itself, and we don't need to send any RTP address in the
+ * Handover Request Acknowledge.)
+ *
+ * Actually, it should be possible to kick this off even above in handover_start_inter_bsc_in(), to do the CRCX towards
+ * the MSC at the same time as establishing the lchan. The gscon_ensure_mgw_endpoint() doesn't care which one of
+ * lchan_rtp_fsm or handover_start_inter_bsc_in() calls it first. The benefit would be that we'd send out the Handover
+ * Command ever so slightly sooner -- which isn't critical really, because a) how long does a CRCX take, milliseconds?
+ * and b) the time critical part is *after* the Handover Command was kicked off to keep the transition between cells as
+ * short as possible. The drawback of doing this earlier is code complexity: receiving the HO_EV_MSC_MGW_OK /
+ * HO_EV_MSC_MGW_FAIL events would need to be juggled in between the HO_EV_LCHAN_ACTIVE / HO_EV_LCHAN_ERROR. So the
+ * decision for now is to leave it here.
+ */
+static void ho_fsm_wait_mgw_endpoint_to_msc_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct gsm_subscriber_connection *conn = ho_fi_conn(fi);
+ struct handover *ho = &conn->ho;
+
+ if (!gscon_connect_mgw_to_msc(conn,
+ ho->new_lchan,
+ ho->inter_bsc_in.msc_assigned_rtp_addr,
+ ho->inter_bsc_in.msc_assigned_rtp_port,
+ fi,
+ HO_EV_MSC_MGW_OK,
+ HO_EV_MSC_MGW_FAIL,
+ NULL,
+ &ho->created_ci_for_msc)) {
+ ho_fail(HO_RESULT_ERROR,
+ "Unable to connect MGW endpoint to the MSC side");
+ }
+}
+
+static void ho_fsm_wait_mgw_endpoint_to_msc(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ struct gsm_subscriber_connection *conn = ho_fi_conn(fi);
+ const struct mgcp_conn_peer *mgw_info;
+
+ switch (event) {
+
+ case HO_EV_MSC_MGW_OK:
+ /* Ensure the endpoint is really there, and log it. This state is only entered for AoIP connections, see
+ * ho_fsm_wait_lchan_active() above. */
+ mgw_info = mgwep_ci_get_rtp_info(conn->user_plane.mgw_endpoint_ci_msc);
+ if (!mgw_info) {
+ ho_fail(HO_RESULT_ERROR,
+ "Unable to retrieve RTP port info allocated by MGW for"
+ " the MSC side.");
+ return;
+ }
+ LOG_HO(conn, LOGL_DEBUG, "MGW's MSC side CI: %s:%u\n",
+ mgw_info->addr, mgw_info->port);
+ ho_fsm_state_chg(HO_ST_WAIT_RR_HO_DETECT);
+ return;
+
+ case HO_EV_MSC_MGW_FAIL:
+ ho_fail(HO_RESULT_ERROR,
+ "Unable to connect MGW endpoint to the MSC side");
+ return;
+
+ default:
+ OSMO_ASSERT(false);
+ }
+}
+
+
static void ho_fsm_wait_rr_ho_detect_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
{
int rc;
@@ -1009,88 +1093,25 @@ static void ho_fsm_wait_rr_ho_complete(struct osmo_fsm_inst *fi, uint32_t event,
}
}
-static void ho_fsm_post_lchan_established(struct osmo_fsm_inst *fi);
-
static void ho_fsm_wait_lchan_established_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
{
struct gsm_subscriber_connection *conn = ho_fi_conn(fi);
if (conn->ho.fi && lchan_state_is(conn->ho.new_lchan, LCHAN_ST_ESTABLISHED)) {
LOG_HO(conn, LOGL_DEBUG, "lchan already established earlier\n");
- ho_fsm_post_lchan_established(fi);
+ ho_success();
}
}
static void ho_fsm_wait_lchan_established(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
- switch (event) {
-
- case HO_EV_LCHAN_ESTABLISHED:
- ho_fsm_post_lchan_established(fi);
- break;
-
- default:
- OSMO_ASSERT(false);
- }
-}
-
-static void ho_fsm_post_lchan_established(struct osmo_fsm_inst *fi)
-{
struct gsm_subscriber_connection *conn = ho_fi_conn(fi);
- struct handover *ho = &conn->ho;
- if (ho->new_lchan->activate.info.requires_voice_stream
- && (ho->scope & HO_INTER_BSC_IN))
- ho_fsm_state_chg(HO_ST_WAIT_MGW_ENDPOINT_TO_MSC);
- else
- ho_success();
-}
-
-static void ho_fsm_wait_mgw_endpoint_to_msc_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
-{
- struct gsm_subscriber_connection *conn = ho_fi_conn(fi);
- struct handover *ho = &conn->ho;
-
- if (!gscon_connect_mgw_to_msc(conn,
- ho->new_lchan,
- ho->inter_bsc_in.msc_assigned_rtp_addr,
- ho->inter_bsc_in.msc_assigned_rtp_port,
- fi,
- HO_EV_MSC_MGW_OK,
- HO_EV_MSC_MGW_FAIL,
- NULL,
- &ho->created_ci_for_msc)) {
- ho_fail(HO_RESULT_ERROR,
- "Unable to connect MGW endpoint to the MSC side");
- }
-}
-
-static void ho_fsm_wait_mgw_endpoint_to_msc(struct osmo_fsm_inst *fi, uint32_t event, void *data)
-{
- struct gsm_subscriber_connection *conn = ho_fi_conn(fi);
switch (event) {
- case HO_EV_MSC_MGW_OK:
- /* For AoIP, we created the MGW endpoint. Ensure it is really there, and log it. */
- if (gscon_is_aoip(conn)) {
- const struct mgcp_conn_peer *mgw_info;
- mgw_info = mgwep_ci_get_rtp_info(conn->user_plane.mgw_endpoint_ci_msc);
- if (!mgw_info) {
- ho_fail(HO_RESULT_ERROR,
- "Unable to retrieve RTP port info allocated by MGW for"
- " the MSC side.");
- return;
- }
- LOG_HO(conn, LOGL_DEBUG, "MGW's MSC side CI: %s:%u\n",
- mgw_info->addr, mgw_info->port);
- }
+ case HO_EV_LCHAN_ESTABLISHED:
ho_success();
- return;
-
- case HO_EV_MSC_MGW_FAIL:
- ho_fail(HO_RESULT_ERROR,
- "Unable to connect MGW endpoint to the MSC side");
- return;
+ break;
default:
OSMO_ASSERT(false);
@@ -1185,6 +1206,19 @@ static const struct osmo_fsm_state ho_fsm_states[] = {
,
.out_state_mask = 0
| S(HO_ST_WAIT_LCHAN_ACTIVE)
+ | S(HO_ST_WAIT_MGW_ENDPOINT_TO_MSC)
+ | S(HO_ST_WAIT_RR_HO_DETECT)
+ ,
+ },
+ [HO_ST_WAIT_MGW_ENDPOINT_TO_MSC] = {
+ .name = "WAIT_MGW_ENDPOINT_TO_MSC",
+ .onenter = ho_fsm_wait_mgw_endpoint_to_msc_onenter,
+ .action = ho_fsm_wait_mgw_endpoint_to_msc,
+ .in_event_mask = 0
+ | S(HO_EV_MSC_MGW_OK)
+ | S(HO_EV_MSC_MGW_FAIL)
+ ,
+ .out_state_mask = 0
| S(HO_ST_WAIT_RR_HO_DETECT)
,
},
@@ -1222,20 +1256,7 @@ static const struct osmo_fsm_state ho_fsm_states[] = {
.in_event_mask = 0
| S(HO_EV_LCHAN_ESTABLISHED)
,
- .out_state_mask = 0
- | S(HO_ST_WAIT_MGW_ENDPOINT_TO_MSC)
- ,
- },
- [HO_ST_WAIT_MGW_ENDPOINT_TO_MSC] = {
- .name = "WAIT_MGW_ENDPOINT_TO_MSC",
- .onenter = ho_fsm_wait_mgw_endpoint_to_msc_onenter,
- .action = ho_fsm_wait_mgw_endpoint_to_msc,
- .in_event_mask = 0
- | S(HO_EV_MSC_MGW_OK)
- | S(HO_EV_MSC_MGW_FAIL)
- ,
},
-
[HO_OUT_ST_WAIT_HO_COMMAND] = {
.name = "inter-BSC-OUT:WAIT_HO_COMMAND",
.action = ho_out_fsm_wait_ho_command,