aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/osmocom/bsc/gsm_data.h19
-rw-r--r--include/osmocom/bsc/lchan_fsm.h13
-rw-r--r--src/osmo-bsc/assignment_fsm.c2
-rw-r--r--src/osmo-bsc/bsc_subscr_conn_fsm.c2
-rw-r--r--src/osmo-bsc/handover_fsm.c6
-rw-r--r--src/osmo-bsc/lchan_fsm.c142
-rw-r--r--src/osmo-bsc/lchan_rtp_fsm.c26
-rw-r--r--src/osmo-bsc/osmo_bsc_bssap.c2
8 files changed, 105 insertions, 107 deletions
diff --git a/include/osmocom/bsc/gsm_data.h b/include/osmocom/bsc/gsm_data.h
index cf34c6f16..20901420e 100644
--- a/include/osmocom/bsc/gsm_data.h
+++ b/include/osmocom/bsc/gsm_data.h
@@ -503,6 +503,19 @@ extern const struct value_string lchan_activate_mode_names[];
static inline const char *lchan_activate_mode_name(enum lchan_activate_mode activ_for)
{ return get_value_string(lchan_activate_mode_names, activ_for); }
+struct lchan_activate_info {
+ enum lchan_activate_mode activ_for;
+ struct gsm_subscriber_connection *for_conn;
+ /* This always is for a specific lchan, so its lchan->type indicates full or half rate.
+ * When a dyn TS was selected, the lchan->type has been set to the desired rate. */
+ enum gsm48_chan_mode chan_mode;
+ uint16_t s15_s0;
+ bool requires_voice_stream;
+ bool wait_before_switching_rtp; /*< true = requires LCHAN_EV_READY_TO_SWITCH_RTP */
+ uint16_t msc_assigned_cic;
+ struct gsm_lchan *re_use_mgw_endpoint_from_lchan;
+};
+
struct gsm_lchan {
/* The TS that we're part of */
struct gsm_bts_trx_ts *ts;
@@ -517,18 +530,14 @@ struct gsm_lchan {
struct mgwep_ci *mgw_endpoint_ci_bts;
struct {
- enum lchan_activate_mode activ_for;
+ struct lchan_activate_info info;
bool activ_ack; /*< true as soon as RSL Chan Activ Ack is received */
bool immediate_assignment_sent;
/*! This flag ensures that when an lchan activation has succeeded, and we have already
* sent ACKs like Immediate Assignment or BSSMAP Assignment Complete, and if other errors
* occur later, e.g. during release, that we don't send a NACK out of context. */
bool concluded;
- bool requires_voice_stream;
- bool wait_before_switching_rtp; /*< true = requires LCHAN_EV_READY_TO_SWITCH_RTP */
- uint16_t msc_assigned_cic;
enum gsm0808_cause gsm0808_error_cause;
- struct gsm_lchan *re_use_mgw_endpoint_from_lchan;
} activate;
struct {
diff --git a/include/osmocom/bsc/lchan_fsm.h b/include/osmocom/bsc/lchan_fsm.h
index 48cd3836a..55ab02400 100644
--- a/include/osmocom/bsc/lchan_fsm.h
+++ b/include/osmocom/bsc/lchan_fsm.h
@@ -52,19 +52,6 @@ void lchan_fsm_alloc(struct gsm_lchan *lchan);
void lchan_release(struct gsm_lchan *lchan, bool do_rr_release,
bool err, enum gsm48_rr_cause cause_rr);
-struct lchan_activate_info {
- enum lchan_activate_mode activ_for;
- struct gsm_subscriber_connection *for_conn;
- /* This always is for a specific lchan, so its lchan->type indicates full or half rate.
- * When a dyn TS was selected, the lchan->type has been set to the desired rate. */
- enum gsm48_chan_mode chan_mode;
- uint16_t s15_s0;
- bool requires_voice_stream;
- bool wait_before_switching_rtp;
- uint16_t msc_assigned_cic;
- struct gsm_lchan *old_lchan;
-};
-
void lchan_activate(struct gsm_lchan *lchan, struct lchan_activate_info *info);
void lchan_ready_to_switch_rtp(struct gsm_lchan *lchan);
diff --git a/src/osmo-bsc/assignment_fsm.c b/src/osmo-bsc/assignment_fsm.c
index 8f236d10c..0d0369aee 100644
--- a/src/osmo-bsc/assignment_fsm.c
+++ b/src/osmo-bsc/assignment_fsm.c
@@ -422,7 +422,7 @@ void assignment_fsm_start(struct gsm_subscriber_connection *conn, struct gsm_bts
.s15_s0 = req->s15_s0,
.requires_voice_stream = conn->assignment.requires_voice_stream,
.msc_assigned_cic = req->msc_assigned_cic,
- .old_lchan = conn->lchan,
+ .re_use_mgw_endpoint_from_lchan = conn->lchan,
};
lchan_activate(conn->assignment.new_lchan, &info);
}
diff --git a/src/osmo-bsc/bsc_subscr_conn_fsm.c b/src/osmo-bsc/bsc_subscr_conn_fsm.c
index 85e754fa4..c1ac6ebf4 100644
--- a/src/osmo-bsc/bsc_subscr_conn_fsm.c
+++ b/src/osmo-bsc/bsc_subscr_conn_fsm.c
@@ -550,7 +550,7 @@ bool gscon_connect_mgw_to_msc(struct gsm_subscriber_connection *conn,
} else
verb = MGCP_VERB_CRCX;
- gscon_ensure_mgw_endpoint(conn, for_lchan->activate.msc_assigned_cic);
+ gscon_ensure_mgw_endpoint(conn, for_lchan->activate.info.msc_assigned_cic);
if (!conn->user_plane.mgw_endpoint) {
LOGPFSML(conn->fi, LOGL_ERROR, "Unable to allocate endpoint info\n");
diff --git a/src/osmo-bsc/handover_fsm.c b/src/osmo-bsc/handover_fsm.c
index aae50b96a..35f2e5553 100644
--- a/src/osmo-bsc/handover_fsm.c
+++ b/src/osmo-bsc/handover_fsm.c
@@ -360,7 +360,7 @@ static void handover_start_intra_bsc(struct gsm_subscriber_connection *conn)
.chan_mode = conn->lchan->tch_mode,
.requires_voice_stream = conn->lchan->mgw_endpoint_ci_bts ? true : false,
.msc_assigned_cic = conn->ho.inter_bsc_in.msc_assigned_cic,
- .old_lchan = conn->lchan,
+ .re_use_mgw_endpoint_from_lchan = conn->lchan,
.wait_before_switching_rtp = true,
};
@@ -706,7 +706,7 @@ static void send_handover_performed(struct gsm_subscriber_connection *conn)
ho_perf_params.chosen_encr_alg = lchan->encr.alg_id;
ho_perf_params.chosen_encr_alg_present = true;
- if (ho->new_lchan->activate.requires_voice_stream) {
+ if (ho->new_lchan->activate.info.requires_voice_stream) {
/* Speech Version (chosen) 3.2.2.51 */
ho_perf_params.speech_version_chosen = gsm0808_permitted_speech(lchan->type, lchan->tch_mode);
ho_perf_params.speech_version_chosen_present = true;
@@ -1010,7 +1010,7 @@ 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.requires_voice_stream
+ 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
diff --git a/src/osmo-bsc/lchan_fsm.c b/src/osmo-bsc/lchan_fsm.c
index 6a95d4c57..9181b322c 100644
--- a/src/osmo-bsc/lchan_fsm.c
+++ b/src/osmo-bsc/lchan_fsm.c
@@ -151,7 +151,7 @@ static void lchan_on_fully_established(struct gsm_lchan *lchan)
return;
lchan->activate.concluded = true;
- switch (lchan->activate.activ_for) {
+ switch (lchan->activate.info.activ_for) {
case FOR_MS_CHANNEL_REQUEST:
/* No signalling to do here, MS is free to use the channel, and should go on to connect
* to the MSC and establish a subscriber connection. */
@@ -201,7 +201,7 @@ static void lchan_on_fully_established(struct gsm_lchan *lchan)
default:
LOG_LCHAN(lchan, LOGL_NOTICE, "lchan %s fully established\n",
- lchan_activate_mode_name(lchan->activate.activ_for));
+ lchan_activate_mode_name(lchan->activate.info.activ_for));
break;
}
}
@@ -238,7 +238,7 @@ struct state_timeout lchan_fsm_timeouts[32] = {
lchan_set_last_error(_lchan, "lchan %s in state %s: " fmt, \
_lchan->activate.concluded ? "failure" : "allocation failed", \
osmo_fsm_state_name(fsm, state_was), ## args); \
- lchan_on_activation_failure(_lchan, _lchan->activate.activ_for, _lchan->conn); \
+ lchan_on_activation_failure(_lchan, _lchan->activate.info.activ_for, _lchan->conn); \
if (fi->state != state_chg) \
lchan_fsm_state_chg(state_chg); \
else \
@@ -495,8 +495,6 @@ static void lchan_fsm_unused(struct osmo_fsm_inst *fi, uint32_t event, void *dat
{
struct lchan_activate_info *info = data;
struct gsm_lchan *lchan = lchan_fi_lchan(fi);
- struct gsm_bts *bts = lchan->ts->trx->bts;
- struct gsm48_multi_rate_conf mr_conf;
switch (event) {
@@ -507,63 +505,8 @@ static void lchan_fsm_unused(struct osmo_fsm_inst *fi, uint32_t event, void *dat
lchan_set_last_error(lchan, NULL);
lchan->release.requested = false;
- lchan->conn = info->for_conn;
- lchan->activate.activ_for = info->activ_for;
- lchan->activate.requires_voice_stream = info->requires_voice_stream;
- lchan->activate.wait_before_switching_rtp = info->wait_before_switching_rtp;
- lchan->activate.msc_assigned_cic = info->msc_assigned_cic;
+ lchan->activate.info = *info;
lchan->activate.concluded = false;
- lchan->activate.re_use_mgw_endpoint_from_lchan = info->old_lchan;
-
- if (info->old_lchan)
- lchan->encr = info->old_lchan->encr;
- else {
- lchan->encr = (struct gsm_encr){
- .alg_id = RSL_ENC_ALG_A5(0), /* no encryption */
- };
- }
-
- /* If there is a previous lchan, and the new lchan is on the same cell as previous one,
- * take over power and TA values. Otherwise, use max power and zero TA. */
- if (info->old_lchan && info->old_lchan->ts->trx->bts == bts) {
- lchan->ms_power = info->old_lchan->ms_power;
- lchan->bs_power = info->old_lchan->bs_power;
- lchan->rqd_ta = info->old_lchan->rqd_ta;
- } else {
- lchan->ms_power = ms_pwr_ctl_lvl(bts->band, bts->ms_max_power);
- /* From lchan_reset():
- * - bs_power is still zero, 0dB reduction, output power = Pn.
- * - TA is still zero, to be determined by RACH. */
- }
-
- if (info->chan_mode == GSM48_CMODE_SPEECH_AMR) {
- gsm48_mr_cfg_from_gsm0808_sc_cfg(&mr_conf, info->s15_s0);
- if (lchan_mr_config(lchan, &mr_conf) < 0) {
- lchan_fail("Can not generate multirate configuration IE\n");
- return;
- }
- }
-
- switch (info->chan_mode) {
-
- case GSM48_CMODE_SIGN:
- lchan->rsl_cmode = RSL_CMOD_SPD_SIGN;
- lchan->tch_mode = GSM48_CMODE_SIGN;
- break;
-
- case GSM48_CMODE_SPEECH_V1:
- case GSM48_CMODE_SPEECH_EFR:
- case GSM48_CMODE_SPEECH_AMR:
- lchan->rsl_cmode = RSL_CMOD_SPD_SPEECH;
- lchan->tch_mode = info->chan_mode;
- break;
-
- default:
- lchan_fail("Not implemented: cannot activate for chan mode %s",
- gsm48_chan_mode_name(info->chan_mode));
- return;
- }
-
lchan_fsm_state_chg(LCHAN_ST_WAIT_TS_READY);
break;
@@ -575,18 +518,75 @@ static void lchan_fsm_unused(struct osmo_fsm_inst *fi, uint32_t event, void *dat
static void lchan_fsm_wait_ts_ready_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
{
struct gsm_lchan *lchan = lchan_fi_lchan(fi);
- struct mgwep_ci *use_mgwep_ci = lchan_use_mgw_endpoint_ci_bts(lchan);
+ struct gsm48_multi_rate_conf mr_conf;
+ struct gsm_bts *bts = lchan->ts->trx->bts;
+ struct mgwep_ci *use_mgwep_ci;
+ struct gsm_lchan *old_lchan = lchan->activate.info.re_use_mgw_endpoint_from_lchan;
+ struct lchan_activate_info *info = &lchan->activate.info;
if (lchan->release.requested) {
lchan_fail("Release requested while activating");
return;
}
+ lchan->conn = info->for_conn;
+
+ if (old_lchan)
+ lchan->encr = old_lchan->encr;
+ else {
+ lchan->encr = (struct gsm_encr){
+ .alg_id = RSL_ENC_ALG_A5(0), /* no encryption */
+ };
+ }
+
+ /* If there is a previous lchan, and the new lchan is on the same cell as previous one,
+ * take over power and TA values. Otherwise, use max power and zero TA. */
+ if (old_lchan && old_lchan->ts->trx->bts == bts) {
+ lchan->ms_power = old_lchan->ms_power;
+ lchan->bs_power = old_lchan->bs_power;
+ lchan->rqd_ta = old_lchan->rqd_ta;
+ } else {
+ lchan->ms_power = ms_pwr_ctl_lvl(bts->band, bts->ms_max_power);
+ /* From lchan_reset():
+ * - bs_power is still zero, 0dB reduction, output power = Pn.
+ * - TA is still zero, to be determined by RACH. */
+ }
+
+ if (info->chan_mode == GSM48_CMODE_SPEECH_AMR) {
+ gsm48_mr_cfg_from_gsm0808_sc_cfg(&mr_conf, info->s15_s0);
+ if (lchan_mr_config(lchan, &mr_conf) < 0) {
+ lchan_fail("Can not generate multirate configuration IE\n");
+ return;
+ }
+ }
+
+ switch (info->chan_mode) {
+
+ case GSM48_CMODE_SIGN:
+ lchan->rsl_cmode = RSL_CMOD_SPD_SIGN;
+ lchan->tch_mode = GSM48_CMODE_SIGN;
+ break;
+
+ case GSM48_CMODE_SPEECH_V1:
+ case GSM48_CMODE_SPEECH_EFR:
+ case GSM48_CMODE_SPEECH_AMR:
+ lchan->rsl_cmode = RSL_CMOD_SPD_SPEECH;
+ lchan->tch_mode = info->chan_mode;
+ break;
+
+ default:
+ lchan_fail("Not implemented: cannot activate for chan mode %s",
+ gsm48_chan_mode_name(info->chan_mode));
+ return;
+ }
+
+ use_mgwep_ci = lchan_use_mgw_endpoint_ci_bts(lchan);
+
LOG_LCHAN(lchan, LOGL_INFO,
"Activation requested: %s voice=%s MGW-ci=%s type=%s tch-mode=%s\n",
- lchan_activate_mode_name(lchan->activate.activ_for),
- lchan->activate.requires_voice_stream ? "yes" : "no",
- lchan->activate.requires_voice_stream ?
+ lchan_activate_mode_name(lchan->activate.info.activ_for),
+ lchan->activate.info.requires_voice_stream ? "yes" : "no",
+ lchan->activate.info.requires_voice_stream ?
(use_mgwep_ci ? mgwep_ci_name(use_mgwep_ci) : "new")
: "none",
gsm_lchant_name(lchan->type),
@@ -597,7 +597,7 @@ static void lchan_fsm_wait_ts_ready_onenter(struct osmo_fsm_inst *fi, uint32_t p
osmo_fsm_inst_dispatch(lchan->ts->fi, TS_EV_LCHAN_REQUESTED, lchan);
/* Prepare an MGW endpoint CI if appropriate. */
- if (lchan->activate.requires_voice_stream)
+ if (lchan->activate.info.requires_voice_stream)
lchan_rtp_fsm_start(lchan);
}
@@ -641,7 +641,7 @@ static void lchan_fsm_wait_activ_ack_onenter(struct osmo_fsm_inst *fi, uint32_t
return;
}
- switch (lchan->activate.activ_for) {
+ switch (lchan->activate.info.activ_for) {
case FOR_MS_CHANNEL_REQUEST:
act_type = RSL_ACT_INTRA_IMM_ASS;
break;
@@ -723,7 +723,7 @@ static void lchan_fsm_post_activ_ack(struct osmo_fsm_inst *fi)
return;
}
- switch (lchan->activate.activ_for) {
+ switch (lchan->activate.info.activ_for) {
case FOR_MS_CHANNEL_REQUEST:
rc = rsl_tx_imm_assignment(lchan);
@@ -778,7 +778,7 @@ static void lchan_fsm_post_activ_ack(struct osmo_fsm_inst *fi)
default:
LOG_LCHAN(lchan, LOGL_NOTICE, "lchan %s is now active\n",
- lchan_activate_mode_name(lchan->activate.activ_for));
+ lchan_activate_mode_name(lchan->activate.info.activ_for));
break;
}
@@ -798,7 +798,7 @@ static void lchan_fsm_wait_rll_rtp_establish(struct osmo_fsm_inst *fi, uint32_t
switch (event) {
case LCHAN_EV_RLL_ESTABLISH_IND:
- if (!lchan->activate.requires_voice_stream
+ if (!lchan->activate.info.requires_voice_stream
|| lchan_rtp_established(lchan))
lchan_fsm_state_chg(LCHAN_ST_ESTABLISHED);
return;
@@ -1395,6 +1395,8 @@ void lchan_forget_conn(struct gsm_lchan *lchan)
if (!lchan)
return;
+ lchan->activate.info.for_conn = NULL;
+
conn = lchan->conn;
if (conn) {
/* Log for both lchan FSM and conn FSM to ease reading the log in case of problems */
diff --git a/src/osmo-bsc/lchan_rtp_fsm.c b/src/osmo-bsc/lchan_rtp_fsm.c
index 6ab3da4d9..84cc28729 100644
--- a/src/osmo-bsc/lchan_rtp_fsm.c
+++ b/src/osmo-bsc/lchan_rtp_fsm.c
@@ -111,9 +111,9 @@ void lchan_rtp_fsm_start(struct gsm_lchan *lchan)
/* Use old lchan only if there is an MGW endpoint present. Otherwise, on ROLLBACK, we might put
* an endpoint "back" to an lchan that never had one to begin with. */
- if (lchan->activate.re_use_mgw_endpoint_from_lchan
- && !lchan->activate.re_use_mgw_endpoint_from_lchan->mgw_endpoint_ci_bts)
- lchan->activate.re_use_mgw_endpoint_from_lchan = NULL;
+ if (lchan->activate.info.re_use_mgw_endpoint_from_lchan
+ && !lchan->activate.info.re_use_mgw_endpoint_from_lchan->mgw_endpoint_ci_bts)
+ lchan->activate.info.re_use_mgw_endpoint_from_lchan = NULL;
lchan_rtp_fsm_state_chg(LCHAN_RTP_ST_WAIT_MGW_ENDPOINT_AVAILABLE);
}
@@ -127,8 +127,8 @@ struct mgwep_ci *lchan_use_mgw_endpoint_ci_bts(struct gsm_lchan *lchan)
return lchan->mgw_endpoint_ci_bts;
if (lchan_state_is(lchan, LCHAN_ST_ESTABLISHED))
return NULL;
- if (lchan->activate.re_use_mgw_endpoint_from_lchan)
- return lchan->activate.re_use_mgw_endpoint_from_lchan->mgw_endpoint_ci_bts;
+ if (lchan->activate.info.re_use_mgw_endpoint_from_lchan)
+ return lchan->activate.info.re_use_mgw_endpoint_from_lchan->mgw_endpoint_ci_bts;
return NULL;
}
@@ -147,7 +147,7 @@ static void lchan_rtp_fsm_wait_mgw_endpoint_available_onenter(struct osmo_fsm_in
return;
}
- mgwep = gscon_ensure_mgw_endpoint(lchan->conn, lchan->activate.msc_assigned_cic);
+ mgwep = gscon_ensure_mgw_endpoint(lchan->conn, lchan->activate.info.msc_assigned_cic);
if (!mgwep) {
lchan_rtp_fail("Internal error: cannot obtain MGW endpoint handle for conn");
return;
@@ -232,7 +232,7 @@ static void lchan_rtp_fsm_switch_rtp(struct osmo_fsm_inst *fi)
{
struct gsm_lchan *lchan = lchan_rtp_fi_lchan(fi);
- if (lchan->activate.wait_before_switching_rtp) {
+ if (lchan->activate.info.wait_before_switching_rtp) {
LOG_LCHAN_RTP(lchan, LOGL_DEBUG,
"Waiting for an event by caller before switching RTP\n");
lchan_rtp_fsm_state_chg(LCHAN_RTP_ST_WAIT_READY_TO_SWITCH_RTP);
@@ -305,7 +305,7 @@ static void lchan_rtp_fsm_wait_ipacc_crcx_ack(struct osmo_fsm_inst *fi, uint32_t
return;
case LCHAN_RTP_EV_READY_TO_SWITCH_RTP:
- lchan->activate.wait_before_switching_rtp = false;
+ lchan->activate.info.wait_before_switching_rtp = false;
return;
case LCHAN_RTP_EV_RELEASE:
@@ -365,7 +365,7 @@ static void lchan_rtp_fsm_wait_ipacc_mdcx_ack(struct osmo_fsm_inst *fi, uint32_t
return;
case LCHAN_RTP_EV_READY_TO_SWITCH_RTP:
- lchan->activate.wait_before_switching_rtp = false;
+ lchan->activate.info.wait_before_switching_rtp = false;
return;
case LCHAN_RTP_EV_RELEASE:
@@ -437,7 +437,7 @@ static void lchan_rtp_fsm_wait_mgw_endpoint_configured_onenter(struct osmo_fsm_i
uint32_t prev_state)
{
struct gsm_lchan *lchan = lchan_rtp_fi_lchan(fi);
- struct gsm_lchan *old_lchan = lchan->activate.re_use_mgw_endpoint_from_lchan;
+ struct gsm_lchan *old_lchan = lchan->activate.info.re_use_mgw_endpoint_from_lchan;
if (lchan->release.requested) {
lchan_rtp_fail("Release requested while activating");
@@ -514,7 +514,7 @@ static void lchan_rtp_fsm_ready(struct osmo_fsm_inst *fi, uint32_t event, void *
static void lchan_rtp_fsm_rollback_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
{
struct gsm_lchan *lchan = lchan_rtp_fi_lchan(fi);
- struct gsm_lchan *old_lchan = lchan->activate.re_use_mgw_endpoint_from_lchan;
+ struct gsm_lchan *old_lchan = lchan->activate.info.re_use_mgw_endpoint_from_lchan;
if (!lchan->mgw_endpoint_ci_bts || !old_lchan) {
osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REQUEST, 0);
@@ -526,7 +526,7 @@ static void lchan_rtp_fsm_rollback_onenter(struct osmo_fsm_inst *fi, uint32_t pr
static void lchan_rtp_fsm_rollback(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
struct gsm_lchan *lchan = lchan_rtp_fi_lchan(fi);
- struct gsm_lchan *old_lchan = lchan->activate.re_use_mgw_endpoint_from_lchan;
+ struct gsm_lchan *old_lchan = lchan->activate.info.re_use_mgw_endpoint_from_lchan;
switch (event) {
@@ -560,7 +560,7 @@ static void lchan_rtp_fsm_established_onenter(struct osmo_fsm_inst *fi, uint32_t
struct gsm_lchan *lchan = lchan_rtp_fi_lchan(fi);
/* Make sure that we will not hand back the MGW endpoint to any old lchan from here on. */
- lchan->activate.re_use_mgw_endpoint_from_lchan = NULL;
+ lchan->activate.info.re_use_mgw_endpoint_from_lchan = NULL;
}
static void lchan_rtp_fsm_established(struct osmo_fsm_inst *fi, uint32_t event, void *data)
diff --git a/src/osmo-bsc/osmo_bsc_bssap.c b/src/osmo-bsc/osmo_bsc_bssap.c
index 5b7b79a8f..01a55ff85 100644
--- a/src/osmo-bsc/osmo_bsc_bssap.c
+++ b/src/osmo-bsc/osmo_bsc_bssap.c
@@ -1108,7 +1108,7 @@ enum handover_result bsc_tx_bssmap_ho_complete(struct gsm_subscriber_connection
};
/* speech_codec_chosen */
- if (ho->new_lchan->activate.requires_voice_stream && gscon_is_aoip(conn)) {
+ if (ho->new_lchan->activate.info.requires_voice_stream && gscon_is_aoip(conn)) {
int perm_spch = gsm0808_permitted_speech(lchan->type, lchan->tch_mode);
params.speech_codec_chosen_present = true;
rc = gsm0808_speech_codec_from_chan_type(&params.speech_codec_chosen, perm_spch);