diff options
Diffstat (limited to 'openbsc/src')
-rw-r--r-- | openbsc/src/libmsc/gsm_04_08.c | 16 | ||||
-rw-r--r-- | openbsc/src/libmsc/mncc_builtin.c | 111 | ||||
-rw-r--r-- | openbsc/src/libmsc/vty_interface_layer3.c | 45 |
3 files changed, 107 insertions, 65 deletions
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); |