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