aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/osmo-bsc/assignment_fsm.c201
-rw-r--r--src/osmo-bsc/bsc_vty.c1
-rw-r--r--src/osmo-bsc/codec_pref.c42
-rw-r--r--src/osmo-bsc/handover_fsm.c18
-rw-r--r--src/osmo-bsc/osmo_bsc_bssap.c133
5 files changed, 292 insertions, 103 deletions
diff --git a/src/osmo-bsc/assignment_fsm.c b/src/osmo-bsc/assignment_fsm.c
index 2ad39596c..67937d634 100644
--- a/src/osmo-bsc/assignment_fsm.c
+++ b/src/osmo-bsc/assignment_fsm.c
@@ -170,7 +170,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->assignment.req.s15_s0;
+ sc.cfg = conn->lchan->ch_mode_rate.s15_s0;
sc_ptr = ≻
}
}
@@ -248,9 +248,11 @@ static void assignment_fsm_update_id(struct gsm_subscriber_connection *conn)
new_lchan->nr);
}
-static bool lchan_type_compat_with_mode(enum gsm_chan_t type,
- enum gsm48_chan_mode chan_mode, int full_rate)
+static bool lchan_type_compat_with_mode(enum gsm_chan_t type, const struct channel_mode_and_rate *ch_mode_rate)
{
+ enum gsm48_chan_mode chan_mode = ch_mode_rate->chan_mode;
+ bool full_rate = ch_mode_rate->full_rate;
+
switch (chan_mode) {
case GSM48_CMODE_SIGN:
switch (type) {
@@ -293,6 +295,107 @@ void assignment_fsm_init()
OSMO_ASSERT(osmo_fsm_register(&assignment_fsm) == 0);
}
+static int check_requires_voice(bool *requires_voice, enum gsm48_chan_mode chan_mode)
+{
+ *requires_voice = false;
+
+ switch (chan_mode) {
+ case GSM48_CMODE_SPEECH_V1:
+ case GSM48_CMODE_SPEECH_EFR:
+ case GSM48_CMODE_SPEECH_AMR:
+ *requires_voice = true;
+ break;
+ case GSM48_CMODE_SIGN:
+ *requires_voice = false;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* Check if the incoming assignment requests 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)
+{
+ bool result_requires_voice_alt;
+ bool result_requires_voice_pref;
+ struct assignment_request *req = &conn->assignment.req;
+ struct osmo_fsm_inst *fi = conn->fi;
+ int 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 */
+
+ /* Check the prefered setting */
+ rc = check_requires_voice(&result_requires_voice_pref, req->ch_mode_rate_pref.chan_mode);
+ if (rc < 0) {
+ assignment_fail(GSM0808_CAUSE_REQ_CODEC_TYPE_OR_CONFIG_NOT_SUPP,
+ "Prefered channel mode not supported: %s",
+ gsm48_chan_mode_name(req->ch_mode_rate_pref.chan_mode));
+ return -EINVAL;
+ }
+ conn->assignment.requires_voice_stream = result_requires_voice_pref;
+
+ /* If there is an alternate setting, check that one as well */
+ if (!req->ch_mode_rate_alt_present)
+ return 0;
+ rc = check_requires_voice(&result_requires_voice_alt, req->ch_mode_rate_alt.chan_mode);
+ if (rc < 0) {
+ assignment_fail(GSM0808_CAUSE_REQ_CODEC_TYPE_OR_CONFIG_NOT_SUPP,
+ "Alternate channel mode not supported: %s",
+ gsm48_chan_mode_name(req->ch_mode_rate_alt.chan_mode));
+ return -EINVAL;
+ }
+
+ /* Make sure both settings match */
+ if (result_requires_voice_pref != result_requires_voice_alt) {
+ assignment_fail(GSM0808_CAUSE_REQ_CODEC_TYPE_OR_CONFIG_NOT_SUPP,
+ "Inconsistent channel modes: %s != %s",
+ gsm48_chan_mode_name(req->ch_mode_rate_pref.chan_mode),
+ gsm48_chan_mode_name(req->ch_mode_rate_alt.chan_mode));
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* Check if the conn is already associated with an lchan. If yes, we will check
+ * if that lchan is compatible with the preferred rate/codec. If the lchan
+ * turns out to be incompatible we try with the alternate rate/codec. */
+static bool reuse_existing_lchan(struct gsm_subscriber_connection *conn)
+{
+ struct assignment_request *req = &conn->assignment.req;
+
+ if (!conn->lchan)
+ return false;
+
+ /* Check if the currently existing lchan is compatible with the
+ * preferred rate/codec. */
+ if (lchan_type_compat_with_mode(conn->lchan->type, &req->ch_mode_rate_pref))
+ conn->lchan->ch_mode_rate = req->ch_mode_rate_pref;
+ else if (req->ch_mode_rate_alt_present
+ && lchan_type_compat_with_mode(conn->lchan->type, &req->ch_mode_rate_alt))
+ conn->lchan->ch_mode_rate = req->ch_mode_rate_alt;
+ else
+ return false;
+
+ if (conn->lchan->tch_mode != conn->lchan->ch_mode_rate.chan_mode) {
+ /* FIXME: send Channel Mode Modify to put the current lchan in the right mode, and kick
+ * off its RTP stream setup code path. See gsm48_lchan_modify() and
+ * gsm48_rx_rr_modif_ack(), and see lchan_fsm.h LCHAN_EV_CHAN_MODE_MODIF_* */
+ LOG_ASSIGNMENT(conn, LOGL_DEBUG,
+ "Current lchan would be compatible, but Channel Mode Modify is not implemented\n");
+ return false;
+ }
+
+ return true;
+}
+
void assignment_fsm_start(struct gsm_subscriber_connection *conn, struct gsm_bts *bts,
struct assignment_request *req)
{
@@ -311,75 +414,77 @@ void assignment_fsm_start(struct gsm_subscriber_connection *conn, struct gsm_bts
conn->assignment.fi = fi;
fi->priv = conn;
+ /* Create a copy of the request data and use that copy from now on. */
conn->assignment.req = *req;
+ req = &conn->assignment.req;
- switch (req->chan_mode) {
-
- case GSM48_CMODE_SPEECH_V1:
- case GSM48_CMODE_SPEECH_EFR:
- case GSM48_CMODE_SPEECH_AMR:
- conn->assignment.requires_voice_stream = true;
- /* Select an lchan below. */
- break;
-
- case GSM48_CMODE_SIGN:
- conn->assignment.requires_voice_stream = false;
- /* Select an lchan below. */
- break;
-
- default:
- assignment_fail(GSM0808_CAUSE_REQ_CODEC_TYPE_OR_CONFIG_NOT_SUPP,
- "Channel mode not supported: %s",
- gsm48_chan_mode_name(req->chan_mode));
+ /* Check if we need a voice stream. If yes, set the approriate struct
+ * members in conn */
+ if (check_requires_voice_stream(conn) < 0)
return;
- }
- if (conn->lchan
- && lchan_type_compat_with_mode(conn->lchan->type, req->chan_mode, req->full_rate)) {
-
- if (conn->lchan->tch_mode == req->chan_mode) {
- /* current lchan suffices and already is in the right mode. We're done. */
- LOG_ASSIGNMENT(conn, LOGL_DEBUG,
- "Current lchan is compatible with requested chan_mode,"
- " sending BSSMAP Assignment Complete directly."
- " requested chan_mode=%s; current lchan is %s\n",
- gsm48_chan_mode_name(req->chan_mode),
- gsm_lchan_name(conn->lchan));
- send_assignment_complete(conn);
- return;
+ /* There may be an already existing lchan, if yes, try to work with
+ * the existing lchan */
+ if (reuse_existing_lchan(conn)) {
+ LOG_ASSIGNMENT(conn, LOGL_DEBUG,
+ "Current lchan 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),
+ gsm_lchan_name(conn->lchan));
+
+ send_assignment_complete(conn);
+ /* If something went wrong during send_assignment_complete(), the fi will be gone from
+ * error handling in there. */
+ if (conn->assignment.fi) {
+ assignment_count_result(BSC_CTR_ASSIGNMENT_COMPLETED);
+ osmo_fsm_inst_term(conn->assignment.fi, OSMO_FSM_TERM_REGULAR, 0);
}
-
- /* FIXME: send Channel Mode Modify to put the current lchan in the right mode, and kick
- * off its RTP stream setup code path. See gsm48_lchan_modify() and
- * gsm48_rx_rr_modif_ack(), and see lchan_fsm.h LCHAN_EV_CHAN_MODE_MODIF_* */
- LOG_ASSIGNMENT(conn, LOGL_ERROR,
- "NOT IMPLEMENTED:"
- " Current lchan would be compatible, we should send Channel Mode Modify\n");
+ return;
}
- conn->assignment.new_lchan = lchan_select_by_chan_mode(bts, req->chan_mode, req->full_rate);
+ /* Try to allocate a new lchan with the preferred codec/rate choice */
+ conn->assignment.new_lchan =
+ lchan_select_by_chan_mode(bts, req->ch_mode_rate_pref.chan_mode, req->ch_mode_rate_pref.full_rate);
+ conn->lchan->ch_mode_rate = req->ch_mode_rate_pref;
+
+ /* In case the lchan allocation fails, we try with the alternat codec/
+ * rate choice (if possible) */
+ if (!conn->assignment.new_lchan && req->ch_mode_rate_alt_present) {
+ conn->assignment.new_lchan =
+ lchan_select_by_chan_mode(bts, req->ch_mode_rate_alt.chan_mode, req->ch_mode_rate_alt.full_rate);
+ conn->lchan->ch_mode_rate = req->ch_mode_rate_alt;
+ }
+ /* 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(BSC_CTR_ASSIGNMENT_NO_CHANNEL);
assignment_fail(GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE,
"BSSMAP Assignment Command:"
- " No lchan available for: chan_mode=%s, full_rate=%i\n",
- get_value_string(gsm48_chan_mode_names, req->chan_mode), req->full_rate);
+ " No lchan available for: preferred=%s%s / alternate=%s%s\n",
+ gsm48_chan_mode_name(req->ch_mode_rate_pref.chan_mode),
+ req->ch_mode_rate_pref.full_rate ? ",FR" : ",HR",
+ req->ch_mode_rate_alt_present ?
+ gsm48_chan_mode_name(req->ch_mode_rate_alt.chan_mode) : "none",
+ req->ch_mode_rate_alt_present ?
+ (req->ch_mode_rate_alt.full_rate ? ",FR" : ",HR") : "");
return;
}
assignment_fsm_update_id(conn);
LOG_ASSIGNMENT(conn, LOGL_INFO, "Starting Assignment: chan_mode=%s, full_rate=%d,"
" aoip=%s MSC-rtp=%s:%u\n",
- gsm48_chan_mode_name(req->chan_mode), req->full_rate,
+ gsm48_chan_mode_name(conn->lchan->ch_mode_rate.chan_mode),
+ conn->lchan->ch_mode_rate.full_rate,
req->aoip ? "yes" : "no", req->msc_rtp_addr, req->msc_rtp_port);
assignment_fsm_state_chg(ASSIGNMENT_ST_WAIT_LCHAN_ACTIVE);
info = (struct lchan_activate_info){
.activ_for = FOR_ASSIGNMENT,
.for_conn = conn,
- .chan_mode = req->chan_mode,
- .s15_s0 = req->s15_s0,
+ .chan_mode = conn->lchan->ch_mode_rate.chan_mode,
+ .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 357ee9eae..9413d36f8 100644
--- a/src/osmo-bsc/bsc_vty.c
+++ b/src/osmo-bsc/bsc_vty.c
@@ -4802,6 +4802,7 @@ DEFUN_HIDDEN(lchan_set_borken, lchan_set_borken_cmd,
ts = vty_get_ts(vty, argv[0], argv[1], argv[2]);
if (!ts)
return CMD_WARNING;
+
lchan = &ts->lchan[ss_nr];
if (!lchan->fi)
return CMD_WARNING;
diff --git a/src/osmo-bsc/codec_pref.c b/src/osmo-bsc/codec_pref.c
index c99c38335..a94d6a834 100644
--- a/src/osmo-bsc/codec_pref.c
+++ b/src/osmo-bsc/codec_pref.c
@@ -266,21 +266,18 @@ static uint16_t gen_bss_supported_amr_s15_s0(const struct bsc_msc_data *msc, con
/*! Match the codec preferences from local config with a received codec preferences IEs received from the
* MSC and the BTS' codec configuration.
- * \param[out] chan_mode GSM 04.08 channel mode.
- * \param[out] full_rate true if full-rate.
- * \param[out] s15_s0 codec configuration bits S15-S0 (AMR)
+ * \param[out] ch_mode_rate resulting codec and rate information
* \param[in] ct GSM 08.08 channel type received from MSC.
* \param[in] scl GSM 08.08 speech codec list received from MSC (optional).
* \param[in] msc associated msc (current codec settings).
* \param[in] bts associated bts (current codec settings).
+ * \param[in] pref selected rate preference (full, half or none).
* \returns 0 on success, -1 in case no match was found */
-int match_codec_pref(enum gsm48_chan_mode *chan_mode,
- bool *full_rate,
- uint16_t *s15_s0,
+int match_codec_pref(struct channel_mode_and_rate *ch_mode_rate,
const struct gsm0808_channel_type *ct,
const struct gsm0808_speech_codec_list *scl,
const struct bsc_msc_data *msc,
- const struct gsm_bts *bts)
+ const struct gsm_bts *bts, enum rate_pref rate_pref)
{
unsigned int i;
uint8_t perm_spch;
@@ -297,6 +294,18 @@ int match_codec_pref(enum gsm48_chan_mode *chan_mode,
/* Pick a permitted speech value from the global codec configuration list */
perm_spch = audio_support_to_gsm88(msc->audio_support[i]);
+ /* Determine if the result is a half or full rate codec */
+ rc = full_rate_from_perm_spch(&ch_mode_rate->full_rate, perm_spch);
+ if (rc < 0)
+ return -EINVAL;
+
+ /* If we have a preference for FR or HR in our request, we
+ * discard the potential match */
+ if (rate_pref == RATE_PREF_HR && ch_mode_rate->full_rate)
+ continue;
+ if (rate_pref == RATE_PREF_FR && !ch_mode_rate->full_rate)
+ continue;
+
/* Check this permitted speech value against the BTS specific parameters.
* if the BTS does not support the codec, try the next one */
if (!test_codec_support_bts(bts, perm_spch))
@@ -312,19 +321,14 @@ int match_codec_pref(enum gsm48_chan_mode *chan_mode,
/* Exit without result, in case no match can be deteched */
if (!match) {
- *full_rate = false;
- *chan_mode = GSM48_CMODE_SIGN;
- *s15_s0 = 0;
+ ch_mode_rate->full_rate = false;
+ ch_mode_rate->chan_mode = GSM48_CMODE_SIGN;
+ ch_mode_rate->s15_s0 = 0;
return -1;
}
- /* Determine if the result is a half or full rate codec */
- rc = full_rate_from_perm_spch(full_rate, perm_spch);
- if (rc < 0)
- return -EINVAL;
-
/* Lookup a channel mode for the selected codec */
- *chan_mode = gsm88_to_chan_mode(perm_spch);
+ ch_mode_rate->chan_mode = gsm88_to_chan_mode(perm_spch);
/* Special handling for AMR */
if (perm_spch == GSM0808_PERM_HR3 || perm_spch == GSM0808_PERM_FR3) {
@@ -337,9 +341,9 @@ int match_codec_pref(enum gsm48_chan_mode *chan_mode,
* result */
amr_s15_s0_supported = gen_bss_supported_amr_s15_s0(msc, bts, (perm_spch == GSM0808_PERM_HR3));
if (sc_match)
- *s15_s0 = sc_match->cfg & amr_s15_s0_supported;
+ ch_mode_rate->s15_s0 = sc_match->cfg & amr_s15_s0_supported;
else
- *s15_s0 = amr_s15_s0_supported;
+ ch_mode_rate->s15_s0 = amr_s15_s0_supported;
/* NOTE: The function test_codec_pref() will populate the
* sc_match pointer from the searched speech codec list. For
@@ -349,7 +353,7 @@ int match_codec_pref(enum gsm48_chan_mode *chan_mode,
* However s15_s0 is always populated with a meaningful value,
* regardless if AoIP is in use or not. */
} else
- *s15_s0 = 0;
+ ch_mode_rate->s15_s0 = 0;
return 0;
}
diff --git a/src/osmo-bsc/handover_fsm.c b/src/osmo-bsc/handover_fsm.c
index 578cff351..30297f620 100644
--- a/src/osmo-bsc/handover_fsm.c
+++ b/src/osmo-bsc/handover_fsm.c
@@ -521,10 +521,8 @@ void handover_start_inter_bsc_in(struct gsm_subscriber_connection *conn,
struct bsc_msc_data *msc = conn->sccp.msc;
struct handover_in_req *req = &ho->inter_bsc_in;
int match_idx;
- enum gsm48_chan_mode mode;
- bool full_rate = false;
- uint16_t s15_s0;
struct osmo_fsm_inst *fi;
+ struct channel_mode_and_rate ch_mode_rate = {};
handover_fsm_alloc(conn);
@@ -562,7 +560,7 @@ void handover_start_inter_bsc_in(struct gsm_subscriber_connection *conn,
bts->nr, req->cell_id_target_name);
/* Figure out channel type */
- if (match_codec_pref(&mode, &full_rate, &s15_s0, &req->ct, &req->scl, msc, bts)) {
+ if (match_codec_pref(&ch_mode_rate, &req->ct, &req->scl, msc, bts, RATE_PREF_NONE)) {
LOG_HO(conn, LOGL_DEBUG,
"BTS %u has no matching channel codec (%s, speech codec list len = %u)\n",
bts->nr, gsm0808_channel_type_name(&req->ct), req->scl.len);
@@ -570,10 +568,10 @@ void handover_start_inter_bsc_in(struct gsm_subscriber_connection *conn,
}
LOG_HO(conn, LOGL_DEBUG, "BTS %u: Found matching audio type: %s %s (for %s)\n",
- bts->nr, gsm48_chan_mode_name(mode), full_rate? "full-rate" : "half-rate",
+ bts->nr, gsm48_chan_mode_name(ch_mode_rate.chan_mode), ch_mode_rate.full_rate? "full-rate" : "half-rate",
gsm0808_channel_type_name(&req->ct));
- lchan = lchan_select_by_chan_mode(bts, mode, full_rate);
+ lchan = lchan_select_by_chan_mode(bts, ch_mode_rate.chan_mode, ch_mode_rate.full_rate);
if (!lchan) {
LOG_HO(conn, LOGL_DEBUG, "BTS %u has no matching free channels\n", bts->nr);
continue;
@@ -605,9 +603,9 @@ void handover_start_inter_bsc_in(struct gsm_subscriber_connection *conn,
info = (struct lchan_activate_info){
.activ_for = FOR_HANDOVER,
.for_conn = conn,
- .chan_mode = mode,
- .s15_s0 = s15_s0,
- .requires_voice_stream = chan_mode_is_tch(mode),
+ .chan_mode = ch_mode_rate.chan_mode,
+ .s15_s0 = ch_mode_rate.s15_s0,
+ .requires_voice_stream = chan_mode_is_tch(ch_mode_rate.chan_mode),
.msc_assigned_cic = req->msc_assigned_cic,
};
@@ -715,7 +713,7 @@ static void send_handover_performed(struct gsm_subscriber_connection *conn)
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->s15_s0;
+ sc.cfg = conn->lchan->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/osmo_bsc_bssap.c b/src/osmo-bsc/osmo_bsc_bssap.c
index ab7f79ce1..85aab22d2 100644
--- a/src/osmo-bsc/osmo_bsc_bssap.c
+++ b/src/osmo-bsc/osmo_bsc_bssap.c
@@ -616,6 +616,101 @@ static int bssmap_handle_lcls_connect_ctrl(struct gsm_subscriber_connection *con
return 0;
}
+/* Select a prefered and an alternative codec rate depending on the available
+ * capabilities. This decision does not include the actual channel load yet,
+ * this is also the reason why the result is a prefered and an alternate
+ * setting. The final decision is made in assignment_fsm.c when the actual
+ * lchan is requested. The preferred lchan will be requested first. If we
+ * find an alternate setting here, this one will be tried secondly if our
+ * primary coice fails. */
+static int select_codecs(struct assignment_request *req, struct gsm0808_channel_type *ct,
+ struct gsm_subscriber_connection *conn)
+{
+ int rc;
+ struct bsc_msc_data *msc;
+
+ msc = conn->sccp.msc;
+ req->ch_mode_rate_alt_present = false;
+
+ switch (ct->ch_rate_type) {
+ case GSM0808_SPEECH_FULL_BM:
+ rc = match_codec_pref(&req->ch_mode_rate_pref, ct, &conn->codec_list, msc, conn_get_bts(conn),
+ RATE_PREF_FR);
+ break;
+ case GSM0808_SPEECH_HALF_LM:
+ rc = match_codec_pref(&req->ch_mode_rate_pref, ct, &conn->codec_list, msc, conn_get_bts(conn),
+ RATE_PREF_HR);
+ break;
+ case GSM0808_SPEECH_PERM:
+ 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_pref, ct, &conn->codec_list, msc, conn_get_bts(conn),
+ RATE_PREF_FR);
+ if (rc < 0) {
+ rc = match_codec_pref(&req->ch_mode_rate_pref, ct, &conn->codec_list, msc, conn_get_bts(conn),
+ RATE_PREF_HR);
+ break;
+ }
+ rc = match_codec_pref(&req->ch_mode_rate_alt, ct, &conn->codec_list, msc, conn_get_bts(conn),
+ RATE_PREF_HR);
+ if (rc == 0)
+ req->ch_mode_rate_alt_present = true;
+ rc = 0;
+ break;
+ case GSM0808_SPEECH_HALF_PREF_NO_CHANGE:
+ case GSM0808_SPEECH_HALF_PREF:
+ rc = match_codec_pref(&req->ch_mode_rate_pref, ct, &conn->codec_list, msc, conn_get_bts(conn),
+ RATE_PREF_HR);
+
+ if (rc < 0) {
+ rc = match_codec_pref(&req->ch_mode_rate_pref, ct, &conn->codec_list, msc, conn_get_bts(conn),
+ RATE_PREF_FR);
+ break;
+ }
+ rc = match_codec_pref(&req->ch_mode_rate_alt, ct, &conn->codec_list, msc, conn_get_bts(conn),
+ RATE_PREF_FR);
+ if (rc == 0)
+ req->ch_mode_rate_alt_present = true;
+ rc = 0;
+ break;
+ default:
+ rc = -EINVAL;
+ break;
+ }
+
+ if (rc < 0) {
+ LOGP(DMSC, LOGL_ERROR, "No supported audio type found for channel_type ="
+ " { ch_indctr=0x%x, ch_rate_type=0x%x, perm_spch=[%s] }\n",
+ ct->ch_indctr, ct->ch_rate_type, osmo_hexdump(ct->perm_spch, ct->perm_spch_len));
+ /* TODO: actually output codec names, e.g. implement
+ * gsm0808_permitted_speech_names[] and iterate perm_spch. */
+ return -EINVAL;
+ }
+
+ if (req->ch_mode_rate_alt_present) {
+ DEBUGP(DMSC, "Found matching audio type (preferred): %s %s for channel_type ="
+ " { ch_indctr=0x%x, ch_rate_type=0x%x, perm_spch=[ %s] }\n",
+ req->ch_mode_rate_pref.full_rate ? "full rate" : "half rate",
+ get_value_string(gsm48_chan_mode_names, req->ch_mode_rate_pref.chan_mode),
+ ct->ch_indctr, ct->ch_rate_type, osmo_hexdump(ct->perm_spch, ct->perm_spch_len));
+ DEBUGP(DMSC, "Found matching audio type (alternative): %s %s for channel_type ="
+ " { ch_indctr=0x%x, ch_rate_type=0x%x, perm_spch=[ %s] }\n",
+ req->ch_mode_rate_alt.full_rate ? "full rate" : "half rate",
+ get_value_string(gsm48_chan_mode_names, req->ch_mode_rate_alt.chan_mode),
+ ct->ch_indctr, ct->ch_rate_type, osmo_hexdump(ct->perm_spch, ct->perm_spch_len));
+ } else {
+ DEBUGP(DMSC, "Found matching audio type: %s %s for channel_type ="
+ " { ch_indctr=0x%x, ch_rate_type=0x%x, perm_spch=[ %s] }\n",
+ req->ch_mode_rate_pref.full_rate ? "full rate" : "half rate",
+ get_value_string(gsm48_chan_mode_names, req->ch_mode_rate_pref.chan_mode),
+ ct->ch_indctr, ct->ch_rate_type, osmo_hexdump(ct->perm_spch, ct->perm_spch_len));
+
+ }
+
+ return 0;
+}
+
/*
* Handle the assignment request message.
*
@@ -625,18 +720,15 @@ static int bssmap_handle_assignm_req(struct gsm_subscriber_connection *conn,
struct msgb *msg, unsigned int length)
{
struct msgb *resp;
- struct bsc_msc_data *msc;
struct tlv_parsed tp;
uint16_t cic = 0;
- enum gsm48_chan_mode chan_mode = GSM48_CMODE_SIGN;
- bool full_rate = false;
- uint16_t s15_s0 = 0;
bool aoip = false;
struct sockaddr_storage rtp_addr;
struct gsm0808_channel_type ct;
uint8_t cause;
int rc;
struct assignment_request req = {};
+ struct channel_mode_and_rate ch_mode_rate_pref = {};
if (!conn) {
LOGP(DMSC, LOGL_ERROR,
@@ -644,7 +736,6 @@ static int bssmap_handle_assignm_req(struct gsm_subscriber_connection *conn,
return -1;
}
- msc = conn->sccp.msc;
aoip = gscon_is_aoip(conn);
tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l4h + 1, length - 1, 0, 0);
@@ -732,33 +823,19 @@ static int bssmap_handle_assignm_req(struct gsm_subscriber_connection *conn,
goto reject;
}
+ req = (struct assignment_request){
+ .aoip = aoip,
+ .msc_assigned_cic = cic,
+ };
+
/* Match codec information from the assignment command against the
* local preferences of the BSC and BTS */
- rc = match_codec_pref(&chan_mode, &full_rate, &s15_s0, &ct, &conn->codec_list,
- msc, conn_get_bts(conn));
+ rc = select_codecs(&req, &ct, conn);
if (rc < 0) {
- LOGP(DMSC, LOGL_ERROR, "No supported audio type found for channel_type ="
- " { ch_indctr=0x%x, ch_rate_type=0x%x, perm_spch=[ %s] }\n",
- ct.ch_indctr, ct.ch_rate_type, osmo_hexdump(ct.perm_spch, ct.perm_spch_len));
- /* TODO: actually output codec names, e.g. implement
- * gsm0808_permitted_speech_names[] and iterate perm_spch. */
cause = GSM0808_CAUSE_REQ_CODEC_TYPE_OR_CONFIG_UNAVAIL;
goto reject;
}
- DEBUGP(DMSC, "Found matching audio type: %s %s for channel_type ="
- " { ch_indctr=0x%x, ch_rate_type=0x%x, perm_spch=[ %s] }\n",
- full_rate? "full rate" : "half rate",
- get_value_string(gsm48_chan_mode_names, chan_mode),
- ct.ch_indctr, ct.ch_rate_type, osmo_hexdump(ct.perm_spch, ct.perm_spch_len));
-
- req = (struct assignment_request){
- .aoip = aoip,
- .msc_assigned_cic = cic,
- .chan_mode = chan_mode,
- .full_rate = full_rate,
- .s15_s0 = s15_s0
- };
if (aoip) {
unsigned int rc = osmo_sockaddr_to_str_and_uint(req.msc_rtp_addr,
sizeof(req.msc_rtp_addr),
@@ -772,9 +849,13 @@ static int bssmap_handle_assignm_req(struct gsm_subscriber_connection *conn,
}
break;
case GSM0808_CHAN_SIGN:
+ ch_mode_rate_pref = (struct channel_mode_and_rate) {
+ .chan_mode = GSM48_CMODE_SIGN,
+ };
+
req = (struct assignment_request){
.aoip = aoip,
- .chan_mode = chan_mode,
+ .ch_mode_rate_pref = ch_mode_rate_pref,
};
break;
default: