diff options
-rw-r--r-- | src/host/layer23/include/osmocom/bb/mobile/settings.h | 1 | ||||
-rw-r--r-- | src/host/layer23/include/osmocom/bb/mobile/support.h | 7 | ||||
-rw-r--r-- | src/host/layer23/src/mobile/gsm48_cc.c | 5 | ||||
-rw-r--r-- | src/host/layer23/src/mobile/gsm48_rr.c | 133 | ||||
-rw-r--r-- | src/host/layer23/src/mobile/mnccms.c | 192 | ||||
-rw-r--r-- | src/host/layer23/src/mobile/settings.c | 4 | ||||
-rw-r--r-- | src/host/layer23/src/mobile/support.c | 7 | ||||
-rw-r--r-- | src/host/layer23/src/mobile/vty_interface.c | 103 |
8 files changed, 420 insertions, 32 deletions
diff --git a/src/host/layer23/include/osmocom/bb/mobile/settings.h b/src/host/layer23/include/osmocom/bb/mobile/settings.h index 7ac54e92..429d417d 100644 --- a/src/host/layer23/include/osmocom/bb/mobile/settings.h +++ b/src/host/layer23/include/osmocom/bb/mobile/settings.h @@ -32,6 +32,7 @@ struct gsm_settings { /* call related settings */ uint8_t cw; /* set if call-waiting is allowed */ uint8_t clip, clir; + uint8_t half, half_prefer; /* changing default behavior */ uint8_t alter_tx_power; diff --git a/src/host/layer23/include/osmocom/bb/mobile/support.h b/src/host/layer23/include/osmocom/bb/mobile/support.h index 782b6406..4e962219 100644 --- a/src/host/layer23/include/osmocom/bb/mobile/support.h +++ b/src/host/layer23/include/osmocom/bb/mobile/support.h @@ -80,6 +80,13 @@ struct gsm_support { int8_t min_rxlev_db; uint8_t scan_to; uint8_t sync_to; + + /* codecs */ + uint8_t full_v1; + uint8_t full_v2; + uint8_t full_v3; + uint8_t half_v1; + uint8_t half_v3; }; struct gsm_support_scan_max { diff --git a/src/host/layer23/src/mobile/gsm48_cc.c b/src/host/layer23/src/mobile/gsm48_cc.c index 4b8db53e..a58f627a 100644 --- a/src/host/layer23/src/mobile/gsm48_cc.c +++ b/src/host/layer23/src/mobile/gsm48_cc.c @@ -550,9 +550,10 @@ static int gsm48_cc_tx_setup(struct gsm_trans *trans) */ gsm48_start_cc_timer(trans, 0x303, GSM48_T303_MS); - if (!setup->emergency) { - /* bearer capability */ + /* bearer capability (optional for emergency calls only) */ + if (setup->fields & MNCC_F_BEARER_CAP) gsm48_encode_bearer_cap(nmsg, 0, &setup->bearer_cap); + if (!setup->emergency) { /* facility */ if (setup->fields & MNCC_F_FACILITY) gsm48_encode_facility(nmsg, 0, &setup->facility); diff --git a/src/host/layer23/src/mobile/gsm48_rr.c b/src/host/layer23/src/mobile/gsm48_rr.c index 333b379b..656d4c2b 100644 --- a/src/host/layer23/src/mobile/gsm48_rr.c +++ b/src/host/layer23/src/mobile/gsm48_rr.c @@ -86,6 +86,8 @@ static void stop_rr_t3124(struct gsm48_rrlayer *rr); static int gsm48_rcv_rsl(struct osmocom_ms *ms, struct msgb *msg); static int gsm48_rr_dl_est(struct osmocom_ms *ms); static int gsm48_rr_tx_meas_rep(struct osmocom_ms *ms); +static int gsm48_rr_set_mode(struct osmocom_ms *ms, uint8_t chan_nr, + uint8_t mode); /* * support @@ -278,6 +280,79 @@ static int gsm48_apply_v_sd(struct gsm48_rrlayer *rr, struct msgb *msg) return 0; } +/* set channel mode if supported, or return error cause */ +static uint8_t gsm48_rr_check_mode(struct osmocom_ms *ms, uint8_t chan_nr, + uint8_t mode) +{ + struct gsm_support *sup = &ms->support; + uint8_t ch_type, ch_subch, ch_ts; + + /* only complain if we use TCH/F or TCH/H */ + rsl_dec_chan_nr(chan_nr, &ch_type, &ch_subch, &ch_ts); + if (ch_type != RSL_CHAN_Bm_ACCHs + && ch_type != RSL_CHAN_Lm_ACCHs) + return 0; + + switch (mode) { + case GSM48_CMODE_SIGN: + LOGP(DRR, LOGL_INFO, "Mode: signalling\n"); + break; + case GSM48_CMODE_SPEECH_V1: + if (ch_type == RSL_CHAN_Bm_ACCHs) { + if (!sup->full_v1) { + LOGP(DRR, LOGL_NOTICE, "Not supporting " + "full-rate speech V1\n"); + return GSM48_RR_CAUSE_CHAN_MODE_UNACCT; + } + LOGP(DRR, LOGL_INFO, "Mode: full-rate speech V1\n"); + } else { + if (!sup->half_v1) { + LOGP(DRR, LOGL_NOTICE, "Not supporting " + "half-rate speech V1\n"); + return GSM48_RR_CAUSE_CHAN_MODE_UNACCT; + } + LOGP(DRR, LOGL_INFO, "Mode: half-rate speech V1\n"); + } + break; + case GSM48_CMODE_SPEECH_EFR: + if (ch_type == RSL_CHAN_Bm_ACCHs) { + if (!sup->full_v2) { + LOGP(DRR, LOGL_NOTICE, "Not supporting " + "full-rate speech V2\n"); + return GSM48_RR_CAUSE_CHAN_MODE_UNACCT; + } + LOGP(DRR, LOGL_INFO, "Mode: full-rate speech V2\n"); + } else { + LOGP(DRR, LOGL_NOTICE, "Not supporting " + "half-rate speech V2\n"); + return GSM48_RR_CAUSE_CHAN_MODE_UNACCT; + } + break; + case GSM48_CMODE_SPEECH_AMR: + if (ch_type == RSL_CHAN_Bm_ACCHs) { + if (!sup->full_v3) { + LOGP(DRR, LOGL_NOTICE, "Not supporting " + "full-rate speech V3\n"); + return GSM48_RR_CAUSE_CHAN_MODE_UNACCT; + } + LOGP(DRR, LOGL_INFO, "Mode: full-rate speech V3\n"); + } else { + if (!sup->half_v3) { + LOGP(DRR, LOGL_NOTICE, "Not supporting " + "half-rate speech V3\n"); + return GSM48_RR_CAUSE_CHAN_MODE_UNACCT; + } + LOGP(DRR, LOGL_INFO, "Mode: half-rate speech V3\n"); + } + break; + default: + LOGP(DRR, LOGL_ERROR, "Mode 0x%02x not supported!\n", mode); + return GSM48_RR_CAUSE_CHAN_MODE_UNACCT; + } + + return 0; +} + /* * state transition */ @@ -883,7 +958,7 @@ static int gsm48_rr_rx_cip_mode_cmd(struct osmocom_ms *ms, struct msgb *msg) || (alg_id == GSM_CIPHER_A5_7 && !sup->a5_7))) { LOGP(DRR, LOGL_NOTICE, "algo not supported\n"); return gsm48_rr_tx_rr_status(ms, - GSM48_RR_CAUSE_CHAN_MODE_UNACCT); + GSM48_RR_CAUSE_PROT_ERROR_UNSPC); } /* check if we have no key */ @@ -3093,7 +3168,8 @@ static int gsm48_rr_activate_channel(struct osmocom_ms *ms, if (rr->cipher_on) l1ctl_tx_crypto_req(ms, rr->cipher_type + 1, subscr->key, 8); -#warning FIXME: channel mode + + gsm48_rr_set_mode(ms, cd->chan_nr, cd->mode); return 0; } @@ -3113,7 +3189,8 @@ static int gsm48_rr_channel_after_time(struct osmocom_ms *ms, if (rr->cipher_on) l1ctl_tx_crypto_req(ms, rr->cipher_type + 1, subscr->key, 8); -#warning FIXME: channel mode + + gsm48_rr_set_mode(ms, cd->chan_nr, cd->mode); return 0; } @@ -3473,6 +3550,25 @@ static int gsm48_rr_rx_chan_rel(struct osmocom_ms *ms, struct msgb *msg) * frequency redefition, chanel mode modify, assignment, and handover */ +/* set channel mode in case of TCH */ +static int gsm48_rr_set_mode(struct osmocom_ms *ms, uint8_t chan_nr, + uint8_t mode) +{ + uint8_t ch_type, ch_subch, ch_ts; + + /* only apply mode to TCH/F or TCH/H */ + rsl_dec_chan_nr(chan_nr, &ch_type, &ch_subch, &ch_ts); + if (ch_type != RSL_CHAN_Bm_ACCHs + && ch_type != RSL_CHAN_Lm_ACCHs) + return -ENOTSUP; + + /* setting (new) timing advance */ + LOGP(DRR, LOGL_INFO, "setting TCH mode to %d\n", mode); + l1ctl_tx_tch_mode_req(ms, mode); + + return 0; +} + /* 9.1.13 FREQUENCY REDEFINITION is received */ static int gsm48_rr_rx_frq_redef(struct osmocom_ms *ms, struct msgb *msg) { @@ -3589,7 +3685,7 @@ static int gsm48_rr_rx_chan_modify(struct osmocom_ms *ms, struct msgb *msg) int payload_len = msgb_l3len(msg) - sizeof(*gh) - sizeof(*cm); struct gsm48_rr_cd *cd = &rr->cd_now; uint8_t ch_type, ch_subch, ch_ts; - uint8_t mode; + uint8_t cause; LOGP(DRR, LOGL_INFO, "CHANNEL MODE MODIFY\n"); @@ -3619,21 +3715,13 @@ static int gsm48_rr_rx_chan_modify(struct osmocom_ms *ms, struct msgb *msg) ch_ts, ch_subch, cd->tsc, cm->mode); } /* mode */ - mode = cm->mode; - switch (mode) { - case GSM48_CMODE_SIGN: - LOGP(DRR, LOGL_INFO, "Mode set to signalling.\n"); - break; - case GSM48_CMODE_SPEECH_V1: - LOGP(DRR, LOGL_INFO, "Mode set to GSM full-rate codec.\n"); - break; - default: - LOGP(DRR, LOGL_ERROR, "Mode %u not supported!\n", mode); - } - rr->cd_now.mode = mode; -#warning FIXME: channel mode + cause = gsm48_rr_check_mode(ms, cd->chan_nr, cm->mode); + if (cause) + return gsm48_rr_tx_rr_status(ms, cause); + cd->mode = cm->mode; + gsm48_rr_set_mode(ms, cd->chan_nr, cd->mode); - return gsm48_rr_tx_chan_modify_ack(ms, &cm->chan_desc, mode); + return gsm48_rr_tx_chan_modify_ack(ms, &cm->chan_desc, cm->mode); } /* 9.1.3 sending ASSIGNMENT COMPLETE */ @@ -3860,6 +3948,7 @@ static int gsm48_rr_rx_ass_cmd(struct osmocom_ms *ms, struct msgb *msg) "mobile allocation after time\n"); memcpy(&cdb->mob_alloc_lv, &cda->mob_alloc_lv, sizeof(cdb->mob_alloc_lv)); + } else if (cda->freq_list_lv[0]) { LOGP(DRR, LOGL_INFO, " before: hopping required and " "frequency list not available, using " @@ -3901,7 +3990,7 @@ static int gsm48_rr_rx_ass_cmd(struct osmocom_ms *ms, struct msgb *msg) cda->mode = cdb->mode = rr->cd_now.mode; /* cipher mode setting */ - if (TLVP_PRESENT(&tp, GSM48_IE_CIP_MODE_SET)) + if (TLVP_PRESENT(&tp, GSM48_IE_CIP_MODE_SET)) { cda->cipher = cdb->cipher = *TLVP_VAL(&tp, GSM48_IE_CIP_MODE_SET); LOGP(DRR, LOGL_INFO, " both: changing cipher mode 0x%02x\n", @@ -3943,6 +4032,9 @@ static int gsm48_rr_rx_ass_cmd(struct osmocom_ms *ms, struct msgb *msg) } /* check if channels are valid */ + cause = gsm48_rr_check_mode(ms, cda->chan_nr, cda->mode); + if (cause) + return gsm48_rr_tx_ass_fail(ms, cause); if (before_time) { cause = gsm48_rr_render_ma(ms, cdb, ma, &ma_len); if (cause) @@ -4231,6 +4323,7 @@ static int gsm48_rr_rx_hando_cmd(struct osmocom_ms *ms, struct msgb *msg) "mobile allocation after time\n"); memcpy(&cdb->mob_alloc_lv, &cda->mob_alloc_lv, sizeof(cdb->mob_alloc_lv)); + } else if (cda->freq_list_lv[0]) { LOGP(DRR, LOGL_INFO, " before: hopping required and " "frequency list not available, using " @@ -4272,7 +4365,7 @@ static int gsm48_rr_rx_hando_cmd(struct osmocom_ms *ms, struct msgb *msg) cda->mode = cdb->mode = rr->cd_now.mode; /* cipher mode setting */ - if (TLVP_PRESENT(&tp, GSM48_IE_CIP_MODE_SET)) + if (TLVP_PRESENT(&tp, GSM48_IE_CIP_MODE_SET)) { cda->cipher = cdb->cipher = *TLVP_VAL(&tp, GSM48_IE_CIP_MODE_SET); LOGP(DRR, LOGL_INFO, " both: changing cipher mode 0x%02x\n", diff --git a/src/host/layer23/src/mobile/mnccms.c b/src/host/layer23/src/mobile/mnccms.c index 6940ed12..9aeaf4dc 100644 --- a/src/host/layer23/src/mobile/mnccms.c +++ b/src/host/layer23/src/mobile/mnccms.c @@ -61,6 +61,117 @@ struct gsm_call *get_call_ref(uint32_t callref) return NULL; } +static int8_t mncc_get_bearer(struct gsm_support *sup, uint8_t speech_ver) +{ + switch (speech_ver) { + case 4: + if (sup->full_v3) + LOGP(DMNCC, LOGL_INFO, " net suggests full rate v3\n"); + else { + LOGP(DMNCC, LOGL_INFO, " full rate v3 not supported\n"); + speech_ver = -1; + } + break; + case 2: + if (sup->full_v2) + LOGP(DMNCC, LOGL_INFO, " net suggests full rate v2\n"); + else { + LOGP(DMNCC, LOGL_INFO, " full rate v2 not supported\n"); + speech_ver = -1; + } + break; + case 0: /* mandatory */ + if (sup->full_v1) + LOGP(DMNCC, LOGL_INFO, " net suggests full rate v1\n"); + else { + LOGP(DMNCC, LOGL_INFO, " full rate v1 not supported\n"); + speech_ver = -1; + } + break; + case 5: + if (sup->half_v3) + LOGP(DMNCC, LOGL_INFO, " net suggests half rate v3\n"); + else { + LOGP(DMNCC, LOGL_INFO, " half rate v3 not supported\n"); + speech_ver = -1; + } + break; + case 1: + if (sup->half_v1) + LOGP(DMNCC, LOGL_INFO, " net suggests half rate v1\n"); + else { + LOGP(DMNCC, LOGL_INFO, " half rate v1 not supported\n"); + speech_ver = -1; + } + break; + default: + LOGP(DMNCC, LOGL_INFO, " net suggests unknown speech version " + "%d\n", speech_ver); + speech_ver = -1; + } + + return speech_ver; +} + +static void mncc_set_bearer(struct osmocom_ms *ms, int8_t speech_ver, + struct gsm_mncc *mncc) +{ + struct gsm_support *sup = &ms->support; + struct gsm_settings *set = &ms->settings; + int i = 0; + + mncc->fields |= MNCC_F_BEARER_CAP; + mncc->bearer_cap.coding = 0; + if (sup->ch_cap == GSM_CAP_SDCCH_TCHF_TCHH + && (sup->half_v1 || sup->half_v3)) { + mncc->bearer_cap.radio = 3; + LOGP(DMNCC, LOGL_INFO, " support TCH/H also\n"); + } else { + mncc->bearer_cap.radio = 1; + LOGP(DMNCC, LOGL_INFO, " support TCH/F only\n"); + } + mncc->bearer_cap.speech_ctm = 0; + /* if no specific speech_ver is given */ + if (speech_ver < 0) { + /* if half rate is supported and prefered */ + if (sup->half_v3 && set->half && set->half_prefer) { + mncc->bearer_cap.speech_ver[i++] = 5; + LOGP(DMNCC, LOGL_INFO, " support half rate v3\n"); + } + if (sup->half_v1 && set->half && set->half_prefer) { + mncc->bearer_cap.speech_ver[i++] = 1; + LOGP(DMNCC, LOGL_INFO, " support half rate v1\n"); + } + /* if full rate is supported */ + if (sup->full_v3) { + mncc->bearer_cap.speech_ver[i++] = 4; + LOGP(DMNCC, LOGL_INFO, " support full rate v3\n"); + } + if (sup->full_v2) { + mncc->bearer_cap.speech_ver[i++] = 2; + LOGP(DMNCC, LOGL_INFO, " support full rate v2\n"); + } + if (sup->full_v1) { /* mandatory, so it's always true */ + mncc->bearer_cap.speech_ver[i++] = 0; + LOGP(DMNCC, LOGL_INFO, " support full rate v1\n"); + } + /* if half rate is supported and not prefered */ + if (sup->half_v3 && set->half && !set->half_prefer) { + mncc->bearer_cap.speech_ver[i++] = 5; + LOGP(DMNCC, LOGL_INFO, " support half rate v3\n"); + } + if (sup->half_v1 && set->half && !set->half_prefer) { + mncc->bearer_cap.speech_ver[i++] = 1; + LOGP(DMNCC, LOGL_INFO, " support half rate v1\n"); + } + /* if specific speech_ver is given (it must be supported) */ + } else + mncc->bearer_cap.speech_ver[i++] = speech_ver; + mncc->bearer_cap.speech_ver[i] = -1; /* end of list */ + mncc->bearer_cap.transfer = 0; + mncc->bearer_cap.mode = 0; +} + /* * MNCCms dummy application */ @@ -92,10 +203,13 @@ int mncc_recv_dummy(struct osmocom_ms *ms, int msg_type, void *arg) int mncc_recv_mobile(struct osmocom_ms *ms, int msg_type, void *arg) { + struct gsm_settings *set = &ms->settings; + struct gsm_support *sup = &ms->support; struct gsm_mncc *data = arg; struct gsm_call *call = get_call_ref(data->callref); struct gsm_mncc mncc; uint8_t cause; + int8_t speech_ver = -1, speech_ver_half = -1, temp; int first_call = 0; /* call does not exist */ @@ -203,6 +317,10 @@ int mncc_recv_mobile(struct osmocom_ms *ms, int msg_type, void *arg) vty_notify(ms, NULL); vty_notify(ms, "Call is proceeding\n"); LOGP(DMNCC, LOGL_INFO, "Call is proceeding\n"); + if ((data->fields & MNCC_F_BEARER_CAP) + && data->bearer_cap.speech_ver[0] >= 0) { + mncc_get_bearer(sup, data->bearer_cap.speech_ver[0]); + } break; case MNCC_ALERT_IND: vty_notify(ms, NULL); @@ -222,6 +340,59 @@ int mncc_recv_mobile(struct osmocom_ms *ms, int msg_type, void *arg) cause = GSM48_CC_CAUSE_USER_BUSY; goto release; } + /* select first supported speech_ver */ + if ((data->fields & MNCC_F_BEARER_CAP)) { + int i; + + for (i = 0; data->bearer_cap.speech_ver[i] >= 0; i++) { + + temp = mncc_get_bearer(sup, + data->bearer_cap.speech_ver[i]); + if (temp < 0) + continue; + if (temp == 5 || temp == 1) { /* half */ + /* only the first half rate */ + if (speech_ver_half < 0) + speech_ver_half = temp; + } else { + /* only the first full rate */ + if (speech_ver < 0) + speech_ver = temp; + } + } + /* half and full given */ + if (speech_ver_half >= 0 && speech_ver >= 0) { + if (set->half_prefer) { + LOGP(DMNCC, LOGL_INFO, " both supported" + " codec rates are given, using " + "preferred half rate\n"); + speech_ver = speech_ver_half; + } else + LOGP(DMNCC, LOGL_INFO, " both supported" + " codec rates are given, using " + "preferred full rate\n"); + } else if (speech_ver_half < 0 && speech_ver < 0) { + LOGP(DMNCC, LOGL_INFO, " no supported codec " + "rate is given\n"); + /* only half rate is given, use it */ + } else if (speech_ver_half >= 0) { + LOGP(DMNCC, LOGL_INFO, " only supported half " + "rate codec is given, using it\n"); + speech_ver = speech_ver_half; + /* only full rate is given, use it */ + } else { + LOGP(DMNCC, LOGL_INFO, " only supported full " + "rate codec is given, using it\n"); + } + if (speech_ver < 0) { + vty_notify(ms, "Incomming call rejected, no " + "voice call\n"); + LOGP(DMNCC, LOGL_INFO, "Incomming call " + "rejected, no voice call\n"); + cause = GSM48_CC_CAUSE_BEARERSERV_UNIMPL; + goto release; + } + } /* presentation allowed if present == 0 */ if (data->calling.present || !data->calling.number[0]) vty_notify(ms, "Incomming call (anonymous)\n"); @@ -238,6 +409,16 @@ int mncc_recv_mobile(struct osmocom_ms *ms, int msg_type, void *arg) data->calling.number, call->callref); memset(&mncc, 0, sizeof(struct gsm_mncc)); mncc.callref = call->callref; + /* only include bearer cap, if not given in setup + * or if multiple codecs are given + * or if not only full rate + * or if given codec is unimplemented + */ + if (!(data->fields & MNCC_F_BEARER_CAP) || speech_ver < 0) + mncc_set_bearer(ms, -1, &mncc); + else if (data->bearer_cap.speech_ver[1] >= 0 + || speech_ver != 0) + mncc_set_bearer(ms, speech_ver, &mncc); mncc_send(ms, MNCC_CALL_CONF_REQ, &mncc); if (first_call) LOGP(DMNCC, LOGL_INFO, "Ring!\n"); @@ -324,20 +505,13 @@ int mncc_call(struct osmocom_ms *ms, char *number) setup.called.type = 1; /* international */ } else setup.called.type = 0; /* auto/unknown - prefix must be - used */ + used */ setup.called.plan = 1; /* ISDN */ strncpy(setup.called.number, number, sizeof(setup.called.number) - 1); /* bearer capability (mandatory) */ - setup.fields |= MNCC_F_BEARER_CAP; - setup.bearer_cap.coding = 0; - setup.bearer_cap.radio = 1; - setup.bearer_cap.speech_ctm = 0; - setup.bearer_cap.speech_ver[0] = 0; - setup.bearer_cap.speech_ver[1] = -1; /* end of list */ - setup.bearer_cap.transfer = 0; - setup.bearer_cap.mode = 0; + mncc_set_bearer(ms, -1, &setup); if (ms->settings.clir) setup.clir.sup = 1; else if (ms->settings.clip) diff --git a/src/host/layer23/src/mobile/settings.c b/src/host/layer23/src/mobile/settings.c index 1aef48b0..6b6a9325 100644 --- a/src/host/layer23/src/mobile/settings.c +++ b/src/host/layer23/src/mobile/settings.c @@ -31,6 +31,7 @@ int gsm_settings_init(struct osmocom_ms *ms) { struct gsm_settings *set = &ms->settings; + struct gsm_support *sup = &ms->support; /* IMEI */ sprintf(set->imei, "000000000000000"); @@ -40,6 +41,9 @@ int gsm_settings_init(struct osmocom_ms *ms) strcpy(set->test_imsi, "001010000000000"); set->test_rplmn_mcc = set->test_rplmn_mnc = 1; + if (sup->half_v1 || sup->half_v3) + set->half = 1; + return 0; } diff --git a/src/host/layer23/src/mobile/support.c b/src/host/layer23/src/mobile/support.c index 3fd581d9..631fd5bf 100644 --- a/src/host/layer23/src/mobile/support.c +++ b/src/host/layer23/src/mobile/support.c @@ -104,6 +104,13 @@ void gsm_support_init(struct osmocom_ms *ms) sup->min_rxlev_db = -100; // TODO sup->sync_to = 6; /* how long to wait sync (0.9 s) */ sup->scan_to = 4; /* how long to wait for all sysinfos (>=4 s) */ + + /* codec */ + sup->full_v1 = 1; + sup->full_v2 = 1; + sup->full_v3 = 0; + sup->half_v1 = 0; + sup->half_v3 = 0; } /* (3.2.1) maximum channels to scan within each band */ diff --git a/src/host/layer23/src/mobile/vty_interface.c b/src/host/layer23/src/mobile/vty_interface.c index 366094f7..eda2d81f 100644 --- a/src/host/layer23/src/mobile/vty_interface.c +++ b/src/host/layer23/src/mobile/vty_interface.c @@ -756,6 +756,7 @@ DEFUN(cfg_ms, cfg_ms_cmd, "ms MS_NAME", static void config_write_ms_single(struct vty *vty, struct osmocom_ms *ms) { + struct gsm_support *sup = &ms->support; struct gsm_settings *set = &ms->settings; vty_out(vty, "ms %s%s", ms->name, VTY_NEWLINE); @@ -833,6 +834,20 @@ static void config_write_ms_single(struct vty *vty, struct osmocom_ms *ms) vty_out(vty, " no location-updating%s", VTY_NEWLINE); else vty_out(vty, " location-updating%s", VTY_NEWLINE); + if (sup->full_v1 || sup->full_v2 || sup->full_v3) { + /* mandatory anyway */ + vty_out(vty, " codec full-speed%s%s", + (!set->half_prefer) ? " prefer" : "", + VTY_NEWLINE); + } + if (sup->half_v1 || sup->half_v3) { + if (set->half) + vty_out(vty, " codec half-speed%s%s", + (set->half_prefer) ? " prefer" : "", + VTY_NEWLINE); + else + vty_out(vty, " no codec half-speed%s", VTY_NEWLINE); + } vty_out(vty, "exit%s", VTY_NEWLINE); vty_out(vty, "!%s", VTY_NEWLINE); } @@ -1130,6 +1145,88 @@ DEFUN(cfg_ms_no_lupd, cfg_ms_no_lupd_cmd, "no location-updating", return CMD_SUCCESS; } +DEFUN(cfg_codec_full, cfg_ms_codec_full_cmd, "codec full-speed", + "Enable codec\nFull speed speech codec") +{ + struct osmocom_ms *ms = vty->index; + struct gsm_support *sup = &ms->support; + + if (!sup->full_v1 && !sup->full_v2 && !sup->full_v3) { + vty_out(vty, "Full-rate codec not supported%s", VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +DEFUN(cfg_codec_full_pref, cfg_ms_codec_full_pref_cmd, "codec full-speed " + "prefer", + "Enable codec\nFull speed speech codec\nPrefer this codec") +{ + struct osmocom_ms *ms = vty->index; + struct gsm_support *sup = &ms->support; + + if (!sup->full_v1 && !sup->full_v2 && !sup->full_v3) { + vty_out(vty, "Full-rate codec not supported%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ms->settings.half_prefer = 0; + + return CMD_SUCCESS; +} + +DEFUN(cfg_codec_half, cfg_ms_codec_half_cmd, "codec half-speed", + "Enable codec\nHalf speed speech codec") +{ + struct osmocom_ms *ms = vty->index; + struct gsm_support *sup = &ms->support; + + if (!sup->half_v1 && !sup->half_v3) { + vty_out(vty, "Half-rate codec not supported%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ms->settings.half = 1; + + return CMD_SUCCESS; +} + +DEFUN(cfg_codec_half_pref, cfg_ms_codec_half_pref_cmd, "codec half-speed " + "prefer", + "Enable codec\nHalf speed speech codec\nPrefer this codec") +{ + struct osmocom_ms *ms = vty->index; + struct gsm_support *sup = &ms->support; + + if (!sup->half_v1 && !sup->half_v3) { + vty_out(vty, "Half-rate codec not supported%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ms->settings.half = 1; + ms->settings.half_prefer = 1; + + return CMD_SUCCESS; +} + +DEFUN(cfg_no_codec_half, cfg_ms_no_codec_half_cmd, "no codec half-speed", + NO_STR "Disable codec\nHalf speed speech codec") +{ + struct osmocom_ms *ms = vty->index; + struct gsm_support *sup = &ms->support; + + if (!sup->half_v1 && !sup->half_v3) { + vty_out(vty, "Half-rate codec not supported%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ms->settings.half = 0; + ms->settings.half_prefer = 0; + + return CMD_SUCCESS; +} + /* per testsim config */ DEFUN(cfg_ms_testsim, cfg_ms_testsim_cmd, "test-sim", "Configure test SIM emulation") @@ -1409,7 +1506,11 @@ int ms_vty_init(void) install_element(MS_NODE, &cfg_ms_no_stick_cmd); install_element(MS_NODE, &cfg_ms_lupd_cmd); install_element(MS_NODE, &cfg_ms_no_lupd_cmd); - + install_element(MS_NODE, &cfg_ms_codec_full_cmd); + install_element(MS_NODE, &cfg_ms_codec_full_pref_cmd); + install_element(MS_NODE, &cfg_ms_codec_half_cmd); + install_element(MS_NODE, &cfg_ms_codec_half_pref_cmd); + install_element(MS_NODE, &cfg_ms_no_codec_half_cmd); install_node(&testsim_node, config_write_dummy); install_default(TESTSIM_NODE); install_element(TESTSIM_NODE, &ournode_exit_cmd); |