X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=src%2Fhost%2Flayer23%2Fsrc%2Fmobile%2Fvty_interface.c;h=567d8eb0d9f3410193382b8f31b60df08a5c87cc;hb=072c2d46412b37eb99f0a1a856ebd4ef2c0beafc;hp=e3d34fe0c3b13fdfb45798b124256c803e4bcd5f;hpb=6d4915b91b13fa879e0dd75d2c275e82b5a5634c;p=osmocom-bb.git diff --git a/src/host/layer23/src/mobile/vty_interface.c b/src/host/layer23/src/mobile/vty_interface.c index e3d34fe..567d8eb 100644 --- a/src/host/layer23/src/mobile/vty_interface.c +++ b/src/host/layer23/src/mobile/vty_interface.c @@ -25,22 +25,28 @@ #include #include -#include -#include +#include +#include +#include +#include #include #include +#include #include #include #include -#include +#include #include +void *l23_ctx; + int mncc_call(struct osmocom_ms *ms, char *number); int mncc_hangup(struct osmocom_ms *ms); int mncc_answer(struct osmocom_ms *ms); int mncc_hold(struct osmocom_ms *ms); int mncc_retrieve(struct osmocom_ms *ms, int number); +int mncc_dtmf(struct osmocom_ms *ms, char *dtmf); extern struct llist_head ms_list; extern struct llist_head active_connections; @@ -83,14 +89,42 @@ static void print_vty(void *priv, const char *fmt, ...) } } +int vty_check_number(struct vty *vty, const char *number) +{ + int i; + + for (i = 0; i < strlen(number); i++) { + /* allow international notation with + */ + if (i == 0 && number[i] == '+') + continue; + if (!(number[i] >= '0' && number[i] <= '9') + && number[i] != '*' + && number[i] != '#' + && !(number[i] >= 'a' && number[i] <= 'c')) { + vty_out(vty, "Invalid digit '%c' of number!%s", + number[i], VTY_NEWLINE); + return -EINVAL; + } + } + if (number[0] == '\0' || (number[0] == '+' && number[1] == '\0')) { + vty_out(vty, "Given number has no digits!%s", VTY_NEWLINE); + return -EINVAL; + } + + return 0; +} + int vty_reading = 0; +static int hide_default = 0; -static void vty_restart(struct vty *vty) +static void vty_restart(struct vty *vty, struct osmocom_ms *ms) { if (vty_reading) return; - vty_out(vty, "You must restart for change to take effect!%s", - VTY_NEWLINE); + if (ms->shutdown != 0) + return; + vty_out(vty, "You must restart MS '%s' ('shutdown / no shutdown') for " + "change to take effect!%s", ms->name, VTY_NEWLINE); } static struct osmocom_ms *get_ms(const char *name, struct vty *vty) @@ -98,89 +132,123 @@ static struct osmocom_ms *get_ms(const char *name, struct vty *vty) struct osmocom_ms *ms; llist_for_each_entry(ms, &ms_list, entity) { - if (!strcmp(ms->name, name)) + if (!strcmp(ms->name, name)) { + if (ms->shutdown) { + vty_out(vty, "MS '%s' is admin down.%s", name, + VTY_NEWLINE); + return NULL; + } return ms; + } } vty_out(vty, "MS name '%s' does not exits.%s", name, VTY_NEWLINE); return NULL; } -DEFUN(show_ms, show_ms_cmd, "show ms", - SHOW_STR "Display available MS entities\n") +static void gsm_ms_dump(struct osmocom_ms *ms, struct vty *vty) { - struct osmocom_ms *ms; - - llist_for_each_entry(ms, &ms_list, entity) { - struct gsm_settings *set = &ms->settings; - - vty_out(vty, "MS NAME: %s%s", ms->name, VTY_NEWLINE); - vty_out(vty, " IMEI: %s%s", set->imei, VTY_NEWLINE); - vty_out(vty, " IMEISV: %s%s", set->imeisv, VTY_NEWLINE); - if (set->imei_random) - vty_out(vty, " IMEI generation: random (%d trailing " - "digits)%s", set->imei_random, VTY_NEWLINE); - else - vty_out(vty, " IMEI generation: fixed%s", VTY_NEWLINE); - vty_out(vty, " network selection mode: %s%s", - (set->plmn_mode == PLMN_MODE_AUTO) - ? "automatic" : "manual", VTY_NEWLINE); - } - - return CMD_SUCCESS; -} - -DEFUN(show_support, show_support_cmd, "show support [ms_name]", - SHOW_STR "Display information about MS support\n" - "Name of MS (see \"show ms\")") -{ - struct osmocom_ms *ms; - - if (argc) { - ms = get_ms(argv[0], vty); - if (!ms) - return CMD_WARNING; - gsm_support_dump(ms, print_vty, vty); - } else { - llist_for_each_entry(ms, &ms_list, entity) { - gsm_support_dump(ms, print_vty, vty); - vty_out(vty, "%s", VTY_NEWLINE); + struct gsm_settings *set = &ms->settings; + struct gsm_trans *trans; + char *service = ""; + + if (!ms->started) + service = ", radio is not started"; + else if (ms->mmlayer.state == GSM48_MM_ST_MM_IDLE) { + /* current MM idle state */ + switch (ms->mmlayer.substate) { + case GSM48_MM_SST_NORMAL_SERVICE: + case GSM48_MM_SST_PLMN_SEARCH_NORMAL: + service = ", service is normal"; + break; + case GSM48_MM_SST_LOC_UPD_NEEDED: + case GSM48_MM_SST_ATTEMPT_UPDATE: + service = ", service is limited (pending)"; + break; + case GSM48_MM_SST_NO_CELL_AVAIL: + service = ", service is unavailable"; + break; + default: + if (ms->subscr.sim_valid) + service = ", service is limited"; + else + service = ", service is limited " + "(IMSI detached)"; + break; } - } + } else + service = ", MM connection active"; - return CMD_SUCCESS; -} + vty_out(vty, "MS '%s' is %s%s%s%s", ms->name, + (ms->shutdown) ? "administratively " : "", + (ms->shutdown || !ms->started) ? "down" : "up", + (!ms->shutdown) ? service : "", + VTY_NEWLINE); + vty_out(vty, " IMEI: %s%s", set->imei, VTY_NEWLINE); + vty_out(vty, " IMEISV: %s%s", set->imeisv, VTY_NEWLINE); + if (set->imei_random) + vty_out(vty, " IMEI generation: random (%d trailing " + "digits)%s", set->imei_random, VTY_NEWLINE); + else + vty_out(vty, " IMEI generation: fixed%s", VTY_NEWLINE); -static void gsm_states_dump(struct osmocom_ms *ms, struct vty *vty) -{ - struct gsm_settings *set = &ms->settings; - struct gsm_trans *trans; + if (ms->shutdown) + return; - vty_out(vty, "Current state of MS '%s'%s", ms->name, VTY_NEWLINE); if (set->plmn_mode == PLMN_MODE_AUTO) - vty_out(vty, " automatic network selection: %s%s", + vty_out(vty, " automatic network selection state: %s%s", plmn_a_state_names[ms->plmn.state], VTY_NEWLINE); else - vty_out(vty, " manual network selection: %s%s", + vty_out(vty, " manual network selection state: %s%s", plmn_m_state_names[ms->plmn.state], VTY_NEWLINE); - vty_out(vty, " cell selection: %s%s", - cs_state_names[ms->cellsel.state], VTY_NEWLINE); - vty_out(vty, " radio ressource layer: %s%s", + vty_out(vty, " cell selection state: %s", + cs_state_names[ms->cellsel.state]); + if (ms->rrlayer.state == GSM48_RR_ST_IDLE && ms->cellsel.selected) + vty_out(vty, " (ARFCN %s)", + gsm_print_arfcn(ms->cellsel.sel_arfcn)); + vty_out(vty, "%s", VTY_NEWLINE); + vty_out(vty, " radio ressource layer state: %s%s", gsm48_rr_state_names[ms->rrlayer.state], VTY_NEWLINE); - vty_out(vty, " mobility management layer: %s", + vty_out(vty, " mobility management layer state: %s", gsm48_mm_state_names[ms->mmlayer.state]); if (ms->mmlayer.state == GSM48_MM_ST_MM_IDLE) vty_out(vty, ", %s", gsm48_mm_substate_names[ms->mmlayer.substate]); vty_out(vty, "%s", VTY_NEWLINE); llist_for_each_entry(trans, &ms->trans_list, entry) { - vty_out(vty, " call control: %s%s", + vty_out(vty, " call control state: %s%s", gsm48_cc_state_name(trans->cc.state), VTY_NEWLINE); } } -DEFUN(show_states, show_states_cmd, "show states [ms_name]", - SHOW_STR "Display current states of given MS\n" + +DEFUN(show_ms, show_ms_cmd, "show ms [MS_NAME]", + SHOW_STR "Display available MS entities\n") +{ + struct osmocom_ms *ms; + + if (argc) { + llist_for_each_entry(ms, &ms_list, entity) { + if (!strcmp(ms->name, argv[0])) { + gsm_ms_dump(ms, vty); + return CMD_SUCCESS; + } + } + vty_out(vty, "MS name '%s' does not exits.%s", argv[0], + VTY_NEWLINE); + return CMD_WARNING; + } else { + llist_for_each_entry(ms, &ms_list, entity) { + gsm_ms_dump(ms, vty); + vty_out(vty, "%s", VTY_NEWLINE); + } + } + + return CMD_SUCCESS; +} + +DEFUN(show_support, show_support_cmd, "show support [MS_NAME]", + SHOW_STR "Display information about MS support\n" "Name of MS (see \"show ms\")") { struct osmocom_ms *ms; @@ -189,10 +257,10 @@ DEFUN(show_states, show_states_cmd, "show states [ms_name]", ms = get_ms(argv[0], vty); if (!ms) return CMD_WARNING; - gsm_states_dump(ms, vty); + gsm_support_dump(ms, print_vty, vty); } else { llist_for_each_entry(ms, &ms_list, entity) { - gsm_states_dump(ms, vty); + gsm_support_dump(ms, print_vty, vty); vty_out(vty, "%s", VTY_NEWLINE); } } @@ -200,7 +268,7 @@ DEFUN(show_states, show_states_cmd, "show states [ms_name]", return CMD_SUCCESS; } -DEFUN(show_subscr, show_subscr_cmd, "show subscriber [ms_name]", +DEFUN(show_subscr, show_subscr_cmd, "show subscriber [MS_NAME]", SHOW_STR "Display information about subscriber\n" "Name of MS (see \"show ms\")") { @@ -213,8 +281,10 @@ DEFUN(show_subscr, show_subscr_cmd, "show subscriber [ms_name]", gsm_subscr_dump(&ms->subscr, print_vty, vty); } else { llist_for_each_entry(ms, &ms_list, entity) { - gsm_subscr_dump(&ms->subscr, print_vty, vty); - vty_out(vty, "%s", VTY_NEWLINE); + if (!ms->shutdown) { + gsm_subscr_dump(&ms->subscr, print_vty, vty); + vty_out(vty, "%s", VTY_NEWLINE); + } } } @@ -237,37 +307,41 @@ DEFUN(show_cell, show_cell_cmd, "show cell MS_NAME", return CMD_SUCCESS; } -DEFUN(show_cell_si, show_cell_si_cmd, "show cell MS_NAME <0-1023>", +DEFUN(show_cell_si, show_cell_si_cmd, "show cell MS_NAME <0-1023> [pcs]", SHOW_STR "Display information about received cell\n" - "Name of MS (see \"show ms\")\nRadio frequency number") + "Name of MS (see \"show ms\")\nRadio frequency number\n" + "Given frequency is PCS band (1900) rather than DCS band.") { struct osmocom_ms *ms; - int i; struct gsm48_sysinfo *s; + uint16_t arfcn = atoi(argv[1]); ms = get_ms(argv[0], vty); if (!ms) return CMD_WARNING; - i = atoi(argv[1]); - if (i < 0 || i > 1023) { - vty_out(vty, "Given ARFCN '%s' not in range (0..1023)%s", - argv[1], VTY_NEWLINE); - return CMD_WARNING; + if (argc > 2) { + if (arfcn < 512 || arfcn > 810) { + vty_out(vty, "Given ARFCN not in PCS band%s", + VTY_NEWLINE); + return CMD_WARNING; + } + arfcn |= ARFCN_PCS; } - s = ms->cellsel.list[i].sysinfo; + + s = ms->cellsel.list[arfcn2index(arfcn)].sysinfo; if (!s) { vty_out(vty, "Given ARFCN '%s' has no sysinfo available%s", argv[1], VTY_NEWLINE); return CMD_SUCCESS; } - gsm48_sysinfo_dump(s, i, print_vty, vty); + gsm48_sysinfo_dump(s, arfcn, print_vty, vty, ms->settings.freq_map); return CMD_SUCCESS; } -DEFUN(show_ba, show_ba_cmd, "show ba MS_NAME [mcc] [mnc]", +DEFUN(show_ba, show_ba_cmd, "show ba MS_NAME [MCC] [MNC]", SHOW_STR "Display information about band allocations\n" "Name of MS (see \"show ms\")\nMobile Country Code\n" "Mobile Network Code") @@ -356,12 +430,14 @@ DEFUN(no_monitor_network, no_monitor_network_cmd, "no monitor network MS_NAME", return CMD_SUCCESS; } -DEFUN(sim_test, sim_test_cmd, "sim testcard MS_NAME [mcc] [mnc]", +DEFUN(sim_test, sim_test_cmd, "sim testcard MS_NAME [MCC] [MNC] [LAC] [TMSI]", "SIM actions\nInsert test card\nName of MS (see \"show ms\")\n" - "Mobile Country Code of RPLMN\nMobile Network Code of RPLMN") + "Mobile Country Code of RPLMN\nMobile Network Code of RPLMN\n" + "Optionally locatio area code\nOptionally current assigned TMSI") { struct osmocom_ms *ms; - uint16_t mcc = 0x001, mnc = 0x01f; + uint16_t mcc = 0x001, mnc = 0x01f, lac = 0x0000; + uint32_t tmsi = 0xffffffff; ms = get_ms(argv[0], vty); if (!ms) @@ -386,7 +462,13 @@ DEFUN(sim_test, sim_test_cmd, "sim testcard MS_NAME [mcc] [mnc]", } } - gsm_subscr_testcard(ms, mcc, mnc); + if (argc >= 4) + lac = strtoul(argv[3], NULL, 16); + + if (argc >= 5) + tmsi = strtoul(argv[4], NULL, 16); + + gsm_subscr_testcard(ms, mcc, mnc, lac, tmsi); return CMD_SUCCESS; } @@ -629,45 +711,48 @@ DEFUN(call, call_cmd, "call MS_NAME (NUMBER|emergency|answer|hangup|hold)", "Hold current active call\n") { struct osmocom_ms *ms; - int i; + struct gsm_settings *set; + struct gsm_settings_abbrev *abbrev; + char *number; ms = get_ms(argv[0], vty); if (!ms) return CMD_WARNING; + set = &ms->settings; - if (!strcmp(argv[1], "emergency")) - mncc_call(ms, (char *)argv[1]); - else switch (argv[1][0]) { - case 'a': + if (set->ch_cap == GSM_CAP_SDCCH) { + vty_out(vty, "Basic call is not supported for SDCCH only " + "mobile%s", VTY_NEWLINE); + return CMD_WARNING; + } + + number = (char *)argv[1]; + if (!strcmp(number, "emergency")) + mncc_call(ms, number); + else if (!strcmp(number, "answer")) mncc_answer(ms); - break; - case 'h': - if (argv[1][1] == 'a') - mncc_hangup(ms); - else - mncc_hold(ms); - break; - default: - for (i = 0; i < strlen(argv[1]); i++) { - /* allow international notation with + */ - if (i == 0 && argv[1][i] == '+') - continue; - if (!(argv[1][i] >= '0' && argv[1][i] <= '9') - && argv[1][i] != '*' - && argv[1][i] != '#' - && !(argv[1][i] >= 'a' && argv[1][i] <= 'c')) { - vty_out(vty, "Invalid digit '%c'%s", argv[1][i], + else if (!strcmp(number, "hangup")) + mncc_hangup(ms); + else if (!strcmp(number, "hold")) + mncc_hold(ms); + else { + llist_for_each_entry(abbrev, &set->abbrev, list) { + if (!strcmp(number, abbrev->abbrev)) { + number = abbrev->number; + vty_out(vty, "Dialing number '%s'%s", number, VTY_NEWLINE); - return CMD_WARNING; + break; } } - mncc_call(ms, (char *)argv[1]); + if (vty_check_number(vty, number)) + return CMD_WARNING; + mncc_call(ms, number); } return CMD_SUCCESS; } -DEFUN(call_retr, call_retr_cmd, "call MS_NAME retrieve [number]", +DEFUN(call_retr, call_retr_cmd, "call MS_NAME retrieve [NUMBER]", "Make a call\nName of MS (see \"show ms\")\n" "Retrieve call on hold\nNumber of call to retrieve") { @@ -682,6 +767,29 @@ DEFUN(call_retr, call_retr_cmd, "call MS_NAME retrieve [number]", return CMD_SUCCESS; } +DEFUN(call_dtmf, call_dtmf_cmd, "call MS_NAME dtmf DIGITS", + "Make a call\nName of MS (see \"show ms\")\n" + "One or more DTMF digits to transmit") +{ + struct osmocom_ms *ms; + struct gsm_settings *set; + + ms = get_ms(argv[0], vty); + if (!ms) + return CMD_WARNING; + set = &ms->settings; + + if (!set->cc_dtmf) { + vty_out(vty, "DTMF not supported, please enable!%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + mncc_dtmf(ms, (char *)argv[1]); + + return CMD_SUCCESS; +} + DEFUN(network_show, network_show_cmd, "network show MS_NAME", "Network ...\nShow results of network search (again)\n" "Name of MS (see \"show ms\")") @@ -733,12 +841,12 @@ DEFUN(network_search, network_search_cmd, "network search MS_NAME", DEFUN(cfg_gps_enable, cfg_gps_enable_cmd, "gps enable", "GPS receiver") { - if (gps_open()) { - gps.enable = 1; + if (osmo_gps_open()) { + g.enable = 1; vty_out(vty, "Failed to open GPS device!%s", VTY_NEWLINE); return CMD_WARNING; } - gps.enable = 1; + g.enable = 1; return CMD_SUCCESS; } @@ -746,22 +854,54 @@ DEFUN(cfg_gps_enable, cfg_gps_enable_cmd, "gps enable", DEFUN(cfg_no_gps_enable, cfg_no_gps_enable_cmd, "no gps enable", NO_STR "Disable GPS receiver") { - if (gps.enable) - gps_close(); - gps.enable = 0; + if (g.enable) + osmo_gps_close(); + g.enable = 0; return CMD_SUCCESS; } +#ifdef _HAVE_GPSD +DEFUN(cfg_gps_host, cfg_gps_host_cmd, "gps host HOST:PORT", + "GPS receiver\nSelect gpsd host and port\n" + "IP and port (optional) of the host running gpsd") +{ + char* colon = strstr(argv[0], ":"); + if (colon != NULL) { + memcpy(g.gpsd_host, argv[0], colon - argv[0] - 1); + g.gpsd_host[colon - argv[0]] = '\0'; + memcpy(g.gpsd_port, colon, strlen(colon)); + g.gpsd_port[strlen(colon)] = '\0'; + } else { + snprintf(g.gpsd_host, ARRAY_SIZE(g.gpsd_host), "%s", argv[0]); + g.gpsd_host[ARRAY_SIZE(g.gpsd_host) - 1] = '\0'; + snprintf(g.gpsd_port, ARRAY_SIZE(g.gpsd_port), "2947"); + g.gpsd_port[ARRAY_SIZE(g.gpsd_port) - 1] = '\0'; + } + g.gps_type = GPS_TYPE_GPSD; + if (g.enable) { + osmo_gps_close(); + if (osmo_gps_open()) { + vty_out(vty, "Failed to connect to gpsd host!%s", + VTY_NEWLINE); + return CMD_WARNING; + } + } + + return CMD_SUCCESS; +} +#endif + DEFUN(cfg_gps_device, cfg_gps_device_cmd, "gps device DEVICE", "GPS receiver\nSelect serial device\n" "Full path of serial device including /dev/") { - strncpy(gps.device, argv[0], sizeof(gps.device)); - gps.device[sizeof(gps.device) - 1] = '\0'; - if (gps.enable) { - gps_close(); - if (gps_open()) { + strncpy(g.device, argv[0], sizeof(g.device)); + g.device[sizeof(g.device) - 1] = '\0'; + g.gps_type = GPS_TYPE_SERIAL; + if (g.enable) { + osmo_gps_close(); + if (osmo_gps_open()) { vty_out(vty, "Failed to open GPS device!%s", VTY_NEWLINE); return CMD_WARNING; @@ -776,13 +916,13 @@ DEFUN(cfg_gps_baud, cfg_gps_baud_cmd, "gps baudrate " "GPS receiver\nSelect baud rate\nDefault, don't modify\n\n\n\n\n\n") { if (argv[0][0] == 'd') - gps.baud = 0; + g.baud = 0; else - gps.baud = atoi(argv[0]); - if (gps.enable) { - gps_close(); - if (gps_open()) { - gps.enable = 0; + g.baud = atoi(argv[0]); + if (g.enable) { + osmo_gps_close(); + if (osmo_gps_open()) { + g.enable = 0; vty_out(vty, "Failed to open GPS device!%s", VTY_NEWLINE); return CMD_WARNING; @@ -792,33 +932,154 @@ DEFUN(cfg_gps_baud, cfg_gps_baud_cmd, "gps baudrate " return CMD_SUCCESS; } +DEFUN(cfg_hide_default, cfg_hide_default_cmd, "hide-default", + "Hide most default values in config to make it more compact") +{ + hide_default = 1; + + return CMD_SUCCESS; +} + +DEFUN(cfg_no_hide_default, cfg_no_hide_default_cmd, "no hide-default", + NO_STR "Show default values in config") +{ + hide_default = 0; + + return CMD_SUCCESS; +} + /* per MS config */ DEFUN(cfg_ms, cfg_ms_cmd, "ms MS_NAME", "Select a mobile station to configure\nName of MS (see \"show ms\")") { struct osmocom_ms *ms; + int found = 0; - ms = get_ms(argv[0], vty); - if (!ms) - return CMD_WARNING; + llist_for_each_entry(ms, &ms_list, entity) { + if (!strcmp(ms->name, argv[0])) { + found = 1; + break; + } + } + + if (!found) { + if (!vty_reading) { + vty_out(vty, "MS name '%s' does not exits, try " + "'ms %s create'%s", argv[0], argv[0], + VTY_NEWLINE); + return CMD_WARNING; + } + ms = mobile_new((char *)argv[0]); + if (!ms) { + vty_out(vty, "Failed to add MS name '%s'%s", argv[0], + VTY_NEWLINE); + return CMD_WARNING; + } + } + + vty->index = ms; + vty->node = MS_NODE; + + return CMD_SUCCESS; +} + +DEFUN(cfg_ms_create, cfg_ms_create_cmd, "ms MS_NAME create", + "Select a mobile station to configure\nName of MS (see \"show ms\")\n" + "Create if MS does not exists") +{ + struct osmocom_ms *ms; + int found = 0; + + llist_for_each_entry(ms, &ms_list, entity) { + if (!strcmp(ms->name, argv[0])) { + found = 1; + break; + } + } + + if (!found) { + ms = mobile_new((char *)argv[0]); + if (!ms) { + vty_out(vty, "Failed to add MS name '%s'%s", argv[0], + VTY_NEWLINE); + return CMD_WARNING; + } + } vty->index = ms; vty->node = MS_NODE; + vty_out(vty, "MS '%s' created, after configuration, do 'no shutdown'%s", + argv[0], VTY_NEWLINE); + return CMD_SUCCESS; +} + +DEFUN(cfg_ms_rename, cfg_ms_rename_cmd, "ms MS_NAME rename MS_NAME", + "Select a mobile station to configure\nName of MS (see \"show ms\")\n" + "Rename MS\nNew name of MS") +{ + struct osmocom_ms *ms; + int found = 0; + + llist_for_each_entry(ms, &ms_list, entity) { + if (!strcmp(ms->name, argv[0])) { + found = 1; + break; + } + } + + if (!found) { + vty_out(vty, "MS name '%s' does not exist%s", argv[0], + VTY_NEWLINE); + return CMD_WARNING; + } + + strncpy(ms->name, argv[1], sizeof(ms->name) - 1); + + return CMD_SUCCESS; +} + +DEFUN(cfg_no_ms, cfg_no_ms_cmd, "no ms MS_NAME", + NO_STR "Select a mobile station to remove\n" + "Name of MS (see \"show ms\")") +{ + struct osmocom_ms *ms; + int found = 0; + + llist_for_each_entry(ms, &ms_list, entity) { + if (!strcmp(ms->name, argv[0])) { + found = 1; + break; + } + } + + if (!found) { + vty_out(vty, "MS name '%s' does not exist%s", argv[0], + VTY_NEWLINE); + return CMD_WARNING; + } + + mobile_delete(ms, 1); + return CMD_SUCCESS; } #define SUP_WRITE(item, cmd) \ if (sup->item) \ - vty_out(vty, " %s%s%s", (set->item) ? "" : "no ", cmd, \ - VTY_NEWLINE); + if (!hide_default || !set->item) \ + vty_out(vty, " %s%s%s", (set->item) ? "" : "no ", \ + cmd, VTY_NEWLINE); -static void config_write_ms_single(struct vty *vty, struct osmocom_ms *ms) +static void config_write_ms(struct vty *vty, struct osmocom_ms *ms) { struct gsm_settings *set = &ms->settings; struct gsm_support *sup = &ms->support; + struct gsm_settings_abbrev *abbrev; vty_out(vty, "ms %s%s", ms->name, VTY_NEWLINE); + vty_out(vty, " layer2-socket %s%s", set->layer2_socket_path, + VTY_NEWLINE); + vty_out(vty, " sap-socket %s%s", set->sap_socket_path, VTY_NEWLINE); switch(set->sim_type) { case GSM_SIM_TYPE_NONE: vty_out(vty, " sim none%s", VTY_NEWLINE); @@ -838,15 +1099,26 @@ static void config_write_ms_single(struct vty *vty, struct osmocom_ms *ms) vty_out(vty, " imei-random %d%s", set->imei_random, VTY_NEWLINE); else - vty_out(vty, " imei-fixed%s", VTY_NEWLINE); + if (!hide_default) + vty_out(vty, " imei-fixed%s", VTY_NEWLINE); if (set->emergency_imsi[0]) vty_out(vty, " emergency-imsi %s%s", set->emergency_imsi, VTY_NEWLINE); else - vty_out(vty, " no emergency-imsi%s", VTY_NEWLINE); - vty_out(vty, " %scall-waiting%s", (set->cw) ? "" : "no ", VTY_NEWLINE); - vty_out(vty, " %sclip%s", (set->clip) ? "" : "no ", VTY_NEWLINE); - vty_out(vty, " %sclir%s", (set->clir) ? "" : "no ", VTY_NEWLINE); + if (!hide_default) + vty_out(vty, " no emergency-imsi%s", VTY_NEWLINE); + if (!hide_default || set->cw) + vty_out(vty, " %scall-waiting%s", (set->cw) ? "" : "no ", + VTY_NEWLINE); + if (!hide_default || set->auto_answer) + vty_out(vty, " %sauto-answer%s", + (set->auto_answer) ? "" : "no ", VTY_NEWLINE); + if (!hide_default || set->clip) + vty_out(vty, " %sclip%s", (set->clip) ? "" : "no ", + VTY_NEWLINE); + if (!hide_default || set->clir) + vty_out(vty, " %sclir%s", (set->clir) ? "" : "no ", + VTY_NEWLINE); if (set->alter_tx_power) if (set->alter_tx_power_value) vty_out(vty, " tx-power %d%s", @@ -854,21 +1126,24 @@ static void config_write_ms_single(struct vty *vty, struct osmocom_ms *ms) else vty_out(vty, " tx-power full%s", VTY_NEWLINE); else - vty_out(vty, " tx-power auto%s", VTY_NEWLINE); + if (!hide_default) + vty_out(vty, " tx-power auto%s", VTY_NEWLINE); if (set->alter_delay) vty_out(vty, " simulated-delay %d%s", set->alter_delay, VTY_NEWLINE); else - vty_out(vty, " no simulated-delay%s", VTY_NEWLINE); + if (!hide_default) + vty_out(vty, " no simulated-delay%s", VTY_NEWLINE); if (set->stick) - vty_out(vty, " stick %d%s", set->stick_arfcn, + vty_out(vty, " stick %d%s%s", set->stick_arfcn & 1023, + (set->stick_arfcn & ARFCN_PCS) ? " pcs" : "", VTY_NEWLINE); else - vty_out(vty, " no stick%s", VTY_NEWLINE); - if (set->no_lupd) - vty_out(vty, " no location-updating%s", VTY_NEWLINE); - else - vty_out(vty, " location-updating%s", VTY_NEWLINE); + if (!hide_default) + vty_out(vty, " no stick%s", VTY_NEWLINE); + if (!hide_default || set->no_lupd) + vty_out(vty, " %slocation-updating%s", + (set->no_lupd) ? "no " : "", VTY_NEWLINE); if (set->full_v1 || set->full_v2 || set->full_v3) { /* mandatory anyway */ vty_out(vty, " codec full-speed%s%s", @@ -883,6 +1158,15 @@ static void config_write_ms_single(struct vty *vty, struct osmocom_ms *ms) else vty_out(vty, " no codec half-speed%s", VTY_NEWLINE); } + if (llist_empty(&set->abbrev)) { + if (!hide_default) + vty_out(vty, " no abbrev%s", VTY_NEWLINE); + } else { + llist_for_each_entry(abbrev, &set->abbrev, list) + vty_out(vty, " abbrev %s %s%s%s%s", abbrev->abbrev, + abbrev->number, (abbrev->name[0]) ? " " : "", + abbrev->name, VTY_NEWLINE); + } vty_out(vty, " support%s", VTY_NEWLINE); SUP_WRITE(sms_ptp, "sms"); SUP_WRITE(a5_1, "a5/1"); @@ -895,75 +1179,161 @@ static void config_write_ms_single(struct vty *vty, struct osmocom_ms *ms) SUP_WRITE(p_gsm, "p-gsm"); SUP_WRITE(e_gsm, "e-gsm"); SUP_WRITE(r_gsm, "r-gsm"); + SUP_WRITE(pcs, "gsm-850"); + SUP_WRITE(gsm_480, "gsm-480"); + SUP_WRITE(gsm_450, "gsm-450"); SUP_WRITE(dcs, "dcs"); - vty_out(vty, " class-900 %d%s", set->class_900, VTY_NEWLINE); - vty_out(vty, " class-dcs %d%s", set->class_dcs, VTY_NEWLINE); - switch (set->ch_cap) { - case GSM_CAP_SDCCH: - vty_out(vty, " channel-capability sdcch%s", VTY_NEWLINE); - break; - case GSM_CAP_SDCCH_TCHF: - vty_out(vty, " channel-capability sdcch+tchf%s", VTY_NEWLINE); - break; - case GSM_CAP_SDCCH_TCHF_TCHH: - vty_out(vty, " channel-capability sdcch+tchf+tchh%s", - VTY_NEWLINE); - break; + SUP_WRITE(pcs, "pcs"); + if (sup->r_gsm || sup->e_gsm || sup->p_gsm) + if (!hide_default || sup->class_900 != set->class_900) + vty_out(vty, " class-900 %d%s", set->class_900, + VTY_NEWLINE); + if (sup->gsm_850) + if (!hide_default || sup->class_850 != set->class_850) + vty_out(vty, " class-850 %d%s", set->class_850, + VTY_NEWLINE); + if (sup->gsm_480 || sup->gsm_450) + if (!hide_default || sup->class_400 != set->class_400) + vty_out(vty, " class-400 %d%s", set->class_400, + VTY_NEWLINE); + if (sup->dcs) + if (!hide_default || sup->class_dcs != set->class_dcs) + vty_out(vty, " class-dcs %d%s", set->class_dcs, + VTY_NEWLINE); + if (sup->pcs) + if (!hide_default || sup->class_pcs != set->class_pcs) + vty_out(vty, " class-pcs %d%s", set->class_pcs, + VTY_NEWLINE); + if (!hide_default || sup->ch_cap != set->ch_cap) { + switch (set->ch_cap) { + case GSM_CAP_SDCCH: + vty_out(vty, " channel-capability sdcch%s", + VTY_NEWLINE); + break; + case GSM_CAP_SDCCH_TCHF: + vty_out(vty, " channel-capability sdcch+tchf%s", + VTY_NEWLINE); + break; + case GSM_CAP_SDCCH_TCHF_TCHH: + vty_out(vty, " channel-capability sdcch+tchf+tchh%s", + VTY_NEWLINE); + break; + } } SUP_WRITE(full_v1, "full-speech-v1"); SUP_WRITE(full_v2, "full-speech-v2"); SUP_WRITE(full_v3, "full-speech-v3"); SUP_WRITE(half_v1, "half-speech-v1"); SUP_WRITE(half_v3, "half-speech-v3"); - vty_out(vty, " min-rxlev %d%s", set->min_rxlev_db, VTY_NEWLINE); - vty_out(vty, " dsc-max %d%s", set->dsc_max, VTY_NEWLINE); + if (!hide_default || sup->min_rxlev_db != set->min_rxlev_db) + vty_out(vty, " min-rxlev %d%s", set->min_rxlev_db, + VTY_NEWLINE); + if (!hide_default || sup->dsc_max != set->dsc_max) + vty_out(vty, " dsc-max %d%s", set->dsc_max, VTY_NEWLINE); vty_out(vty, " exit%s", VTY_NEWLINE); vty_out(vty, " test-sim%s", VTY_NEWLINE); vty_out(vty, " imsi %s%s", set->test_imsi, VTY_NEWLINE); switch (set->test_ki_type) { case GSM_SIM_KEY_XOR: - vty_out(vty, " ki xor %s%s", hexdump(set->test_ki, 12), - VTY_NEWLINE); + vty_out(vty, " ki xor %s%s", + osmo_hexdump(set->test_ki, 12), VTY_NEWLINE); break; case GSM_SIM_KEY_COMP128: - vty_out(vty, " ki comp128 %s%s", hexdump(set->test_ki, 16), - VTY_NEWLINE); + vty_out(vty, " ki comp128 %s%s", + osmo_hexdump(set->test_ki, 16), VTY_NEWLINE); break; } - vty_out(vty, " %sbarred-access%s", (set->test_barr) ? "" : "no ", - VTY_NEWLINE); - if (set->test_rplmn_valid) - vty_out(vty, " rplmn %s %s%s", + if (!hide_default || set->test_barr) + vty_out(vty, " %sbarred-access%s", + (set->test_barr) ? "" : "no ", VTY_NEWLINE); + if (set->test_rplmn_valid) { + vty_out(vty, " rplmn %s %s", gsm_print_mcc(set->test_rplmn_mcc), - gsm_print_mnc(set->test_rplmn_mnc), + gsm_print_mnc(set->test_rplmn_mnc)); + if (set->test_lac > 0x0000 && set->test_lac < 0xfffe) + vty_out(vty, " 0x%04x", set->test_lac); + if (set->test_tmsi != 0xffffffff) + vty_out(vty, " 0x%08x", set->test_tmsi); + vty_out(vty, "%s", VTY_NEWLINE); + } else + if (!hide_default) + vty_out(vty, " no rplmn%s", VTY_NEWLINE); + if (!hide_default || set->test_always) + vty_out(vty, " hplmn-search %s%s", + (set->test_always) ? "everywhere" : "foreign-country", VTY_NEWLINE); - else - vty_out(vty, " no rplmn%s", VTY_NEWLINE); - vty_out(vty, " hplmn-search %s%s", (set->test_always) ? "everywhere" - : "foreign-country", VTY_NEWLINE); vty_out(vty, " exit%s", VTY_NEWLINE); + /* no shutdown must be written to config, because shutdown is default */ + vty_out(vty, " %sshutdown%s", (ms->shutdown) ? "" : "no ", + VTY_NEWLINE); vty_out(vty, "exit%s", VTY_NEWLINE); vty_out(vty, "!%s", VTY_NEWLINE); } -static int config_write_ms(struct vty *vty) +static int config_write(struct vty *vty) { struct osmocom_ms *ms; - vty_out(vty, "gps device %s%s", gps.device, VTY_NEWLINE); - if (gps.baud) - vty_out(vty, "gps baudrate %d%s", gps.baud, VTY_NEWLINE); +#ifdef _HAVE_GPSD + vty_out(vty, "gpsd host %s%s", g.gpsd_host, VTY_NEWLINE); + vty_out(vty, "gpsd port %s%s", g.gpsd_port, VTY_NEWLINE); +#endif + vty_out(vty, "gps device %s%s", g.device, VTY_NEWLINE); + if (g.baud) + vty_out(vty, "gps baudrate %d%s", g.baud, VTY_NEWLINE); else vty_out(vty, "gps baudrate default%s", VTY_NEWLINE); - vty_out(vty, "%sgps enable%s", (gps.enable) ? "" : "no ", VTY_NEWLINE); + vty_out(vty, "%sgps enable%s", (g.enable) ? "" : "no ", VTY_NEWLINE); + vty_out(vty, "!%s", VTY_NEWLINE); + + vty_out(vty, "%shide-default%s", (hide_default) ? "": "no ", + VTY_NEWLINE); vty_out(vty, "!%s", VTY_NEWLINE); llist_for_each_entry(ms, &ms_list, entity) - config_write_ms_single(vty, ms); + config_write_ms(vty, ms); return CMD_SUCCESS; } +DEFUN(cfg_ms_show_this, cfg_ms_show_this_cmd, "show this", + SHOW_STR "Show config of this MS") +{ + struct osmocom_ms *ms = vty->index; + + config_write_ms(vty, ms); + + return CMD_SUCCESS; +} + +DEFUN(cfg_ms_layer2, cfg_ms_layer2_cmd, "layer2-socket PATH", + "Define socket path to connect between layer 2 and layer 1\n" + "Unix socket, default '/tmp/osmocom_l2'") +{ + struct osmocom_ms *ms = vty->index; + struct gsm_settings *set = &ms->settings; + + strncpy(set->layer2_socket_path, argv[0], + sizeof(set->layer2_socket_path) - 1); + + vty_restart(vty, ms); + return CMD_SUCCESS; +} + +DEFUN(cfg_ms_sap, cfg_ms_sap_cmd, "sap-socket PATH", + "Define socket path to connect to SIM reader\n" + "Unix socket, default '/tmp/osmocom_sap'") +{ + struct osmocom_ms *ms = vty->index; + struct gsm_settings *set = &ms->settings; + + strncpy(set->sap_socket_path, argv[0], + sizeof(set->sap_socket_path) - 1); + + vty_restart(vty, ms); + return CMD_SUCCESS; +} + DEFUN(cfg_ms_sim, cfg_ms_sim_cmd, "sim (none|reader|test)", "Set SIM card type when powering on\nNo SIM interted\n" "Use SIM from reader\nTest SIM inserted") @@ -986,7 +1356,7 @@ DEFUN(cfg_ms_sim, cfg_ms_sim_cmd, "sim (none|reader|test)", return CMD_WARNING; } - vty_restart(vty); + vty_restart(vty, ms); return CMD_SUCCESS; } @@ -1049,7 +1419,7 @@ DEFUN(cfg_ms_imei_fixed, cfg_ms_imei_fixed_cmd, "imei-fixed", set->imei_random = 0; - vty_restart(vty); + vty_restart(vty, ms); return CMD_SUCCESS; } @@ -1062,7 +1432,7 @@ DEFUN(cfg_ms_imei_random, cfg_ms_imei_random_cmd, "imei-random <0-15>", set->imei_random = atoi(argv[0]); - vty_restart(vty); + vty_restart(vty, ms); return CMD_SUCCESS; } @@ -1116,6 +1486,28 @@ DEFUN(cfg_cw, cfg_ms_cw_cmd, "call-waiting", return CMD_SUCCESS; } +DEFUN(cfg_no_auto_answer, cfg_ms_no_auto_answer_cmd, "no auto-answer", + NO_STR "Disable auto-answering calls") +{ + struct osmocom_ms *ms = vty->index; + struct gsm_settings *set = &ms->settings; + + set->auto_answer = 0; + + return CMD_SUCCESS; +} + +DEFUN(cfg_auto_answer, cfg_ms_auto_answer_cmd, "auto-answer", + "Enable auto-answering calls") +{ + struct osmocom_ms *ms = vty->index; + struct gsm_settings *set = &ms->settings; + + set->auto_answer = 1; + + return CMD_SUCCESS; +} + DEFUN(cfg_clip, cfg_ms_clip_cmd, "clip", "Force caller ID presentation") { @@ -1220,14 +1612,24 @@ DEFUN(cfg_ms_no_sim_delay, cfg_ms_no_sim_delay_cmd, "no simulated-delay", return CMD_SUCCESS; } -DEFUN(cfg_ms_stick, cfg_ms_stick_cmd, "stick <0-1023>", - "Stick to the given cell\nARFCN of the cell to stick to") +DEFUN(cfg_ms_stick, cfg_ms_stick_cmd, "stick <0-1023> [pcs]", + "Stick to the given cell\nARFCN of the cell to stick to\n" + "Given frequency is PCS band (1900) rather than DCS band.") { struct osmocom_ms *ms = vty->index; struct gsm_settings *set = &ms->settings; + uint16_t arfcn = atoi(argv[0]); + if (argc > 1) { + if (arfcn < 512 || arfcn > 810) { + vty_out(vty, "Given ARFCN not in PCS band%s", + VTY_NEWLINE); + return CMD_WARNING; + } + arfcn |= ARFCN_PCS; + } set->stick = 1; - set->stick_arfcn = atoi(argv[0]); + set->stick_arfcn = arfcn; return CMD_SUCCESS; } @@ -1347,6 +1749,80 @@ DEFUN(cfg_no_codec_half, cfg_ms_no_codec_half_cmd, "no codec half-speed", return CMD_SUCCESS; } +DEFUN(cfg_abbrev, cfg_ms_abbrev_cmd, "abbrev ABBREVIATION NUMBER [NAME]", + "Store given abbreviation number\n1-3 digits abbreviation\n" + "Number to store for the abbreviation " + "(Use digits '0123456789*#abc', and '+' to dial international)\n" + "Name of the abbreviation") +{ + struct osmocom_ms *ms = vty->index; + struct gsm_settings *set = &ms->settings; + struct gsm_settings_abbrev *abbrev; + int i; + + llist_for_each_entry(abbrev, &set->abbrev, list) { + if (!strcmp(argv[0], abbrev->abbrev)) { + vty_out(vty, "Given abbreviation '%s' already stored, " + "delete first!%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + } + + if (strlen(argv[0]) >= sizeof(abbrev->abbrev)) { + vty_out(vty, "Given abbreviation too long%s", VTY_NEWLINE); + return CMD_WARNING; + } + + for (i = 0; i < strlen(argv[0]); i++) { + if (argv[0][i] < '0' || argv[0][i] > '9') { + vty_out(vty, "Given abbreviation must have digits " + "0..9 only!%s", VTY_NEWLINE); + return CMD_WARNING; + } + } + + if (vty_check_number(vty, argv[1])) + return CMD_WARNING; + + abbrev = talloc_zero(l23_ctx, struct gsm_settings_abbrev); + if (!abbrev) { + vty_out(vty, "No Memory!%s", VTY_NEWLINE); + return CMD_WARNING; + } + llist_add_tail(&abbrev->list, &set->abbrev); + strncpy(abbrev->abbrev, argv[0], sizeof(abbrev->abbrev) - 1); + strncpy(abbrev->number, argv[1], sizeof(abbrev->number) - 1); + if (argc >= 3) + strncpy(abbrev->name, argv[2], sizeof(abbrev->name) - 1); + + return CMD_SUCCESS; +} + +DEFUN(cfg_no_abbrev, cfg_ms_no_abbrev_cmd, "no abbrev [ABBREVIATION]", + NO_STR "Remove given abbreviation number or all numbers\n" + "Abbreviation number to remove") +{ + struct osmocom_ms *ms = vty->index; + struct gsm_settings *set = &ms->settings; + struct gsm_settings_abbrev *abbrev, *abbrev2; + uint8_t deleted = 0; + + llist_for_each_entry_safe(abbrev, abbrev2, &set->abbrev, list) { + if (argc < 1 || !strcmp(argv[0], abbrev->abbrev)) { + llist_del(&abbrev->list); + deleted = 1; + } + } + + if (argc >= 1 && !deleted) { + vty_out(vty, "Given abbreviation '%s' not found!%s", + argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + static int config_write_dummy(struct vty *vty) { return CMD_SUCCESS; @@ -1374,7 +1850,7 @@ DEFUN(cfg, cfg_cmd, cmd, "Enable " desc "support") \ return CMD_WARNING; \ } \ if (restart) \ - vty_restart(vty); \ + vty_restart(vty, ms); \ set->item = 1; \ return CMD_SUCCESS; \ } @@ -1392,11 +1868,35 @@ DEFUN(cfg, cfg_cmd, "no " cmd, NO_STR "Disable " desc " support") \ return CMD_WARNING; \ } \ if (restart) \ - vty_restart(vty); \ + vty_restart(vty, ms); \ set->item = 0; \ return CMD_SUCCESS; \ } +#define SET_EN(cfg, cfg_cmd, item, cmd, desc, restart) \ +DEFUN(cfg, cfg_cmd, cmd, "Enable " desc "support") \ +{ \ + struct osmocom_ms *ms = vty->index; \ + struct gsm_settings *set = &ms->settings; \ + if (restart) \ + vty_restart(vty, ms); \ + set->item = 1; \ + return CMD_SUCCESS; \ +} + +#define SET_DI(cfg, cfg_cmd, item, cmd, desc, restart) \ +DEFUN(cfg, cfg_cmd, "no " cmd, NO_STR "Disable " desc " support") \ +{ \ + struct osmocom_ms *ms = vty->index; \ + struct gsm_settings *set = &ms->settings; \ + if (restart) \ + vty_restart(vty, ms); \ + set->item = 0; \ + return CMD_SUCCESS; \ +} + +SET_EN(cfg_ms_sup_dtmf, cfg_ms_sup_dtmf_cmd, cc_dtmf, "dtmf", "DTMF", 0); +SET_DI(cfg_ms_sup_no_dtmf, cfg_ms_sup_no_dtmf_cmd, cc_dtmf, "dtmf", "DTMF", 0); SUP_EN(cfg_ms_sup_sms, cfg_ms_sup_sms_cmd, sms_ptp, "sms", "SMS", 0); SUP_DI(cfg_ms_sup_no_sms, cfg_ms_sup_no_sms_cmd, sms_ptp, "sms", "SMS", 0); SUP_EN(cfg_ms_sup_a5_1, cfg_ms_sup_a5_1_cmd, a5_1, "a5/1", "A5/1", 0); @@ -1427,9 +1927,23 @@ SUP_DI(cfg_ms_sup_no_r_gsm, cfg_ms_sup_no_r_gsm_cmd, r_gsm, "r-gsm", "R-GSM (850)", 1); SUP_EN(cfg_ms_sup_dcs, cfg_ms_sup_dcs_cmd, dcs, "dcs", "DCS (1800)", 0); SUP_DI(cfg_ms_sup_no_dcs, cfg_ms_sup_no_dcs_cmd, dcs, "dcs", "DCS (1800)", 0); +SUP_EN(cfg_ms_sup_gsm_850, cfg_ms_sup_gsm_850_cmd, gsm_850, "gsm-850", + "GSM 850", 0); +SUP_DI(cfg_ms_sup_no_gsm_850, cfg_ms_sup_no_gsm_850_cmd, gsm_850, "gsm-850", + "GSM 850", 0); +SUP_EN(cfg_ms_sup_pcs, cfg_ms_sup_pcs_cmd, pcs, "pcs", "PCS (1900)", 0); +SUP_DI(cfg_ms_sup_no_pcs, cfg_ms_sup_no_pcs_cmd, pcs, "pcs", "PCS (1900)", 0); +SUP_EN(cfg_ms_sup_gsm_480, cfg_ms_sup_gsm_480_cmd, gsm_480, "gsm-480", + "GSM 480", 0); +SUP_DI(cfg_ms_sup_no_gsm_480, cfg_ms_sup_no_gsm_480_cmd, gsm_480, "gsm-480", + "GSM 480", 0); +SUP_EN(cfg_ms_sup_gsm_450, cfg_ms_sup_gsm_450_cmd, gsm_450, "gsm-450", + "GSM 450", 0); +SUP_DI(cfg_ms_sup_no_gsm_450, cfg_ms_sup_no_gsm_450_cmd, gsm_450, "gsm-450", + "GSM 450", 0); DEFUN(cfg_ms_sup_class_900, cfg_ms_sup_class_900_cmd, "class-900 (1|2|3|4|5)", - "Select power class for GSM 850/900\n" + "Select power class for GSM 900\n" "20 Watts\n" "8 Watts\n" "5 Watts\n" @@ -1443,7 +1957,49 @@ DEFUN(cfg_ms_sup_class_900, cfg_ms_sup_class_900_cmd, "class-900 (1|2|3|4|5)", set->class_900 = atoi(argv[0]); if (set->class_900 < sup->class_900 && !vty_reading) - vty_out(vty, "You selected an higher class than supported " + vty_out(vty, "Note: You selected a higher class than supported " + " by hardware!%s", VTY_NEWLINE); + + return CMD_SUCCESS; +} + +DEFUN(cfg_ms_sup_class_850, cfg_ms_sup_class_850_cmd, "class-850 (1|2|3|4|5)", + "Select power class for GSM 850\n" + "20 Watts\n" + "8 Watts\n" + "5 Watts\n" + "2 Watts\n" + "0.8 Watts") +{ + struct osmocom_ms *ms = vty->index; + struct gsm_settings *set = &ms->settings; + struct gsm_support *sup = &ms->support; + + set->class_850 = atoi(argv[0]); + + if (set->class_850 < sup->class_850 && !vty_reading) + vty_out(vty, "Note: You selected a higher class than supported " + " by hardware!%s", VTY_NEWLINE); + + return CMD_SUCCESS; +} + +DEFUN(cfg_ms_sup_class_400, cfg_ms_sup_class_400_cmd, "class-400 (1|2|3|4|5)", + "Select power class for GSM 400 (480 and 450)\n" + "20 Watts\n" + "8 Watts\n" + "5 Watts\n" + "2 Watts\n" + "0.8 Watts") +{ + struct osmocom_ms *ms = vty->index; + struct gsm_settings *set = &ms->settings; + struct gsm_support *sup = &ms->support; + + set->class_400 = atoi(argv[0]); + + if (set->class_400 < sup->class_400 && !vty_reading) + vty_out(vty, "Note: You selected a higher class than supported " " by hardware!%s", VTY_NEWLINE); return CMD_SUCCESS; @@ -1463,7 +2019,27 @@ DEFUN(cfg_ms_sup_class_dcs, cfg_ms_sup_class_dcs_cmd, "class-dcs (1|2|3)", if (((set->class_dcs + 1) & 3) < ((sup->class_dcs + 1) & 3) && !vty_reading) - vty_out(vty, "You selected an higher class than supported " + vty_out(vty, "Note: You selected a higher class than supported " + " by hardware!%s", VTY_NEWLINE); + + return CMD_SUCCESS; +} + +DEFUN(cfg_ms_sup_class_pcs, cfg_ms_sup_class_pcs_cmd, "class-pcs (1|2|3)", + "Select power class for PCS 1900\n" + "1 Watt\n" + "0.25 Watts\n" + "4 Watts") +{ + struct osmocom_ms *ms = vty->index; + struct gsm_settings *set = &ms->settings; + struct gsm_support *sup = &ms->support; + + set->class_pcs = atoi(argv[0]); + + if (((set->class_pcs + 1) & 3) < ((sup->class_pcs + 1) & 3) + && !vty_reading) + vty_out(vty, "Note: You selected a higher class than supported " " by hardware!%s", VTY_NEWLINE); return CMD_SUCCESS; @@ -1491,6 +2067,10 @@ DEFUN(cfg_ms_sup_ch_cap, cfg_ms_sup_ch_cap_cmd, "channel-capability " return CMD_WARNING; } + if (ch_cap != set->ch_cap + && (ch_cap == GSM_CAP_SDCCH || set->ch_cap == GSM_CAP_SDCCH)) + vty_restart(vty, ms); + set->ch_cap = ch_cap; return CMD_SUCCESS; @@ -1509,13 +2089,13 @@ SUP_EN(cfg_ms_sup_full_v3, cfg_ms_sup_full_v3_cmd, full_v3, "full-speech-v3", SUP_DI(cfg_ms_sup_no_full_v3, cfg_ms_sup_no_full_v3_cmd, full_v3, "full-speech-v3", "Full rate speech V3 (AMR)", 0); SUP_EN(cfg_ms_sup_half_v1, cfg_ms_sup_half_v1_cmd, half_v1, "half-speech-v1", - "Half rate speech V1 (AMR)", 0); + "Half rate speech V1", 0); SUP_DI(cfg_ms_sup_no_half_v1, cfg_ms_sup_no_half_v1_cmd, half_v1, "half-speech-v1", "Half rate speech V1", 0); SUP_EN(cfg_ms_sup_half_v3, cfg_ms_sup_half_v3_cmd, half_v3, "half-speech-v3", "Half rate speech V3 (AMR)", 0); SUP_DI(cfg_ms_sup_no_half_v3, cfg_ms_sup_no_half_v3_cmd, half_v3, - "half-speech-v3", "Half rate speech V3", 0); + "half-speech-v3", "Half rate speech V3 (AMR)", 0); DEFUN(cfg_ms_sup_min_rxlev, cfg_ms_sup_min_rxlev_cmd, "min-rxlev <-110--47>", "Set the minimum receive level to select a cell\n" @@ -1566,7 +2146,7 @@ DEFUN(cfg_test_imsi, cfg_test_imsi_cmd, "imsi IMSI", strcpy(set->test_imsi, argv[0]); - vty_restart(vty); + vty_restart(vty, ms); return CMD_SUCCESS; } @@ -1658,12 +2238,14 @@ DEFUN(cfg_test_no_rplmn, cfg_test_no_rplmn_cmd, "no rplmn", set->test_rplmn_valid = 0; - vty_restart(vty); + vty_restart(vty, ms); return CMD_SUCCESS; } -DEFUN(cfg_test_rplmn, cfg_test_rplmn_cmd, "rplmn MCC MNC", - "Set Registered PLMN\nMobile Country Code\nMobile Network Code") +DEFUN(cfg_test_rplmn, cfg_test_rplmn_cmd, "rplmn MCC MNC [LAC] [TMSI]", + "Set Registered PLMN\nMobile Country Code\nMobile Network Code\n" + "Optionally set locatio area code\n" + "Optionally set current assigned TMSI") { struct osmocom_ms *ms = vty->index; struct gsm_settings *set = &ms->settings; @@ -1682,7 +2264,17 @@ DEFUN(cfg_test_rplmn, cfg_test_rplmn_cmd, "rplmn MCC MNC", set->test_rplmn_mcc = mcc; set->test_rplmn_mnc = mnc; - vty_restart(vty); + if (argc >= 3) + set->test_lac = strtoul(argv[2], NULL, 16); + else + set->test_lac = 0xfffe; + + if (argc >= 4) + set->test_tmsi = strtoul(argv[3], NULL, 16); + else + set->test_tmsi = 0xffffffff; + + vty_restart(vty, ms); return CMD_SUCCESS; } @@ -1703,7 +2295,69 @@ DEFUN(cfg_test_hplmn, cfg_test_hplmn_cmd, "hplmn-search (everywhere|foreign-coun break; } - vty_restart(vty); + vty_restart(vty, ms); + return CMD_SUCCESS; +} + +DEFUN(cfg_no_shutdown, cfg_ms_no_shutdown_cmd, "no shutdown", + NO_STR "Activate and run MS") +{ + struct osmocom_ms *ms = vty->index, *tmp; + int rc; + + if (ms->shutdown != 2) + return CMD_SUCCESS; + + llist_for_each_entry(tmp, &ms_list, entity) { + if (tmp->shutdown == 2) + continue; + if (!strcmp(ms->settings.layer2_socket_path, + tmp->settings.layer2_socket_path)) { + vty_out(vty, "Cannot start MS '%s', because MS '%s' " + "use the same layer2-socket.%sPlease shutdown " + "MS '%s' first.%s", ms->name, tmp->name, + VTY_NEWLINE, tmp->name, VTY_NEWLINE); + return CMD_WARNING; + } + if (!strcmp(ms->settings.sap_socket_path, + tmp->settings.sap_socket_path)) { + vty_out(vty, "Cannot start MS '%s', because MS '%s' " + "use the same sap-socket.%sPlease shutdown " + "MS '%s' first.%s", ms->name, tmp->name, + VTY_NEWLINE, tmp->name, VTY_NEWLINE); + return CMD_WARNING; + } + } + + rc = mobile_init(ms); + if (rc < 0) { + vty_out(vty, "Connection to layer 1 failed!%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +DEFUN(cfg_shutdown, cfg_ms_shutdown_cmd, "shutdown", + "Shut down and deactivate MS") +{ + struct osmocom_ms *ms = vty->index; + + if (ms->shutdown == 0) + mobile_exit(ms, 0); + + return CMD_SUCCESS; +} + +DEFUN(cfg_shutdown_force, cfg_ms_shutdown_force_cmd, "shutdown force", + "Shut down and deactivate MS\nDo not perform IMSI detach") +{ + struct osmocom_ms *ms = vty->index; + + if (ms->shutdown <= 1) + mobile_exit(ms, 1); + return CMD_SUCCESS; } @@ -1769,6 +2423,14 @@ gDEFUN(ournode_end, return CMD_SUCCESS; } +DEFUN(off, off_cmd, "off", + "Turn mobiles off (shutdown) and exit") +{ + osmo_signal_dispatch(SS_GLOBAL, S_GLOBAL_SHUTDOWN, NULL); + + return CMD_SUCCESS; +} + #define SUP_NODE(item) \ install_element(SUPPORT_NODE, &cfg_ms_sup_item_cmd); @@ -1777,7 +2439,6 @@ int ms_vty_init(void) install_element_ve(&show_ms_cmd); install_element_ve(&show_subscr_cmd); install_element_ve(&show_support_cmd); - install_element_ve(&show_states_cmd); install_element_ve(&show_cell_cmd); install_element_ve(&show_cell_si_cmd); install_element_ve(&show_ba_cmd); @@ -1785,6 +2446,7 @@ int ms_vty_init(void) install_element_ve(&show_forb_plmn_cmd); install_element_ve(&monitor_network_cmd); install_element_ve(&no_monitor_network_cmd); + install_element(ENABLE_NODE, &off_cmd); install_element(ENABLE_NODE, &sim_test_cmd); install_element(ENABLE_NODE, &sim_reader_cmd); @@ -1800,18 +2462,31 @@ int ms_vty_init(void) install_element(ENABLE_NODE, &network_select_cmd); install_element(ENABLE_NODE, &call_cmd); install_element(ENABLE_NODE, &call_retr_cmd); + install_element(ENABLE_NODE, &call_dtmf_cmd); +#ifdef _HAVE_GPSD + install_element(CONFIG_NODE, &cfg_gps_host_cmd); +#endif install_element(CONFIG_NODE, &cfg_gps_device_cmd); install_element(CONFIG_NODE, &cfg_gps_baud_cmd); install_element(CONFIG_NODE, &cfg_gps_enable_cmd); install_element(CONFIG_NODE, &cfg_no_gps_enable_cmd); + install_element(CONFIG_NODE, &cfg_hide_default_cmd); + install_element(CONFIG_NODE, &cfg_no_hide_default_cmd); + install_element(CONFIG_NODE, &cfg_ms_cmd); + install_element(CONFIG_NODE, &cfg_ms_create_cmd); + install_element(CONFIG_NODE, &cfg_ms_rename_cmd); + install_element(CONFIG_NODE, &cfg_no_ms_cmd); install_element(CONFIG_NODE, &ournode_end_cmd); - install_node(&ms_node, config_write_ms); + install_node(&ms_node, config_write); install_default(MS_NODE); install_element(MS_NODE, &ournode_exit_cmd); install_element(MS_NODE, &ournode_end_cmd); + install_element(MS_NODE, &cfg_ms_show_this_cmd); + install_element(MS_NODE, &cfg_ms_layer2_cmd); + install_element(MS_NODE, &cfg_ms_sap_cmd); install_element(MS_NODE, &cfg_ms_sim_cmd); install_element(MS_NODE, &cfg_ms_mode_cmd); install_element(MS_NODE, &cfg_ms_imei_cmd); @@ -1821,6 +2496,8 @@ int ms_vty_init(void) install_element(MS_NODE, &cfg_ms_emerg_imsi_cmd); install_element(MS_NODE, &cfg_ms_cw_cmd); install_element(MS_NODE, &cfg_ms_no_cw_cmd); + install_element(MS_NODE, &cfg_ms_auto_answer_cmd); + install_element(MS_NODE, &cfg_ms_no_auto_answer_cmd); install_element(MS_NODE, &cfg_ms_clip_cmd); install_element(MS_NODE, &cfg_ms_clir_cmd); install_element(MS_NODE, &cfg_ms_no_clip_cmd); @@ -1838,12 +2515,16 @@ int ms_vty_init(void) 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_element(MS_NODE, &cfg_ms_abbrev_cmd); + install_element(MS_NODE, &cfg_ms_no_abbrev_cmd); install_element(MS_NODE, &cfg_ms_testsim_cmd); install_element(MS_NODE, &cfg_ms_support_cmd); install_node(&support_node, config_write_dummy); install_default(SUPPORT_NODE); install_element(SUPPORT_NODE, &ournode_exit_cmd); install_element(SUPPORT_NODE, &ournode_end_cmd); + install_element(SUPPORT_NODE, &cfg_ms_sup_dtmf_cmd); + install_element(SUPPORT_NODE, &cfg_ms_sup_no_dtmf_cmd); install_element(SUPPORT_NODE, &cfg_ms_sup_sms_cmd); install_element(SUPPORT_NODE, &cfg_ms_sup_no_sms_cmd); install_element(SUPPORT_NODE, &cfg_ms_sup_a5_1_cmd); @@ -1868,8 +2549,19 @@ int ms_vty_init(void) install_element(SUPPORT_NODE, &cfg_ms_sup_no_r_gsm_cmd); install_element(SUPPORT_NODE, &cfg_ms_sup_dcs_cmd); install_element(SUPPORT_NODE, &cfg_ms_sup_no_dcs_cmd); + install_element(SUPPORT_NODE, &cfg_ms_sup_gsm_850_cmd); + install_element(SUPPORT_NODE, &cfg_ms_sup_no_gsm_850_cmd); + install_element(SUPPORT_NODE, &cfg_ms_sup_pcs_cmd); + install_element(SUPPORT_NODE, &cfg_ms_sup_no_pcs_cmd); + install_element(SUPPORT_NODE, &cfg_ms_sup_gsm_480_cmd); + install_element(SUPPORT_NODE, &cfg_ms_sup_no_gsm_480_cmd); + install_element(SUPPORT_NODE, &cfg_ms_sup_gsm_450_cmd); + install_element(SUPPORT_NODE, &cfg_ms_sup_no_gsm_450_cmd); install_element(SUPPORT_NODE, &cfg_ms_sup_class_900_cmd); install_element(SUPPORT_NODE, &cfg_ms_sup_class_dcs_cmd); + install_element(SUPPORT_NODE, &cfg_ms_sup_class_850_cmd); + install_element(SUPPORT_NODE, &cfg_ms_sup_class_pcs_cmd); + install_element(SUPPORT_NODE, &cfg_ms_sup_class_400_cmd); install_element(SUPPORT_NODE, &cfg_ms_sup_ch_cap_cmd); install_element(SUPPORT_NODE, &cfg_ms_sup_full_v1_cmd); install_element(SUPPORT_NODE, &cfg_ms_sup_no_full_v1_cmd); @@ -1895,6 +2587,9 @@ int ms_vty_init(void) install_element(TESTSIM_NODE, &cfg_test_no_rplmn_cmd); install_element(TESTSIM_NODE, &cfg_test_rplmn_cmd); install_element(TESTSIM_NODE, &cfg_test_hplmn_cmd); + install_element(MS_NODE, &cfg_ms_shutdown_cmd); + install_element(MS_NODE, &cfg_ms_shutdown_force_cmd); + install_element(MS_NODE, &cfg_ms_no_shutdown_cmd); return 0; }