From 0951d756655d7c637efd450d125f7a9ae38098eb Mon Sep 17 00:00:00 2001 From: Neels Hofmeyr Date: Tue, 27 Apr 2021 23:17:14 +0000 Subject: make sure channel mode and s15_s0 are updated only after an ACK I noticed during testing that an lchan used as TCH/F in fact still had its channel mode set to Signalling -- because on Assignment, the Speech mode used to be placed in the *previous* lchan and the new lchan was never updated after the Activ ACK. This is unbearable confusion which I complained about numerous times, so far mostly for cosmetic reasons. But implementing re-assignment properly actually requires this to be cleaned up. Keep all volatile chan mode settings in lchan->activate.* or lchan->modify.*, and only update lchan->* members when an ACK has been received for those settings. So a failed request keeps a sane state. Make sure that those settings are in fact updated in the proper lchan, upon an ACK, so that subsequent re-assignment or mode-modify know the accurate lchan state. Related are upcoming patches that sort out the AMR multirate configuration in a similar fashion, see Iebac2dc26412d877e5364f90d6f2ed7a7952351e Ia7519d2fa9e7f0b61b222d27d077bde4660c40b9 Ie57f9d0e3912632903d9740291225bfd1634ed47. Related: SYS#5315 OS#4940 OS#3787 OS#3833 Change-Id: Ie0da36124d73efc28a8809b63d7c96e2167fc412 --- include/osmocom/bsc/gsm_data.h | 28 +++++---------- src/osmo-bsc/abis_rsl.c | 37 +++++++++++--------- src/osmo-bsc/assignment_fsm.c | 71 +++++++++++++++++++------------------- src/osmo-bsc/bsc_vty.c | 22 ++++++++---- src/osmo-bsc/gsm_04_08_rr.c | 16 ++++----- src/osmo-bsc/gsm_data.c | 16 +++++++++ src/osmo-bsc/handover_decision_2.c | 24 +++++++------ src/osmo-bsc/handover_fsm.c | 16 ++++----- src/osmo-bsc/lchan_fsm.c | 33 ++++++++++-------- src/osmo-bsc/lchan_rtp_fsm.c | 12 +++---- src/osmo-bsc/osmo_bsc_bssap.c | 57 +++++++++++++++--------------- src/osmo-bsc/osmo_bsc_lcls.c | 7 ++-- tests/handover/handover_test.c | 10 +++--- 13 files changed, 186 insertions(+), 163 deletions(-) diff --git a/include/osmocom/bsc/gsm_data.h b/include/osmocom/bsc/gsm_data.h index 4b175a4c0..68c307425 100644 --- a/include/osmocom/bsc/gsm_data.h +++ b/include/osmocom/bsc/gsm_data.h @@ -105,6 +105,8 @@ enum channel_rate { CH_RATE_FULL, }; +enum channel_rate chan_t_to_chan_rate(enum gsm_chan_t chan_t); + struct channel_mode_and_rate { enum gsm48_chan_mode chan_mode; enum channel_rate chan_rate; @@ -137,7 +139,7 @@ struct assignment_request { /* Rate/codec setting in preference order (need at least 1 !) */ int n_ch_mode_rate; - struct channel_mode_and_rate ch_mode_rate[3]; + struct channel_mode_and_rate ch_mode_rate_list[3]; }; /* State of an ongoing Assignment, while the assignment_fsm is still busy. This serves as state separation to keep the @@ -146,6 +148,7 @@ struct assignment_request { struct assignment_fsm_data { struct assignment_request req; bool requires_voice_stream; + struct channel_mode_and_rate selected_ch_mode_rate; struct osmo_fsm_inst *fi; struct gsm_lchan *new_lchan; @@ -585,12 +588,8 @@ static inline const char *lchan_activate_mode_name(enum lchan_activate_for activ struct lchan_activate_info { enum lchan_activate_for 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; + struct channel_mode_and_rate ch_mode_rate; struct gsm_encr encr; - /* AMR config */ - 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; @@ -613,11 +612,9 @@ static inline const char *lchan_modify_for_name(enum lchan_modify_for modify_for struct lchan_modify_info { enum lchan_modify_for modify_for; - enum gsm48_chan_mode chan_mode; + struct channel_mode_and_rate ch_mode_rate; bool requires_voice_stream; uint16_t msc_assigned_cic; - /* AMR config */ - uint16_t s15_s0; }; struct gsm_lchan { @@ -672,8 +669,6 @@ struct gsm_lchan { enum gsm_chan_t type; /* RSL channel mode */ enum rsl_cmod_spd rsl_cmode; - /* If TCH, traffic channel mode */ - enum gsm48_chan_mode tch_mode; enum lchan_csd_mode csd_mode; /* Power levels for MS and BTS */ uint8_t bs_power; @@ -684,8 +679,6 @@ struct gsm_lchan { /* AMR bits */ uint8_t mr_ms_lv[7]; uint8_t mr_bts_lv[7]; - /* AMR bits were based on these rate bits: */ - uint16_t s15_s0; /* Established data link layer services */ uint8_t sapis[8]; @@ -727,12 +720,9 @@ struct gsm_lchan { struct gsm_subscriber_connection *conn; - /* Depending on the preferences that where submitted together with - * the assignment and the current channel load, the BSC has to select - * one of the offered codec/rates. The final selection by the BSC is - * stored here and is used when sending the assignment complete or - * when performing a handover procedure. */ - struct channel_mode_and_rate ch_mode_rate; + /* After the Channel Activation ACK or RSL Mode Modify ACK is received, this reflects the actually used + * channel_mode_and_rate. */ + struct channel_mode_and_rate current_ch_mode_rate; }; /* One Timeslot in a TRX */ diff --git a/src/osmo-bsc/abis_rsl.c b/src/osmo-bsc/abis_rsl.c index eb303456d..1aaebe3a6 100644 --- a/src/osmo-bsc/abis_rsl.c +++ b/src/osmo-bsc/abis_rsl.c @@ -70,7 +70,7 @@ static void count_codecs(struct gsm_bts *bts, struct gsm_lchan *lchan) OSMO_ASSERT(bts); if (lchan->type == GSM_LCHAN_TCH_H) { - switch (lchan->tch_mode) { + switch (lchan->current_ch_mode_rate.chan_mode) { case GSM48_CMODE_SPEECH_AMR: rate_ctr_inc(&bts->bts_ctrs->ctr[BTS_CTR_CODEC_AMR_H]); break; @@ -81,7 +81,7 @@ static void count_codecs(struct gsm_bts *bts, struct gsm_lchan *lchan) break; } } else if (lchan->type == GSM_LCHAN_TCH_F) { - switch (lchan->tch_mode) { + switch (lchan->current_ch_mode_rate.chan_mode) { case GSM48_CMODE_SPEECH_AMR: rate_ctr_inc(&bts->bts_ctrs->ctr[BTS_CTR_CODEC_AMR_F]); break; @@ -351,7 +351,8 @@ int rsl_chan_ms_power_ctrl(struct gsm_lchan *lchan) } static int channel_mode_from_lchan(struct rsl_ie_chan_mode *cm, - struct gsm_lchan *lchan) + struct gsm_lchan *lchan, + const struct channel_mode_and_rate *ch_mode_rate) { memset(cm, 0, sizeof(*cm)); @@ -366,7 +367,7 @@ static int channel_mode_from_lchan(struct rsl_ie_chan_mode *cm, cm->spd_ind = lchan->rsl_cmode; if (lchan->rsl_cmode == RSL_CMOD_SPD_SIGN && - lchan->tch_mode != GSM48_CMODE_SIGN) + ch_mode_rate->chan_mode != GSM48_CMODE_SIGN) LOGP(DRSL, LOGL_ERROR, "unsupported: rsl_mode == signalling, " "but tch_mode != signalling\n"); @@ -389,7 +390,7 @@ static int channel_mode_from_lchan(struct rsl_ie_chan_mode *cm, return -EINVAL; } - switch (lchan->tch_mode) { + switch (ch_mode_rate->chan_mode) { case GSM48_CMODE_SIGN: cm->chan_rate = 0; break; @@ -408,7 +409,7 @@ static int channel_mode_from_lchan(struct rsl_ie_chan_mode *cm, switch (lchan->csd_mode) { case LCHAN_CSD_M_NT: /* non-transparent CSD with RLP */ - switch (lchan->tch_mode) { + switch (ch_mode_rate->chan_mode) { case GSM48_CMODE_DATA_14k5: cm->chan_rate = RSL_CMOD_SP_NT_14k5; break; @@ -421,7 +422,7 @@ static int channel_mode_from_lchan(struct rsl_ie_chan_mode *cm, default: LOGP(DRSL, LOGL_ERROR, "unsupported lchan->tch_mode %u\n", - lchan->tch_mode); + ch_mode_rate->chan_mode); return -EINVAL; } break; @@ -458,20 +459,19 @@ static int channel_mode_from_lchan(struct rsl_ie_chan_mode *cm, } break; default: - LOGP(DRSL, LOGL_ERROR, - "unsupported lchan->tch_mode %u\n", - lchan->tch_mode); + LOGP(DRSL, LOGL_ERROR, "unsupported channel mode %u\n", ch_mode_rate->chan_mode); return -EINVAL; } return 0; } -static void mr_config_for_bts(struct gsm_lchan *lchan, struct msgb *msg) +static void mr_config_for_bts(struct gsm_lchan *lchan, struct msgb *msg, + const struct channel_mode_and_rate *ch_mode_rate) { uint8_t len; - if (lchan->tch_mode != GSM48_CMODE_SPEECH_AMR) + if (ch_mode_rate->chan_mode != GSM48_CMODE_SPEECH_AMR) return; len = lchan->mr_bts_lv[0]; @@ -532,7 +532,7 @@ int rsl_tx_chan_activ(struct gsm_lchan *lchan, uint8_t act_type, uint8_t ho_ref) /* PDCH activation is a job for rsl_tx_dyn_ts_pdch_act_deact(); */ OSMO_ASSERT(act_type != RSL_ACT_OSMO_PDCH); - rc = channel_mode_from_lchan(&cm, lchan); + rc = channel_mode_from_lchan(&cm, lchan, &lchan->activate.info.ch_mode_rate); if (rc < 0) { LOGP(DRSL, LOGL_ERROR, "%s Cannot find channel mode from lchan type\n", @@ -606,7 +606,7 @@ int rsl_tx_chan_activ(struct gsm_lchan *lchan, uint8_t act_type, uint8_t ho_ref) add_power_control_params(msg, RSL_IE_BS_POWER_PARAM, lchan); add_power_control_params(msg, RSL_IE_MS_POWER_PARAM, lchan); - mr_config_for_bts(lchan, msg); + mr_config_for_bts(lchan, msg, &lchan->activate.info.ch_mode_rate); rep_acch_cap_for_bts(lchan, msg); msg->dst = trx->rsl_link; @@ -637,7 +637,7 @@ int rsl_chan_mode_modify_req(struct gsm_lchan *lchan) uint8_t chan_nr = gsm_lchan2chan_nr(lchan); struct rsl_ie_chan_mode cm; - rc = channel_mode_from_lchan(&cm, lchan); + rc = channel_mode_from_lchan(&cm, lchan, &lchan->modify.info.ch_mode_rate); if (rc < 0) return rc; @@ -656,7 +656,7 @@ int rsl_chan_mode_modify_req(struct gsm_lchan *lchan) msgb_tlv_put(msg, RSL_IE_ENCR_INFO, rc, encr_info); } - mr_config_for_bts(lchan, msg); + mr_config_for_bts(lchan, msg, &lchan->modify.info.ch_mode_rate); rep_acch_cap_for_bts(lchan, msg); msg->dst = lchan->ts->trx->rsl_link; @@ -1768,7 +1768,10 @@ void abis_rsl_chan_rqd_queue_poll(struct gsm_bts *bts) gsm_chreq_name(rqd->reason), rqd->ref.ra, rqd->ta); info = (struct lchan_activate_info){ .activ_for = ACTIVATE_FOR_MS_CHANNEL_REQUEST, - .chan_mode = GSM48_CMODE_SIGN, + .ch_mode_rate = { + .chan_mode = GSM48_CMODE_SIGN, + .chan_rate = CH_RATE_SDCCH, + }, .ta = rqd->ta, .ta_known = true, }; diff --git a/src/osmo-bsc/assignment_fsm.c b/src/osmo-bsc/assignment_fsm.c index 60e3342a0..aeb9a2417 100644 --- a/src/osmo-bsc/assignment_fsm.c +++ b/src/osmo-bsc/assignment_fsm.c @@ -85,7 +85,7 @@ static const struct osmo_tdef_state_timeout assignment_fsm_timeouts[32] = { if (bts) { \ rate_ctr_inc(&bts->bts_ctrs->ctr[BTS_##counter]); \ if (BTS_##counter != BTS_CTR_ASSIGNMENT_NO_CHANNEL) { \ - switch (conn->lchan->ch_mode_rate.chan_mode) { \ + switch (conn->assignment.req.ch_mode_rate_list[0].chan_mode) { \ case GSM48_CMODE_SIGN: \ rate_ctr_inc(&bts->bts_ctrs->ctr[BTS_##counter##_SIGN]); \ break; \ @@ -175,18 +175,18 @@ static void send_assignment_complete(struct gsm_subscriber_connection *conn) struct gsm_lchan *lchan = conn->lchan; struct osmo_fsm_inst *fi = conn->fi; - chosen_channel = gsm0808_chosen_channel(lchan->type, lchan->tch_mode); + chosen_channel = gsm0808_chosen_channel(lchan->type, lchan->current_ch_mode_rate.chan_mode); if (!chosen_channel) { assignment_fail(GSM0808_CAUSE_EQUIPMENT_FAILURE, "Unable to compose Chosen Channel for mode=%s type=%s", - get_value_string(gsm48_chan_mode_names, lchan->tch_mode), + get_value_string(gsm48_chan_mode_names, lchan->current_ch_mode_rate.chan_mode), gsm_lchant_name(lchan->type)); return; } /* Generate voice related fields */ if (conn->assignment.requires_voice_stream) { - perm_spch = gsm0808_permitted_speech(lchan->type, lchan->tch_mode); + perm_spch = gsm0808_permitted_speech(lchan->type, lchan->current_ch_mode_rate.chan_mode); if (gscon_is_aoip(conn)) { if (!osmo_mgcpc_ep_ci_get_crcx_info_to_sockaddr(conn->user_plane.mgw_endpoint_ci_msc, @@ -212,7 +212,7 @@ static void send_assignment_complete(struct gsm_subscriber_connection *conn) if (gscon_is_aoip(conn)) { /* Extrapolate speech codec from speech mode */ gsm0808_speech_codec_from_chan_type(&sc, perm_spch); - sc.cfg = conn->lchan->activate.info.s15_s0; + sc.cfg = conn->lchan->activate.info.ch_mode_rate.s15_s0; sc_ptr = ≻ } } @@ -395,11 +395,11 @@ static int check_requires_voice_stream(struct gsm_subscriber_connection *conn) * a mismatch is not permitted */ for (i = 0; i < req->n_ch_mode_rate; i++) { - rc = check_requires_voice(&requires_voice_alt, req->ch_mode_rate[i].chan_mode); + rc = check_requires_voice(&requires_voice_alt, req->ch_mode_rate_list[i].chan_mode); if (rc < 0) { assignment_fail(GSM0808_CAUSE_REQ_CODEC_TYPE_OR_CONFIG_NOT_SUPP, "Channel mode not supported (prev level %d): %s", i, - gsm48_chan_mode_name(req->ch_mode_rate[i].chan_mode)); + gsm48_chan_mode_name(req->ch_mode_rate_list[i].chan_mode)); return -EINVAL; } @@ -408,8 +408,8 @@ static int check_requires_voice_stream(struct gsm_subscriber_connection *conn) else if (requires_voice_alt != requires_voice_pref) { assignment_fail(GSM0808_CAUSE_REQ_CODEC_TYPE_OR_CONFIG_NOT_SUPP, "Requested a mix of Signalling and non-Signalling channel modes: %s != %s", - gsm48_chan_mode_name(req->ch_mode_rate[0].chan_mode), - gsm48_chan_mode_name(req->ch_mode_rate[i].chan_mode)); + gsm48_chan_mode_name(req->ch_mode_rate_list[0].chan_mode), + gsm48_chan_mode_name(req->ch_mode_rate_list[i].chan_mode)); return -EINVAL; } } @@ -431,9 +431,9 @@ static bool reuse_existing_lchan(struct gsm_subscriber_connection *conn) /* Check if the currently existing lchan is compatible with the * preferred rate/codec. */ for (i = 0; i < req->n_ch_mode_rate; i++) { - if (!lchan_type_compat_with_mode(conn->lchan->type, &req->ch_mode_rate[i])) + if (!lchan_type_compat_with_mode(conn->lchan->type, &req->ch_mode_rate_list[i])) continue; - conn->lchan->ch_mode_rate = req->ch_mode_rate[i]; + conn->assignment.selected_ch_mode_rate = req->ch_mode_rate_list[i]; return true; } @@ -485,12 +485,12 @@ void assignment_fsm_start(struct gsm_subscriber_connection *conn, struct gsm_bts /* If the requested mode and the current TCH mode matches up, just send the * assignment complete directly and be done with the assignment procedure. */ - if (conn->lchan->tch_mode == conn->lchan->ch_mode_rate.chan_mode) { + if (conn->lchan->current_ch_mode_rate.chan_mode == conn->assignment.selected_ch_mode_rate.chan_mode) { LOG_ASSIGNMENT(conn, LOGL_DEBUG, "Current lchan mode is compatible with requested chan_mode," " sending BSSMAP Assignment Complete directly." " requested chan_mode=%s; current lchan is %s\n", - gsm48_chan_mode_name(conn->lchan->ch_mode_rate.chan_mode), + gsm48_chan_mode_name(conn->assignment.selected_ch_mode_rate.chan_mode), gsm_lchan_name(conn->lchan)); if (req->assign_for == ASSIGN_FOR_BSSMAP_REQ) @@ -509,14 +509,13 @@ void assignment_fsm_start(struct gsm_subscriber_connection *conn, struct gsm_bts LOG_ASSIGNMENT(conn, LOGL_DEBUG, "Current lchan mode is not compatible with requested chan_mode," " so we will modify it. requested chan_mode=%s; current lchan is %s\n", - gsm48_chan_mode_name(conn->lchan->ch_mode_rate.chan_mode), + gsm48_chan_mode_name(conn->assignment.selected_ch_mode_rate.chan_mode), gsm_lchan_name(conn->lchan)); modif_info = (struct lchan_modify_info){ .modify_for = MODIFY_FOR_ASSIGNMENT, - .chan_mode = conn->lchan->ch_mode_rate.chan_mode, + .ch_mode_rate = conn->assignment.selected_ch_mode_rate, .requires_voice_stream = conn->assignment.requires_voice_stream, - .s15_s0 = conn->lchan->ch_mode_rate.s15_s0, .msc_assigned_cic = req->msc_assigned_cic, }; @@ -529,22 +528,23 @@ void assignment_fsm_start(struct gsm_subscriber_connection *conn, struct gsm_bts /* Try to allocate a new lchan in order of preference */ for (i = 0; i < req->n_ch_mode_rate; i++) { conn->assignment.new_lchan = lchan_select_by_chan_mode(bts, - req->ch_mode_rate[i].chan_mode, req->ch_mode_rate[i].chan_rate); - /* FIXME: at this point there is merely an assignment request with a given ch_mode_rate. Writing this to - * conn->lchan->ch_mode_rate is a violation of scopes: the lchan->* state should only be modified - * *after* the assignment is confirmed to be completed. Before that, this data should live in - * conn->assignment or the lchan_activate_info, the designated places for not-yet-confirmed data. See - * OS#3833 */ - conn->lchan->ch_mode_rate = req->ch_mode_rate[i]; - if (conn->assignment.new_lchan) - break; + req->ch_mode_rate_list[i].chan_mode, req->ch_mode_rate_list[i].chan_rate); + if (!conn->assignment.new_lchan) + continue; + LOG_ASSIGNMENT(conn, LOGL_DEBUG, "selected new lchan %s for mode[%d] = %s channel_rate=%d\n", + gsm_lchan_name(conn->assignment.new_lchan), + i, gsm48_chan_mode_name(req->ch_mode_rate_list[i].chan_mode), + req->ch_mode_rate_list[i].chan_rate); + + conn->assignment.selected_ch_mode_rate = req->ch_mode_rate_list[i]; + break; } /* Check whether the lchan allocation was successful or not and tear * down the assignment in case of failure. */ if (!conn->assignment.new_lchan) { assignment_count_result(CTR_ASSIGNMENT_NO_CHANNEL); - switch (req->ch_mode_rate[0].chan_mode) { + switch (req->ch_mode_rate_list[0].chan_mode) { case GSM48_CMODE_SIGN: rate_ctr_inc(&bts->bts_ctrs->ctr[BTS_CTR_ASSIGNMENT_NO_CHANNEL_SIGN]); break; @@ -559,12 +559,12 @@ void assignment_fsm_start(struct gsm_subscriber_connection *conn, struct gsm_bts assignment_fail(GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE, "BSSMAP Assignment Command:" " No lchan available for: pref=%s:%s / alt1=%s:%s / alt2=%s:%s\n", - gsm48_chan_mode_name(req->ch_mode_rate[0].chan_mode), - rate_names[req->ch_mode_rate[0].chan_rate], - req->n_ch_mode_rate > 1 ? gsm48_chan_mode_name(req->ch_mode_rate[1].chan_mode) : "", - req->n_ch_mode_rate > 1 ? rate_names[req->ch_mode_rate[1].chan_rate] : "", - req->n_ch_mode_rate > 2 ? gsm48_chan_mode_name(req->ch_mode_rate[2].chan_mode) : "", - req->n_ch_mode_rate > 2 ? rate_names[req->ch_mode_rate[2].chan_rate] : "" + gsm48_chan_mode_name(req->ch_mode_rate_list[0].chan_mode), + rate_names[req->ch_mode_rate_list[0].chan_rate], + req->n_ch_mode_rate > 1 ? gsm48_chan_mode_name(req->ch_mode_rate_list[1].chan_mode) : "", + req->n_ch_mode_rate > 1 ? rate_names[req->ch_mode_rate_list[1].chan_rate] : "", + req->n_ch_mode_rate > 2 ? gsm48_chan_mode_name(req->ch_mode_rate_list[2].chan_mode) : "", + req->n_ch_mode_rate > 2 ? rate_names[req->ch_mode_rate_list[2].chan_rate] : "" ); return; } @@ -572,8 +572,8 @@ void assignment_fsm_start(struct gsm_subscriber_connection *conn, struct gsm_bts assignment_fsm_update_id(conn); LOG_ASSIGNMENT(conn, LOGL_INFO, "Starting Assignment: chan_mode=%s, chan_type=%s," " aoip=%s MSC-rtp=%s:%u (osmux=%s)\n", - gsm48_chan_mode_name(conn->lchan->ch_mode_rate.chan_mode), - rate_names[conn->lchan->ch_mode_rate.chan_rate], + gsm48_chan_mode_name(conn->assignment.selected_ch_mode_rate.chan_mode), + rate_names[conn->assignment.selected_ch_mode_rate.chan_rate], req->aoip ? "yes" : "no", req->msc_rtp_addr, req->msc_rtp_port, req->use_osmux ? "yes" : "no"); @@ -581,9 +581,8 @@ void assignment_fsm_start(struct gsm_subscriber_connection *conn, struct gsm_bts activ_info = (struct lchan_activate_info){ .activ_for = ACTIVATE_FOR_ASSIGNMENT, .for_conn = conn, - .chan_mode = conn->lchan->ch_mode_rate.chan_mode, + .ch_mode_rate = conn->assignment.selected_ch_mode_rate, .encr = conn->lchan->encr, - .s15_s0 = conn->lchan->ch_mode_rate.s15_s0, .requires_voice_stream = conn->assignment.requires_voice_stream, .msc_assigned_cic = req->msc_assigned_cic, .re_use_mgw_endpoint_from_lchan = conn->lchan, diff --git a/src/osmo-bsc/bsc_vty.c b/src/osmo-bsc/bsc_vty.c index b964dbc9e..7ede51a05 100644 --- a/src/osmo-bsc/bsc_vty.c +++ b/src/osmo-bsc/bsc_vty.c @@ -1624,7 +1624,7 @@ static void lchan_dump_full_vty(struct vty *vty, struct gsm_lchan *lchan) ms_pwr_dbm(lchan->ts->trx->bts->band, lchan->ms_power), VTY_NEWLINE); vty_out(vty, " Channel Mode / Codec: %s%s", - gsm48_chan_mode_name(lchan->tch_mode), + gsm48_chan_mode_name(lchan->current_ch_mode_rate.chan_mode), VTY_NEWLINE); if (lchan->conn && lchan->conn->bsub) { vty_out(vty, " Subscriber:%s", VTY_NEWLINE); @@ -6071,13 +6071,17 @@ static int lchan_act_single(struct vty *vty, struct gsm_lchan *lchan, const char if (!strcmp(codec_str, "hr") || !strcmp(codec_str, "fr")) { info = (struct lchan_activate_info) { .activ_for = ACTIVATE_FOR_VTY, - .chan_mode = GSM48_CMODE_SPEECH_V1, + .ch_mode_rate = { + .chan_mode = GSM48_CMODE_SPEECH_V1, + }, .requires_voice_stream = false, }; } else if (!strcmp(codec_str, "efr")) { info = (struct lchan_activate_info) { .activ_for = ACTIVATE_FOR_VTY, - .chan_mode = GSM48_CMODE_SPEECH_EFR, + .ch_mode_rate = { + .chan_mode = GSM48_CMODE_SPEECH_EFR, + }, .requires_voice_stream = false, }; } else if (!strcmp(codec_str, "amr")) { @@ -6087,14 +6091,18 @@ static int lchan_act_single(struct vty *vty, struct gsm_lchan *lchan, const char } info = (struct lchan_activate_info) { .activ_for = ACTIVATE_FOR_VTY, - .chan_mode = GSM48_CMODE_SPEECH_AMR, - .s15_s0 = amr_modes[amr_mode], + .ch_mode_rate = { + .chan_mode = GSM48_CMODE_SPEECH_AMR, + .s15_s0 = amr_modes[amr_mode], + }, .requires_voice_stream = false, }; } else if (!strcmp(codec_str, "sig")) { info = (struct lchan_activate_info) { .activ_for = ACTIVATE_FOR_VTY, - .chan_mode = GSM48_CMODE_SIGN, + .ch_mode_rate = { + .chan_mode = GSM48_CMODE_SIGN, + }, .requires_voice_stream = false, }; } else { @@ -6102,6 +6110,8 @@ static int lchan_act_single(struct vty *vty, struct gsm_lchan *lchan, const char return CMD_WARNING; } + info.ch_mode_rate.chan_rate = chan_t_to_chan_rate(lchan_t); + vty_out(vty, "%% activating lchan %s as %s%s", gsm_lchan_name(lchan), gsm_chan_t_name(lchan->type), VTY_NEWLINE); lchan_activate(lchan, &info); diff --git a/src/osmo-bsc/gsm_04_08_rr.c b/src/osmo-bsc/gsm_04_08_rr.c index 764af7238..8a375cb55 100644 --- a/src/osmo-bsc/gsm_04_08_rr.c +++ b/src/osmo-bsc/gsm_04_08_rr.c @@ -234,7 +234,7 @@ int get_reason_by_chreq(uint8_t ra, int neci) static void mr_config_for_ms(struct gsm_lchan *lchan, struct msgb *msg) { - if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR) + if (lchan->current_ch_mode_rate.chan_mode == GSM48_CMODE_SPEECH_AMR) msgb_tlv_put(msg, GSM48_IE_MUL_RATE_CFG, lchan->mr_ms_lv[0], lchan->mr_ms_lv + 1); } @@ -538,7 +538,7 @@ struct msgb *gsm48_make_ho_cmd(struct gsm_lchan *new_lchan, uint8_t power_comman } /* FIXME: optional bits for type of synchronization? */ - msgb_tv_put(msg, GSM48_IE_CHANMODE_1, new_lchan->tch_mode); + msgb_tv_put(msg, GSM48_IE_CHANMODE_1, new_lchan->current_ch_mode_rate.chan_mode); /* Mobile Allocation (after time), TLV (see 3GPP TS 44.018, 10.5.2.21) */ if (new_lchan->ts->hopping.enabled) { @@ -548,7 +548,7 @@ struct msgb *gsm48_make_ho_cmd(struct gsm_lchan *new_lchan, uint8_t power_comman } /* in case of multi rate we need to attach a config */ - if (new_lchan->tch_mode == GSM48_CMODE_SPEECH_AMR) + if (new_lchan->current_ch_mode_rate.chan_mode == GSM48_CMODE_SPEECH_AMR) msgb_tlv_put(msg, GSM48_IE_MUL_RATE_CFG, new_lchan->mr_ms_lv[0], new_lchan->mr_ms_lv + 1); @@ -573,7 +573,8 @@ int gsm48_send_rr_ass_cmd(struct gsm_lchan *current_lchan, struct gsm_lchan *new struct gsm48_ass_cmd *ass = (struct gsm48_ass_cmd *) msgb_put(msg, sizeof(*ass)); - DEBUGP(DRR, "-> ASSIGNMENT COMMAND tch_mode=0x%02x\n", new_lchan->tch_mode); + DEBUGP(DRR, "-> ASSIGNMENT COMMAND tch_mode=0x%02x\n", + current_lchan->conn->assignment.selected_ch_mode_rate.chan_mode); msg->lchan = current_lchan; gh->proto_discr = GSM48_PDISC_RR; @@ -599,7 +600,7 @@ int gsm48_send_rr_ass_cmd(struct gsm_lchan *current_lchan, struct gsm_lchan *new si1->cell_channel_description); } - msgb_tv_put(msg, GSM48_IE_CHANMODE_1, new_lchan->tch_mode); + msgb_tv_put(msg, GSM48_IE_CHANMODE_1, current_lchan->conn->assignment.selected_ch_mode_rate.chan_mode); /* Mobile Allocation (freq. hopping), TLV (see 3GPP TS 44.018, 10.5.2.21) */ if (new_lchan->ts->hopping.enabled) { @@ -645,7 +646,6 @@ int gsm48_lchan_modify(struct gsm_lchan *lchan, uint8_t mode) DEBUGP(DRR, "-> CHANNEL MODE MODIFY mode=0x%02x\n", mode); - lchan->tch_mode = mode; msg->lchan = lchan; gh->proto_discr = GSM48_PDISC_RR; gh->msg_type = GSM48_MT_RR_CHAN_MODE_MODIF; @@ -670,10 +670,10 @@ int gsm48_rx_rr_modif_ack(struct msgb *msg) LOG_LCHAN(msg->lchan, LOGL_DEBUG, "CHANNEL MODE MODIFY ACK for %s\n", gsm48_chan_mode_name(mod->mode)); - if (mod->mode != msg->lchan->tch_mode) { + if (mod->mode != msg->lchan->modify.info.ch_mode_rate.chan_mode) { LOG_LCHAN(msg->lchan, LOGL_ERROR, "CHANNEL MODE MODIFY ACK has wrong mode: Wanted: %s Got: %s\n", - gsm48_chan_mode_name(msg->lchan->tch_mode), + gsm48_chan_mode_name(msg->lchan->modify.info.ch_mode_rate.chan_mode), gsm48_chan_mode_name(mod->mode)); return -1; } diff --git a/src/osmo-bsc/gsm_data.c b/src/osmo-bsc/gsm_data.c index 781db7c62..a37106491 100644 --- a/src/osmo-bsc/gsm_data.c +++ b/src/osmo-bsc/gsm_data.c @@ -685,6 +685,22 @@ enum gsm_phys_chan_config gsm_pchan_by_lchan_type(enum gsm_chan_t type) } } +enum channel_rate chan_t_to_chan_rate(enum gsm_chan_t chan_t) +{ + switch (chan_t) { + case GSM_LCHAN_SDCCH: + return CH_RATE_SDCCH; + case GSM_LCHAN_TCH_F: + return CH_RATE_FULL; + case GSM_LCHAN_TCH_H: + return CH_RATE_HALF; + default: + /* For other channel types, the channel_rate value is never used. It is fine to return an invalid value, + * and callers don't actually need to check for this. */ + return -1; + } +} + /* Can the timeslot in principle be used as this PCHAN kind? */ bool ts_is_capable_of_pchan(struct gsm_bts_trx_ts *ts, enum gsm_phys_chan_config pchan) { diff --git a/src/osmo-bsc/handover_decision_2.c b/src/osmo-bsc/handover_decision_2.c index 3326c0bb6..5b7d4b16c 100644 --- a/src/osmo-bsc/handover_decision_2.c +++ b/src/osmo-bsc/handover_decision_2.c @@ -52,7 +52,7 @@ lchan->ts->nr, \ lchan->nr, \ gsm_lchant_name(lchan->type), \ - gsm48_chan_mode_name(lchan->tch_mode), \ + gsm48_chan_mode_name(lchan->current_ch_mode_rate.chan_mode), \ bsc_subscr_name(lchan->conn? lchan->conn->bsub : NULL), \ ## args) @@ -63,7 +63,7 @@ lchan->ts->nr, \ lchan->nr, \ gsm_lchant_name(lchan->type), \ - gsm48_chan_mode_name(lchan->tch_mode), \ + gsm48_chan_mode_name(lchan->current_ch_mode_rate.chan_mode), \ new_bts->nr, \ bsc_subscr_name(lchan->conn? lchan->conn->bsub : NULL), \ ## args) @@ -75,7 +75,7 @@ lchan->ts->nr, \ lchan->nr, \ gsm_lchant_name(lchan->type), \ - gsm48_chan_mode_name(lchan->tch_mode), \ + gsm48_chan_mode_name(lchan->current_ch_mode_rate.chan_mode), \ gsm0808_cell_id_list_name(remote_cil), \ bsc_subscr_name(lchan->conn? lchan->conn->bsub : NULL), \ ## args) @@ -478,7 +478,7 @@ static void check_requirements(struct ho_candidate *c) /* compatibility check for codecs. * if so, the candidates for full rate and half rate are selected */ - switch (c->current.lchan->tch_mode) { + switch (c->current.lchan->current_ch_mode_rate.chan_mode) { case GSM48_CMODE_SPEECH_V1: switch (c->current.lchan->type) { case GSM_LCHAN_TCH_F: /* mandatory */ @@ -489,7 +489,7 @@ static void check_requirements(struct ho_candidate *c) LOGPHOLCHANTOBTS(c->current.lchan, c->target.bts, LOGL_DEBUG, "tch_mode='%s' type='%s' not supported\n", get_value_string(gsm48_chan_mode_names, - c->current.lchan->tch_mode), + c->current.lchan->current_ch_mode_rate.chan_mode), gsm_lchant_name(c->current.lchan->type)); break; } @@ -498,7 +498,8 @@ static void check_requirements(struct ho_candidate *c) break; default: LOGPHOLCHAN(c->current.lchan, LOGL_ERROR, "Unexpected channel type: neither TCH/F nor TCH/H for %s\n", - get_value_string(gsm48_chan_mode_names, c->current.lchan->tch_mode)); + get_value_string(gsm48_chan_mode_names, + c->current.lchan->current_ch_mode_rate.chan_mode)); return; } break; @@ -757,7 +758,7 @@ static void check_requirements_remote_bss(struct ho_candidate *c) /* compatibility check for codecs -- we have no notion of what the remote BSS supports. We can * only assume that a handover would work, and use only the local requirements. */ - switch (c->current.lchan->tch_mode) { + switch (c->current.lchan->current_ch_mode_rate.chan_mode) { case GSM48_CMODE_SPEECH_V1: switch (c->current.lchan->type) { case GSM_LCHAN_TCH_F: /* mandatory */ @@ -769,7 +770,8 @@ static void check_requirements_remote_bss(struct ho_candidate *c) break; default: LOGPHOLCHAN(c->current.lchan, LOGL_ERROR, "Unexpected channel type: neither TCH/F nor TCH/H for %s\n", - get_value_string(gsm48_chan_mode_names, c->current.lchan->tch_mode)); + get_value_string(gsm48_chan_mode_names, + c->current.lchan->current_ch_mode_rate.chan_mode)); return; } break; @@ -815,7 +817,7 @@ static int trigger_local_ho_or_as(struct ho_candidate *c, uint8_t requirements) bool full_rate = false; /* afs_bias becomes > 0, if AFS is used and is improved */ - if (c->current.lchan->tch_mode == GSM48_CMODE_SPEECH_AMR) + if (c->current.lchan->current_ch_mode_rate.chan_mode == GSM48_CMODE_SPEECH_AMR) afs_bias = ho_get_hodec2_afs_bias_rxlev(c->target.bts->ho); /* select TCH rate, prefer TCH/F if AFS is improved */ @@ -1243,7 +1245,7 @@ static void collect_candidates_for_lchan(struct gsm_lchan *lchan, static int find_alternative_lchan(struct gsm_lchan *lchan, bool include_weaker_rxlev) { struct gsm_bts *bts = lchan->ts->trx->bts; - int ahs = (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR + int ahs = (lchan->current_ch_mode_rate.chan_mode == GSM48_CMODE_SPEECH_AMR && lchan->type == GSM_LCHAN_TCH_H); int rxlev_current; struct ho_candidate clist[1 + ARRAY_SIZE(lchan->neigh_meas)]; @@ -1451,7 +1453,7 @@ static void on_measurement_report(struct gsm_meas_rep *mr) /* improve levels in case of AFS, if defined */ if (lchan->type == GSM_LCHAN_TCH_F - && lchan->tch_mode == GSM48_CMODE_SPEECH_AMR) { + && lchan->current_ch_mode_rate.chan_mode == GSM48_CMODE_SPEECH_AMR) { int av_rxlev_was = av_rxlev; int av_rxqual_was = av_rxqual; int rxlev_bias = ho_get_hodec2_afs_bias_rxlev(bts->ho); diff --git a/src/osmo-bsc/handover_fsm.c b/src/osmo-bsc/handover_fsm.c index 0b5a8be51..b7658c578 100644 --- a/src/osmo-bsc/handover_fsm.c +++ b/src/osmo-bsc/handover_fsm.c @@ -61,7 +61,7 @@ lchan ? lchan->ts->nr : 0, \ lchan ? gsm_lchant_name(lchan->type) : "?", \ lchan ? lchan->nr : 0, \ - lchan ? gsm48_chan_mode_name(lchan->tch_mode) : "?" + lchan ? gsm48_chan_mode_name(lchan->current_ch_mode_rate.chan_mode) : "?" #define LOG_FMT_TO_LCHAN "%u-%u-%u-%s%s%s-%u" #define LOG_ARGS_TO_LCHAN(lchan) \ @@ -398,14 +398,14 @@ static void handover_start_intra_bsc(struct gsm_subscriber_connection *conn) info = (struct lchan_activate_info){ .activ_for = ACTIVATE_FOR_HANDOVER, .for_conn = conn, - .chan_mode = conn->lchan->tch_mode, + .ch_mode_rate = conn->lchan->current_ch_mode_rate, .encr = conn->lchan->encr, .requires_voice_stream = conn->lchan->mgw_endpoint_ci_bts ? true : false, .msc_assigned_cic = conn->ho.inter_bsc_in.msc_assigned_cic, .re_use_mgw_endpoint_from_lchan = conn->lchan, .wait_before_switching_rtp = true, - .s15_s0 = conn->lchan->activate.info.s15_s0, }; + info.ch_mode_rate.chan_rate = chan_t_to_chan_rate(ho->new_lchan->type); /* For intra-cell handover, we know the accurate Timing Advance from the previous lchan. For inter-cell * handover, no Timing Advance for the new cell is known, so leave it unset. */ @@ -696,8 +696,7 @@ void handover_start_inter_bsc_in(struct gsm_subscriber_connection *conn, info = (struct lchan_activate_info){ .activ_for = ACTIVATE_FOR_HANDOVER, .for_conn = conn, - .chan_mode = ch_mode_rate.chan_mode, - .s15_s0 = ch_mode_rate.s15_s0, + .ch_mode_rate = ch_mode_rate, .requires_voice_stream = chan_mode_is_tch(ch_mode_rate.chan_mode), .msc_assigned_cic = req->msc_assigned_cic, }; @@ -849,7 +848,7 @@ static void send_handover_performed(struct gsm_subscriber_connection *conn) }; /* Chosen Channel 3.2.2.33 */ - ho_perf_params.chosen_channel = gsm0808_chosen_channel(lchan->type, lchan->tch_mode); + ho_perf_params.chosen_channel = gsm0808_chosen_channel(lchan->type, lchan->current_ch_mode_rate.chan_mode); if (!ho_perf_params.chosen_channel) { LOG_HO(conn, LOGL_ERROR, "Failed to generate Chosen Channel IE, can't send HANDOVER PERFORMED!\n"); return; @@ -862,14 +861,15 @@ static void send_handover_performed(struct gsm_subscriber_connection *conn) 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 = gsm0808_permitted_speech(lchan->type, + lchan->current_ch_mode_rate.chan_mode); ho_perf_params.speech_version_chosen_present = true; /* Speech Codec (chosen) 3.2.2.104 */ if (gscon_is_aoip(conn)) { /* Extrapolate speech codec from speech mode */ gsm0808_speech_codec_from_chan_type(&sc, ho_perf_params.speech_version_chosen); - sc.cfg = conn->lchan->ch_mode_rate.s15_s0; + sc.cfg = conn->lchan->current_ch_mode_rate.s15_s0; memcpy(&ho_perf_params.speech_codec_chosen, &sc, sizeof(sc)); ho_perf_params.speech_codec_chosen_present = true; } diff --git a/src/osmo-bsc/lchan_fsm.c b/src/osmo-bsc/lchan_fsm.c index 173534672..6144ccf35 100644 --- a/src/osmo-bsc/lchan_fsm.c +++ b/src/osmo-bsc/lchan_fsm.c @@ -569,6 +569,8 @@ static int lchan_mr_config(struct gsm_lchan *lchan, uint16_t s15_s0) /* Proceed with the generation of the multirate configuration IE * (MS and BTS) */ + /* FIXME: this actually modifies the lchan->mr_ms_lv and ->mr_bts_lv before an ACK for these AMR bits has been + * received. Until an ACK is received, all state should live in lchan->activate.* or lchan->modify.* ONLY. */ rc = gsm48_multirate_config(lchan->mr_ms_lv, &mr_conf_filtered, mr->ms_mode, mr->num_modes); if (rc != 0) { LOG_LCHAN(lchan, LOGL_ERROR, "can not encode multirate configuration (MS)\n"); @@ -580,7 +582,6 @@ static int lchan_mr_config(struct gsm_lchan *lchan, uint16_t s15_s0) return -EINVAL; } - lchan->s15_s0 = s15_s0; return 0; } @@ -645,30 +646,28 @@ static void lchan_fsm_wait_ts_ready_onenter(struct osmo_fsm_inst *fi, uint32_t p lchan->bs_power = bts->bs_power_ctrl.bs_power_val_db / 2; } - if (info->chan_mode == GSM48_CMODE_SPEECH_AMR) { - if (lchan_mr_config(lchan, info->s15_s0) < 0) { + if (info->ch_mode_rate.chan_mode == GSM48_CMODE_SPEECH_AMR) { + if (lchan_mr_config(lchan, info->ch_mode_rate.s15_s0) < 0) { lchan_fail("Can not generate multirate configuration IE\n"); return; } } - switch (info->chan_mode) { + switch (info->ch_mode_rate.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)); + gsm48_chan_mode_name(info->ch_mode_rate.chan_mode)); return; } @@ -682,7 +681,7 @@ static void lchan_fsm_wait_ts_ready_onenter(struct osmo_fsm_inst *fi, uint32_t p (use_mgwep_ci ? osmo_mgcpc_ep_ci_name(use_mgwep_ci) : "new") : "none", gsm_lchant_name(lchan->type), - gsm48_chan_mode_name(lchan->tch_mode), + gsm48_chan_mode_name(lchan->activate.info.ch_mode_rate.chan_mode), (lchan->activate.info.encr.alg_id ? : 1)-1, lchan->activate.info.encr.key_len ? osmo_hexdump_nospc(lchan->activate.info.encr.key, lchan->activate.info.encr.key_len) : "none"); @@ -822,6 +821,11 @@ static void lchan_fsm_post_activ_ack(struct osmo_fsm_inst *fi) { int rc; struct gsm_lchan *lchan = lchan_fi_lchan(fi); + + lchan->current_ch_mode_rate = lchan->activate.info.ch_mode_rate; + LOG_LCHAN(lchan, LOGL_INFO, "Rx Activ ACK %s\n", + gsm48_chan_mode_name(lchan->current_ch_mode_rate.chan_mode)); + if (lchan->release.requested) { lchan_fail_to(LCHAN_ST_WAIT_RF_RELEASE_ACK, "Release requested while activating"); return; @@ -948,7 +952,7 @@ static void lchan_fsm_wait_rll_rtp_establish(struct osmo_fsm_inst *fi, uint32_t static void lchan_fsm_wait_rr_chan_mode_modify_ack_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state) { struct gsm_lchan *lchan = lchan_fi_lchan(fi); - gsm48_lchan_modify(lchan, lchan->modify.info.chan_mode); + gsm48_lchan_modify(lchan, lchan->modify.info.ch_mode_rate.chan_mode); } static void lchan_fsm_wait_rr_chan_mode_modify_ack(struct osmo_fsm_inst *fi, uint32_t event, void *data) @@ -989,8 +993,7 @@ static void lchan_fsm_wait_rsl_chan_mode_modify_ack(struct osmo_fsm_inst *fi, ui case LCHAN_EV_RSL_CHAN_MODE_MODIFY_ACK: /* The Channel Mode Modify was ACKed, now the requested values become the accepted and used values. */ - lchan->tch_mode = lchan->modify.info.chan_mode; - lchan->s15_s0 = lchan->modify.info.s15_s0; + lchan->current_ch_mode_rate = lchan->modify.info.ch_mode_rate; if (lchan->modify.info.requires_voice_stream && !lchan->fi_rtp) { @@ -999,7 +1002,7 @@ static void lchan_fsm_wait_rsl_chan_mode_modify_ack(struct osmo_fsm_inst *fi, ui lchan->activate.info = (struct lchan_activate_info){ .activ_for = ACTIVATE_FOR_MODE_MODIFY_RTP, .for_conn = lchan->conn, - .s15_s0 = lchan->modify.info.s15_s0, + .ch_mode_rate = lchan->modify.info.ch_mode_rate, .requires_voice_stream = true, .msc_assigned_cic = lchan->modify.info.msc_assigned_cic, }; @@ -1142,8 +1145,8 @@ static void lchan_fsm_established(struct osmo_fsm_inst *fi, uint32_t event, void use_mgwep_ci = lchan_use_mgw_endpoint_ci_bts(lchan); - if (modif_info->chan_mode == GSM48_CMODE_SPEECH_AMR) { - if (lchan_mr_config(lchan, modif_info->s15_s0) < 0) { + if (modif_info->ch_mode_rate.chan_mode == GSM48_CMODE_SPEECH_AMR) { + if (lchan_mr_config(lchan, modif_info->ch_mode_rate.s15_s0) < 0) { lchan_fail("Can not generate multirate configuration IE\n"); return; } @@ -1157,7 +1160,7 @@ static void lchan_fsm_established(struct osmo_fsm_inst *fi, uint32_t event, void (use_mgwep_ci ? osmo_mgcpc_ep_ci_name(use_mgwep_ci) : "new") : "none", gsm_lchant_name(lchan->type), - gsm48_chan_mode_name(lchan->tch_mode)); + gsm48_chan_mode_name(lchan->modify.info.ch_mode_rate.chan_mode)); lchan_fsm_state_chg(LCHAN_ST_WAIT_RR_CHAN_MODE_MODIFY_ACK); return; diff --git a/src/osmo-bsc/lchan_rtp_fsm.c b/src/osmo-bsc/lchan_rtp_fsm.c index 8991acccd..366bd1b06 100644 --- a/src/osmo-bsc/lchan_rtp_fsm.c +++ b/src/osmo-bsc/lchan_rtp_fsm.c @@ -268,19 +268,19 @@ static void lchan_rtp_fsm_wait_ipacc_crcx_ack_onenter(struct osmo_fsm_inst *fi, return; } - val = ipacc_speech_mode(lchan->tch_mode, lchan->type); + val = ipacc_speech_mode(lchan->activate.info.ch_mode_rate.chan_mode, lchan->type); if (val < 0) { lchan_rtp_fail("Cannot determine Abis/IP speech mode for tch_mode=%s type=%s\n", - get_value_string(gsm48_chan_mode_names, lchan->tch_mode), + get_value_string(gsm48_chan_mode_names, lchan->activate.info.ch_mode_rate.chan_mode), gsm_lchant_name(lchan->type)); return; } lchan->abis_ip.speech_mode = val; - val = ipacc_payload_type(lchan->tch_mode, lchan->type); + val = ipacc_payload_type(lchan->activate.info.ch_mode_rate.chan_mode, lchan->type); if (val < 0) { lchan_rtp_fail("Cannot determine Abis/IP payload type for tch_mode=%s type=%s\n", - get_value_string(gsm48_chan_mode_names, lchan->tch_mode), + get_value_string(gsm48_chan_mode_names, lchan->activate.info.ch_mode_rate.chan_mode), gsm_lchant_name(lchan->type)); return; } @@ -834,14 +834,14 @@ static int chan_mode_to_mgcp_bss_pt(enum mgcp_codecs codec) void mgcp_pick_codec(struct mgcp_conn_peer *verb_info, const struct gsm_lchan *lchan, bool bss_side) { - enum mgcp_codecs codec = chan_mode_to_mgcp_codec(lchan->tch_mode, + enum mgcp_codecs codec = chan_mode_to_mgcp_codec(lchan->activate.info.ch_mode_rate.chan_mode, lchan->type == GSM_LCHAN_TCH_H? false : true); int custom_pt; if (codec < 0) { LOG_LCHAN(lchan, LOGL_ERROR, "Unable to determine MGCP codec type for %s in chan-mode %s\n", - gsm_lchant_name(lchan->type), gsm48_chan_mode_name(lchan->tch_mode)); + gsm_lchant_name(lchan->type), gsm48_chan_mode_name(lchan->activate.info.ch_mode_rate.chan_mode)); verb_info->codecs_len = 0; return; } diff --git a/src/osmo-bsc/osmo_bsc_bssap.c b/src/osmo-bsc/osmo_bsc_bssap.c index fff5fbb59..239c2ca88 100644 --- a/src/osmo-bsc/osmo_bsc_bssap.c +++ b/src/osmo-bsc/osmo_bsc_bssap.c @@ -679,12 +679,12 @@ static int select_codecs(struct assignment_request *req, struct gsm0808_channel_ switch (ct->ch_rate_type) { case GSM0808_SPEECH_FULL_BM: - rc = match_codec_pref(&req->ch_mode_rate[nc], ct, &conn->codec_list, msc, bts, + rc = match_codec_pref(&req->ch_mode_rate_list[nc], ct, &conn->codec_list, msc, bts, RATE_PREF_FR); nc += (rc == 0) ? 1 : 0; break; case GSM0808_SPEECH_HALF_LM: - rc = match_codec_pref(&req->ch_mode_rate[nc], ct, &conn->codec_list, msc, bts, + rc = match_codec_pref(&req->ch_mode_rate_list[nc], ct, &conn->codec_list, msc, bts, RATE_PREF_HR); nc += (rc == 0) ? 1 : 0; break; @@ -692,19 +692,19 @@ static int select_codecs(struct assignment_request *req, struct gsm0808_channel_ case GSM0808_SPEECH_PERM_NO_CHANGE: case GSM0808_SPEECH_FULL_PREF_NO_CHANGE: case GSM0808_SPEECH_FULL_PREF: - rc = match_codec_pref(&req->ch_mode_rate[nc], ct, &conn->codec_list, msc, bts, + rc = match_codec_pref(&req->ch_mode_rate_list[nc], ct, &conn->codec_list, msc, bts, RATE_PREF_FR); nc += (rc == 0) ? 1 : 0; - rc = match_codec_pref(&req->ch_mode_rate[nc], ct, &conn->codec_list, msc, bts, + rc = match_codec_pref(&req->ch_mode_rate_list[nc], ct, &conn->codec_list, msc, bts, RATE_PREF_HR); nc += (rc == 0) ? 1 : 0; break; case GSM0808_SPEECH_HALF_PREF_NO_CHANGE: case GSM0808_SPEECH_HALF_PREF: - rc = match_codec_pref(&req->ch_mode_rate[nc], ct, &conn->codec_list, msc, bts, + rc = match_codec_pref(&req->ch_mode_rate_list[nc], ct, &conn->codec_list, msc, bts, RATE_PREF_HR); nc += (rc == 0) ? 1 : 0; - rc = match_codec_pref(&req->ch_mode_rate[nc], ct, &conn->codec_list, msc, bts, + rc = match_codec_pref(&req->ch_mode_rate_list[nc], ct, &conn->codec_list, msc, bts, RATE_PREF_FR); nc += (rc == 0) ? 1 : 0; break; @@ -726,8 +726,8 @@ static int select_codecs(struct assignment_request *req, struct gsm0808_channel_ DEBUGP(DMSC, "Found matching audio type (pref=%d): %s %s for channel_type =" " { ch_indctr=0x%x, ch_rate_type=0x%x, perm_spch=[ %s] }\n", i, - req->ch_mode_rate[i].chan_rate == CH_RATE_FULL ? "full rate" : "half rate", - get_value_string(gsm48_chan_mode_names, req->ch_mode_rate[i].chan_mode), + req->ch_mode_rate_list[i].chan_rate == CH_RATE_FULL ? "full rate" : "half rate", + get_value_string(gsm48_chan_mode_names, req->ch_mode_rate_list[i].chan_mode), ct->ch_indctr, ct->ch_rate_type, osmo_hexdump(ct->perm_spch, ct->perm_spch_len)); } @@ -742,43 +742,43 @@ static int select_sign_chan(struct assignment_request *req, struct gsm0808_chann switch (ct->ch_rate_type) { case GSM0808_SIGN_ANY: - req->ch_mode_rate[nc++].chan_rate = CH_RATE_SDCCH; - req->ch_mode_rate[nc++].chan_rate = CH_RATE_HALF; - req->ch_mode_rate[nc++].chan_rate = CH_RATE_FULL; + req->ch_mode_rate_list[nc++].chan_rate = CH_RATE_SDCCH; + req->ch_mode_rate_list[nc++].chan_rate = CH_RATE_HALF; + req->ch_mode_rate_list[nc++].chan_rate = CH_RATE_FULL; break; case GSM0808_SIGN_SDCCH: - req->ch_mode_rate[nc++].chan_rate = CH_RATE_SDCCH; + req->ch_mode_rate_list[nc++].chan_rate = CH_RATE_SDCCH; break; case GSM0808_SIGN_SDCCH_FULL_BM: - req->ch_mode_rate[nc++].chan_rate = CH_RATE_SDCCH; - req->ch_mode_rate[nc++].chan_rate = CH_RATE_FULL; + req->ch_mode_rate_list[nc++].chan_rate = CH_RATE_SDCCH; + req->ch_mode_rate_list[nc++].chan_rate = CH_RATE_FULL; break; case GSM0808_SIGN_SDCCH_HALF_LM: - req->ch_mode_rate[nc++].chan_rate = CH_RATE_SDCCH; - req->ch_mode_rate[nc++].chan_rate = CH_RATE_HALF; + req->ch_mode_rate_list[nc++].chan_rate = CH_RATE_SDCCH; + req->ch_mode_rate_list[nc++].chan_rate = CH_RATE_HALF; break; case GSM0808_SIGN_FULL_BM: - req->ch_mode_rate[nc++].chan_rate = CH_RATE_FULL; + req->ch_mode_rate_list[nc++].chan_rate = CH_RATE_FULL; break; case GSM0808_SIGN_HALF_LM: - req->ch_mode_rate[nc++].chan_rate = CH_RATE_HALF; + req->ch_mode_rate_list[nc++].chan_rate = CH_RATE_HALF; break; case GSM0808_SIGN_FULL_PREF: case GSM0808_SIGN_FULL_PREF_NO_CHANGE: - req->ch_mode_rate[nc++].chan_rate = CH_RATE_FULL; - req->ch_mode_rate[nc++].chan_rate = CH_RATE_HALF; + req->ch_mode_rate_list[nc++].chan_rate = CH_RATE_FULL; + req->ch_mode_rate_list[nc++].chan_rate = CH_RATE_HALF; break; case GSM0808_SIGN_HALF_PREF: case GSM0808_SIGN_HALF_PREF_NO_CHANGE: - req->ch_mode_rate[nc++].chan_rate = CH_RATE_HALF; - req->ch_mode_rate[nc++].chan_rate = CH_RATE_FULL; + req->ch_mode_rate_list[nc++].chan_rate = CH_RATE_HALF; + req->ch_mode_rate_list[nc++].chan_rate = CH_RATE_FULL; break; default: break; } for (i = 0; i < nc; i++) - req->ch_mode_rate[i].chan_mode = GSM48_CMODE_SIGN; + req->ch_mode_rate_list[i].chan_mode = GSM48_CMODE_SIGN; req->n_ch_mode_rate = nc; @@ -1379,7 +1379,7 @@ int bsc_tx_bssmap_ho_required(struct gsm_lchan *lchan, const struct gsm0808_cell case GSM_LCHAN_TCH_H: params.speech_version_used_present = true; params.speech_version_used = gsm0808_permitted_speech(lchan->type, - lchan->tch_mode); + lchan->current_ch_mode_rate.chan_mode); if (!params.speech_version_used) { LOG_HO(lchan->conn, LOGL_ERROR, "Cannot encode Speech Version (Used)" " for BSSMAP Handover Required message\n"); @@ -1417,9 +1417,10 @@ int bsc_tx_bssmap_ho_request_ack(struct gsm_subscriber_connection *conn, struct .l3_info = rr_ho_command->data, .l3_info_len = rr_ho_command->len, .chosen_channel_present = true, - .chosen_channel = gsm0808_chosen_channel(new_lchan->type, new_lchan->tch_mode), + .chosen_channel = gsm0808_chosen_channel(new_lchan->type, new_lchan->current_ch_mode_rate.chan_mode), .chosen_encr_alg = new_lchan->encr.alg_id, - .chosen_speech_version = gsm0808_permitted_speech(new_lchan->type, new_lchan->tch_mode), + .chosen_speech_version = gsm0808_permitted_speech(new_lchan->type, + new_lchan->current_ch_mode_rate.chan_mode), }; if (gscon_is_aoip(conn)) { @@ -1475,7 +1476,7 @@ enum handover_result bsc_tx_bssmap_ho_complete(struct gsm_subscriber_connection .chosen_encr_alg = lchan->encr.alg_id, .chosen_channel_present = true, - .chosen_channel = gsm0808_chosen_channel(lchan->type, lchan->tch_mode), + .chosen_channel = gsm0808_chosen_channel(lchan->type, lchan->current_ch_mode_rate.chan_mode), .lcls_bss_status_present = (lcls_status != 0xff), .lcls_bss_status = lcls_status, @@ -1483,7 +1484,7 @@ enum handover_result bsc_tx_bssmap_ho_complete(struct gsm_subscriber_connection /* speech_codec_chosen */ if (ho->new_lchan->activate.info.requires_voice_stream && gscon_is_aoip(conn)) { - int perm_spch = gsm0808_permitted_speech(lchan->type, lchan->tch_mode); + int perm_spch = gsm0808_permitted_speech(lchan->type, lchan->current_ch_mode_rate.chan_mode); params.speech_codec_chosen_present = true; rc = gsm0808_speech_codec_from_chan_type(¶ms.speech_codec_chosen, perm_spch); if (rc) { diff --git a/src/osmo-bsc/osmo_bsc_lcls.c b/src/osmo-bsc/osmo_bsc_lcls.c index 4ab04419d..2c90d011d 100644 --- a/src/osmo-bsc/osmo_bsc_lcls.c +++ b/src/osmo-bsc/osmo_bsc_lcls.c @@ -345,15 +345,14 @@ static bool lcls_enable_possible(const struct gsm_subscriber_connection *conn) return false; } - if (conn->lchan->tch_mode != conn->lcls.other->lchan->tch_mode + if (conn->lchan->current_ch_mode_rate.chan_mode != conn->lcls.other->lchan->current_ch_mode_rate.chan_mode && conn->sccp.msc->lcls_codec_mismatch_allow == false) { LOGPFSM(conn->lcls.fi, "Not enabling LS due to TCH-mode mismatch: %s:%s != %s:%s\n", gsm_lchan_name(conn->lchan), - gsm48_chan_mode_name(conn->lchan->tch_mode), + gsm48_chan_mode_name(conn->lchan->current_ch_mode_rate.chan_mode), gsm_lchan_name(conn->lcls.other->lchan), - gsm48_chan_mode_name(conn->lcls.other->lchan-> - tch_mode)); + gsm48_chan_mode_name(conn->lcls.other->lchan->current_ch_mode_rate.chan_mode)); return false; } diff --git a/tests/handover/handover_test.c b/tests/handover/handover_test.c index 2b8e8775b..c16b26dcc 100644 --- a/tests/handover/handover_test.c +++ b/tests/handover/handover_test.c @@ -397,14 +397,14 @@ struct gsm_lchan *lchan_act(struct gsm_lchan *lchan, int full_rate, const char * create_conn(lchan); if (!strcasecmp(codec, "FR") && full_rate) - lchan->tch_mode = GSM48_CMODE_SPEECH_V1; + lchan->current_ch_mode_rate.chan_mode = GSM48_CMODE_SPEECH_V1; else if (!strcasecmp(codec, "HR") && !full_rate) - lchan->tch_mode = GSM48_CMODE_SPEECH_V1; + lchan->current_ch_mode_rate.chan_mode = GSM48_CMODE_SPEECH_V1; else if (!strcasecmp(codec, "EFR") && full_rate) - lchan->tch_mode = GSM48_CMODE_SPEECH_EFR; + lchan->current_ch_mode_rate.chan_mode = GSM48_CMODE_SPEECH_EFR; else if (!strcasecmp(codec, "AMR")) { - lchan->tch_mode = GSM48_CMODE_SPEECH_AMR; - lchan->activate.info.s15_s0 = 0x0002; + lchan->current_ch_mode_rate.chan_mode = GSM48_CMODE_SPEECH_AMR; + lchan->current_ch_mode_rate.s15_s0 = 0x0002; } else { fprintf(stderr, "Given codec unknown\n"); exit(EXIT_FAILURE); -- cgit v1.2.3