assignment_fsm: chan mode check: support CSD

Replace check_requires_voice_stream, which used to iterate over
ch_mode_rate_list and verify that all entries are either for speech or
signalling. Instead verify in check_chan_mode_rate_against_ch_indctr,
that all entries of ch_mode_rate_list have a chan_mode that matches the
ch_indctr (data, speech, signalling; called "speech / data indicator" in
3GPP TS 48.008 § 3.2.2.11).

This ensures that all of them are either data, speech or signalling and
not mixed.

Related: OS#4393
Change-Id: Iee5cbfee84d7f2ad59ee2d5a19891a2b59bbafff
This commit is contained in:
Oliver Smith 2023-02-21 17:17:33 +01:00
parent 0361b01614
commit 2150b307c2
3 changed files with 29 additions and 32 deletions

View File

@ -163,6 +163,9 @@ struct assignment_request {
/* The TSC to use if 'use' is true, otherwise automatically determine the TSC value to use. Valid range is 0 to
* 7, as described in 3GPP TS 45.002. */
struct optional_val tsc;
/* The "speech / data indicator" from 3GPP TS 48.008 § 3.2.2.11 Channel Type (speech/data/signalling). */
enum gsm0808_chan_indicator ch_indctr;
};
/* State of an ongoing Assignment, while the assignment_fsm is still busy. This serves as state separation to keep the

View File

@ -370,62 +370,53 @@ static __attribute__((constructor)) void assignment_fsm_init(void)
OSMO_ASSERT(osmo_fsm_register(&assignment_fsm) == 0);
}
static int check_requires_voice(bool *requires_voice, enum gsm48_chan_mode chan_mode)
static int chan_mode_to_ch_indctr(enum gsm48_chan_mode chan_mode)
{
*requires_voice = false;
switch (gsm48_chan_mode_to_non_vamos(chan_mode)) {
case GSM48_CMODE_DATA_14k5:
case GSM48_CMODE_DATA_12k0:
case GSM48_CMODE_DATA_6k0:
case GSM48_CMODE_DATA_3k6:
return GSM0808_CHAN_DATA;
case GSM48_CMODE_SPEECH_V1:
case GSM48_CMODE_SPEECH_EFR:
case GSM48_CMODE_SPEECH_AMR:
*requires_voice = true;
break;
return GSM0808_CHAN_SPEECH;
case GSM48_CMODE_SIGN:
*requires_voice = false;
break;
return GSM0808_CHAN_SIGN;
default:
return -EINVAL;
}
return 0;
}
/* Check if the incoming assignment request requires a voice stream or not,
* we will look at the preferred and the alternate channel mode and also make
* sure that both are consistent. */
static int check_requires_voice_stream(struct gsm_subscriber_connection *conn)
/* Check if the incoming assignment request has a channel mode that is
* inconsistent with ch_indctr, e.g. GSM48_CMODE_DATA_14k5 and
* GSM0808_CHAN_SPEECH */
static int check_chan_mode_rate_against_ch_indctr(struct gsm_subscriber_connection *conn)
{
bool requires_voice_pref = false, requires_voice_alt;
struct assignment_request *req = &conn->assignment.req;
struct osmo_fsm_inst *fi = conn->fi;
int i, rc;
/* When the assignment request indicates that there is an alternate
* rate available (e.g. "Full or Half rate channel, Half rate
* preferred..."), then both must be either voice or either signalling,
* a mismatch is not permitted */
int i;
uint8_t ch_indctr;
for (i = 0; i < req->n_ch_mode_rate; i++) {
rc = check_requires_voice(&requires_voice_alt, req->ch_mode_rate_list[i].chan_mode);
if (rc < 0) {
ch_indctr = chan_mode_to_ch_indctr(req->ch_mode_rate_list[i].chan_mode);
if (ch_indctr < 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_list[i].chan_mode));
return -EINVAL;
}
if (i==0)
requires_voice_pref = requires_voice_alt;
else if (requires_voice_alt != requires_voice_pref) {
if (ch_indctr != req->ch_indctr) {
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_list[0].chan_mode),
gsm48_chan_mode_name(req->ch_mode_rate_list[i].chan_mode));
"Channel mode %s has ch_indctr %d, channel type has ch_indctr %d",
gsm48_chan_mode_name(req->ch_mode_rate_list[i].chan_mode),
ch_indctr, req->ch_indctr);
return -EINVAL;
}
}
conn->assignment.requires_voice_stream = requires_voice_pref;
return 0;
}
@ -471,6 +462,8 @@ static int _reassignment_request(enum assign_for assign_for, struct gsm_lchan *l
.present = (tsc >= 0),
.val = tsc,
},
.ch_indctr = chan_mode_to_ch_indctr(lchan->current_ch_mode_rate.chan_mode),
};
if (to_lchan)
@ -529,10 +522,9 @@ void assignment_fsm_start(struct gsm_subscriber_connection *conn, struct gsm_bts
assignment_count(CTR_ASSIGNMENT_ATTEMPTED);
/* Check if we need a voice stream. If yes, set the appropriate struct
* members in conn */
if (check_requires_voice_stream(conn) < 0)
if (check_chan_mode_rate_against_ch_indctr(conn) < 0)
return;
conn->assignment.requires_voice_stream = (req->ch_indctr != GSM0808_CHAN_SIGN);
if (!req->target_lchan && reuse_existing_lchan(conn)) {
/* The already existing lchan is suitable for this mode */

View File

@ -1136,6 +1136,8 @@ static int bssmap_handle_assignm_req(struct gsm_subscriber_connection *conn,
goto reject;
}
req.ch_indctr = ct.ch_indctr;
return osmo_fsm_inst_dispatch(conn->fi, GSCON_EV_ASSIGNMENT_START, &req);
reject: