aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Eversberg <jolly@eversberg.eu>2013-03-31 12:01:25 +0200
committerIvan Kluchnikov <kluchnikovi@gmail.com>2015-05-26 15:55:13 +0300
commit8d0f77c8ffe328cd80b6f01e721220cd6867a98d (patch)
treee00a6209fd3b77537d35d99fe92cbd49dccd9ead
parent4e3a2670550ef0cabd8e682395ea385967824049 (diff)
osmo-nitb support for codec negotiation
The caller's most preferred codec is selected out of the union of codecs, which both parties support. Since codec negotiation is done automatically, there is no need to define codec for TCH/F and TCH/H via VTY anymore. Conflicts: openbsc/src/libmsc/gsm_04_08.c openbsc/src/libmsc/vty_interface_layer3.c
-rw-r--r--openbsc/include/openbsc/mncc.h4
-rw-r--r--openbsc/include/openbsc/mncc_int.h6
-rw-r--r--openbsc/src/libmsc/gsm_04_08.c16
-rw-r--r--openbsc/src/libmsc/mncc_builtin.c111
-rw-r--r--openbsc/src/libmsc/vty_interface_layer3.c45
5 files changed, 111 insertions, 71 deletions
diff --git a/openbsc/include/openbsc/mncc.h b/openbsc/include/openbsc/mncc.h
index 46ba23729..865a89ba5 100644
--- a/openbsc/include/openbsc/mncc.h
+++ b/openbsc/include/openbsc/mncc.h
@@ -44,6 +44,10 @@ struct gsm_call {
uint32_t callref;
/* the 'remote' transaction */
uint32_t remote_ref;
+
+ /* the capabilities */
+ uint8_t lchan_type;
+ struct gsm_mncc_bearer_cap bcap;
};
#define MNCC_SETUP_REQ 0x0101
diff --git a/openbsc/include/openbsc/mncc_int.h b/openbsc/include/openbsc/mncc_int.h
index 4f30f08c0..92012c101 100644
--- a/openbsc/include/openbsc/mncc_int.h
+++ b/openbsc/include/openbsc/mncc_int.h
@@ -3,10 +3,4 @@
#include <stdint.h>
-struct mncc_int {
- uint8_t def_codec[2];
-};
-
-extern struct mncc_int mncc_int;
-
#endif
diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c
index 8cfa2e674..9997a11d1 100644
--- a/openbsc/src/libmsc/gsm_04_08.c
+++ b/openbsc/src/libmsc/gsm_04_08.c
@@ -3208,6 +3208,8 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg)
/* If subscriber has no lchan */
if (!conn) {
+ uint8_t type;
+
/* find transaction with this subscriber already paging */
llist_for_each_entry(transt, &net->trans_list, entry) {
/* Transaction of our lchan? */
@@ -3227,9 +3229,20 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg)
/* store setup informations until paging was successfull */
memcpy(&trans->cc.msg, data, sizeof(struct gsm_mncc));
+ switch (data->lchan_type) {
+ case GSM_LCHAN_TCH_F:
+ type = RSL_CHANNEED_TCH_F;
+ break;
+ case GSM_LCHAN_TCH_H:
+ type = RSL_CHANNEED_TCH_ForH;
+ break;
+ default:
+ type = RSL_CHANNEED_SDCCH;
+ }
+
/* Request a channel */
trans->paging_request = subscr_request_channel(subscr,
- RSL_CHANNEED_TCH_F, setup_trig_pag_evt,
+ type, setup_trig_pag_evt,
trans);
if (!trans->paging_request) {
LOGP(DCC, LOGL_ERROR, "Failed to allocate paging token.\n");
@@ -3237,6 +3250,7 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg)
trans_free(trans);
return 0;
}
+
subscr_put(subscr);
return 0;
}
diff --git a/openbsc/src/libmsc/mncc_builtin.c b/openbsc/src/libmsc/mncc_builtin.c
index 5c3461bea..e6c11b183 100644
--- a/openbsc/src/libmsc/mncc_builtin.c
+++ b/openbsc/src/libmsc/mncc_builtin.c
@@ -42,10 +42,6 @@ static LLIST_HEAD(call_list);
static uint32_t new_callref = 0x00000001;
-struct mncc_int mncc_int = {
- .def_codec = { GSM48_CMODE_SPEECH_V1, GSM48_CMODE_SPEECH_V1 },
-};
-
static void free_call(struct gsm_call *call)
{
llist_del(&call->entry);
@@ -65,14 +61,53 @@ static struct gsm_call *get_call_ref(uint32_t callref)
return NULL;
}
-static uint8_t determine_lchan_mode(struct gsm_mncc *setup)
+static void store_bearer_cap(struct gsm_call *call, struct gsm_mncc *mncc)
+{
+ call->lchan_type = mncc->lchan_type;
+ memcpy(&call->bcap, &mncc->bearer_cap, sizeof(struct gsm_mncc_bearer_cap));
+}
+
+#define is_speech_ver_tch_h(speech_ver) ((speech_ver & 1) == 1)
+
+#define speech_ver_to_lchan_mode(speech_ver) (((speech_ver & 0xe) << 4) | 1)
+
+static int determine_lchan_mode(struct gsm_call *calling,
+ struct gsm_call *called)
{
- /* FIXME: check codec capabilities of the phone */
+ int i, j;
- if (setup->lchan_type != GSM_LCHAN_TCH_H)
- return mncc_int.def_codec[0];
- else
- return mncc_int.def_codec[1];
+ /* FIXME: dynamic channel configuration */
+ if (calling->lchan_type != called->lchan_type) {
+ LOGP(DMNCC, LOGL_NOTICE, "Not equal lchan_types\n");
+ return -ENOTSUP;
+ }
+ if (calling->lchan_type != GSM_LCHAN_TCH_F
+ && calling->lchan_type != GSM_LCHAN_TCH_H) {
+ LOGP(DMNCC, LOGL_NOTICE, "Not TCH lchan_types\n");
+ return -ENOTSUP;
+ }
+
+ /* select best codec, as prefered by the caller and supporte by both. */
+ for (i = 0; calling->bcap.speech_ver[i] >= 0; i++) {
+ /* omit capability of different channel type
+ * FIXME: dynamic channel configuration */
+ if (calling->lchan_type == GSM_LCHAN_TCH_F
+ && is_speech_ver_tch_h(calling->bcap.speech_ver[i]))
+ continue;
+ if (calling->lchan_type == GSM_LCHAN_TCH_H
+ && !is_speech_ver_tch_h(calling->bcap.speech_ver[i]))
+ continue;
+ for (j = 0; called->bcap.speech_ver[j] >= 0; j++) {
+ if (calling->bcap.speech_ver[i]
+ == called->bcap.speech_ver[j]) {
+ /* convert speech version to lchan mode */
+ return speech_ver_to_lchan_mode(
+ calling->bcap.speech_ver[i]);
+ }
+ }
+ }
+
+ return -ENOTSUP;
}
/* on incoming call, look up database and send setup to remote subscr. */
@@ -129,12 +164,8 @@ static int mncc_setup_ind(struct gsm_call *call, int msg_type,
DEBUGP(DMNCC, "(call %x) Accepting call.\n", call->callref);
mncc_tx_to_cc(call->net, MNCC_CALL_PROC_REQ, &mncc);
- /* modify mode */
- memset(&mncc, 0, sizeof(struct gsm_mncc));
- mncc.callref = call->callref;
- mncc.lchan_mode = determine_lchan_mode(setup);
- DEBUGP(DMNCC, "(call %x) Modify channel mode.\n", call->callref);
- mncc_tx_to_cc(call->net, MNCC_LCHAN_MODIFY, &mncc);
+ /* store bearer capabilites of supported modes */
+ store_bearer_cap(call, setup);
/* send setup to remote */
// setup->fields |= MNCC_F_SIGNAL;
@@ -149,6 +180,50 @@ out_reject:
return 0;
}
+static int mncc_call_conf_ind(struct gsm_call *call, int msg_type,
+ struct gsm_mncc *conf)
+{
+ struct gsm_call *remote;
+ struct gsm_mncc mncc;
+ int mode;
+
+ memset(&mncc, 0, sizeof(struct gsm_mncc));
+ mncc.callref = call->callref;
+
+ /* send alerting to remote */
+ if (!(remote = get_call_ref(call->remote_ref)))
+ return 0;
+
+ /* store bearer capabilites of supported modes */
+ store_bearer_cap(call, conf);
+
+ mode = determine_lchan_mode(call, remote);
+ if (mode < 0) {
+ LOGP(DMNCC, LOGL_NOTICE, "(call %x,%x) There is no commonly "
+ "supported speech version\n", call->callref,
+ remote->callref);
+ mncc_set_cause(&mncc, GSM48_CAUSE_LOC_PRN_S_LU,
+ GSM48_CC_CAUSE_BEARER_CA_UNAVAIL);
+ goto out_release;
+ }
+
+ /* modify mode */
+ mncc.lchan_mode = mode;
+ DEBUGP(DMNCC, "(call %x) Modify channel mode.\n", call->callref);
+ mncc_tx_to_cc(call->net, MNCC_LCHAN_MODIFY, &mncc);
+ mncc.callref = remote->callref;
+ DEBUGP(DMNCC, "(call %x) Modify channel mode.\n", remote->callref);
+ mncc_tx_to_cc(remote->net, MNCC_LCHAN_MODIFY, &mncc);
+
+ return 0;
+
+out_release:
+ mncc_tx_to_cc(call->net, MNCC_REL_REQ, &mncc);
+ free_call(call);
+ mncc_tx_to_cc(remote->net, MNCC_REL_REQ, &mncc);
+ free_call(remote);
+ return 0;
+}
static int mncc_alert_ind(struct gsm_call *call, int msg_type,
struct gsm_mncc *alert)
{
@@ -357,9 +432,7 @@ int int_mncc_recv(struct gsm_network *net, struct msgb *msg)
case MNCC_SETUP_COMPL_IND:
break;
case MNCC_CALL_CONF_IND:
- /* we now need to MODIFY the channel */
- data->lchan_mode = determine_lchan_mode(data);
- mncc_tx_to_cc(call->net, MNCC_LCHAN_MODIFY, data);
+ rc = mncc_call_conf_ind(call, msg_type, arg);
break;
case MNCC_ALERT_IND:
rc = mncc_alert_ind(call, msg_type, arg);
diff --git a/openbsc/src/libmsc/vty_interface_layer3.c b/openbsc/src/libmsc/vty_interface_layer3.c
index 6cf51a33f..de33126e1 100644
--- a/openbsc/src/libmsc/vty_interface_layer3.c
+++ b/openbsc/src/libmsc/vty_interface_layer3.c
@@ -882,19 +882,6 @@ static struct cmd_node mncc_int_node = {
1,
};
-static const struct value_string tchf_codec_names[] = {
- { GSM48_CMODE_SPEECH_V1, "fr" },
- { GSM48_CMODE_SPEECH_EFR, "efr" },
- { GSM48_CMODE_SPEECH_AMR, "amr" },
- { 0, NULL }
-};
-
-static const struct value_string tchh_codec_names[] = {
- { GSM48_CMODE_SPEECH_V1, "hr" },
- { GSM48_CMODE_SPEECH_AMR, "amr" },
- { 0, NULL }
-};
-
static int config_write_mncc_int(struct vty *vty)
{
uint16_t meas_port;
@@ -905,12 +892,6 @@ static int config_write_mncc_int(struct vty *vty)
meas_scenario = meas_feed_scenario_get();
vty_out(vty, "mncc-int%s", VTY_NEWLINE);
- vty_out(vty, " default-codec tch-f %s%s",
- get_value_string(tchf_codec_names, mncc_int.def_codec[0]),
- VTY_NEWLINE);
- vty_out(vty, " default-codec tch-h %s%s",
- get_value_string(tchh_codec_names, mncc_int.def_codec[1]),
- VTY_NEWLINE);
if (meas_port)
vty_out(vty, " meas-feed destination %s %u%s",
meas_host, meas_port, VTY_NEWLINE);
@@ -918,29 +899,6 @@ static int config_write_mncc_int(struct vty *vty)
vty_out(vty, " meas-feed scenario %s%s",
meas_scenario, VTY_NEWLINE);
-
- return CMD_SUCCESS;
-}
-
-DEFUN(mnccint_def_codec_f,
- mnccint_def_codec_f_cmd,
- "default-codec tch-f (fr|efr|amr)",
- "Set default codec\n" "Codec for TCH/F\n"
- "Full-Rate\n" "Enhanced Full-Rate\n" "Adaptive Multi-Rate\n")
-{
- mncc_int.def_codec[0] = get_string_value(tchf_codec_names, argv[0]);
-
- return CMD_SUCCESS;
-}
-
-DEFUN(mnccint_def_codec_h,
- mnccint_def_codec_h_cmd,
- "default-codec tch-h (hr|amr)",
- "Set default codec\n" "Codec for TCH/H\n"
- "Half-Rate\n" "Adaptive Multi-Rate\n")
-{
- mncc_int.def_codec[1] = get_string_value(tchh_codec_names, argv[0]);
-
return CMD_SUCCESS;
}
@@ -1083,11 +1041,8 @@ int bsc_vty_init_extra(void)
install_element(CONFIG_NODE, &cfg_mncc_int_cmd);
install_node(&mncc_int_node, config_write_mncc_int);
vty_install_default(MNCC_INT_NODE);
- install_element(MNCC_INT_NODE, &mnccint_def_codec_f_cmd);
- install_element(MNCC_INT_NODE, &mnccint_def_codec_h_cmd);
install_element(MNCC_INT_NODE, &mnccint_meas_feed_cmd);
install_element(MNCC_INT_NODE, &meas_feed_scenario_cmd);
-
install_element(CFG_LOG_NODE, &log_level_sms_cmd);
install_element(CFG_LOG_NODE, &logging_fltr_imsi_cmd);