aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Eversberg <jolly@eversberg.eu>2013-03-31 12:01:25 +0200
committerAndreas Eversberg <jolly@eversberg.eu>2015-12-27 22:26:33 +0100
commit5724fb76169008c7f7d6bf8ffedbe2a4a78f8e00 (patch)
tree3e617d3852cbe6cdee98fbe58c3c24fec5ba42d6
parenta964c3e894e13530d17eff50d3903d8ac968bb37 (diff)
osmo-nitb support for codec negotiationjolly/32c3
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.
-rw-r--r--openbsc/include/openbsc/mncc.h4
-rw-r--r--openbsc/include/openbsc/mncc_int.h8
-rw-r--r--openbsc/src/libmsc/gsm_04_08.c17
-rw-r--r--openbsc/src/libmsc/mncc_builtin.c112
-rw-r--r--openbsc/src/libmsc/vty_interface_layer3.c43
5 files changed, 109 insertions, 75 deletions
diff --git a/openbsc/include/openbsc/mncc.h b/openbsc/include/openbsc/mncc.h
index 10192addd..fd1f2badd 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 213ce1414..92012c101 100644
--- a/openbsc/include/openbsc/mncc_int.h
+++ b/openbsc/include/openbsc/mncc_int.h
@@ -3,12 +3,4 @@
#include <stdint.h>
-struct mncc_int {
- uint8_t def_codec[2];
-};
-
-extern struct mncc_int mncc_int;
-
-uint8_t mncc_codec_for_mode(int lchan_type);
-
#endif
diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c
index 7e8134ee7..a961fc80b 100644
--- a/openbsc/src/libmsc/gsm_04_08.c
+++ b/openbsc/src/libmsc/gsm_04_08.c
@@ -3089,7 +3089,7 @@ static int tch_rtp_create(struct gsm_network *net, uint32_t callref)
if (lchan->tch_mode == GSM48_CMODE_SIGN) {
trans->conn->mncc_rtp_create_pending = 1;
return gsm0808_assign_req(trans->conn,
- mncc_codec_for_mode(lchan->type),
+ GSM48_CMODE_SPEECH_V1,
lchan->type != GSM_LCHAN_TCH_H);
}
@@ -3355,6 +3355,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? */
@@ -3374,9 +3376,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");
diff --git a/openbsc/src/libmsc/mncc_builtin.c b/openbsc/src/libmsc/mncc_builtin.c
index 77df6fba3..8fe4c33e0 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,19 +61,53 @@ static struct gsm_call *get_call_ref(uint32_t callref)
return NULL;
}
-uint8_t mncc_codec_for_mode(int lchan_type)
+static void store_bearer_cap(struct gsm_call *call, struct gsm_mncc *mncc)
{
- /* FIXME: check codec capabilities of the phone */
-
- if (lchan_type != GSM_LCHAN_TCH_H)
- return mncc_int.def_codec[0];
- else
- return mncc_int.def_codec[1];
+ call->lchan_type = mncc->lchan_type;
+ memcpy(&call->bcap, &mncc->bearer_cap, sizeof(struct gsm_mncc_bearer_cap));
}
-static uint8_t determine_lchan_mode(struct gsm_mncc *setup)
+#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)
{
- return mncc_codec_for_mode(setup->lchan_type);
+ int i, j;
+
+ /* 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. */
@@ -134,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;
@@ -154,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)
{
@@ -362,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 f49c53a08..cc86d5265 100644
--- a/openbsc/src/libmsc/vty_interface_layer3.c
+++ b/openbsc/src/libmsc/vty_interface_layer3.c
@@ -888,19 +888,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;
@@ -911,12 +898,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);
@@ -928,28 +909,6 @@ static int config_write_mncc_int(struct vty *vty)
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;
-}
-
#define OBSOLETE_MSG "Obsolete\n"
/* this is just for backwards compatibility as the sms code moved into
* libosmocore and old config files no longer parse... */
@@ -1109,8 +1068,6 @@ 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);