+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")
+{
+ struct osmocom_ms *ms;
+
+ ms = get_ms(argv[0], vty);
+ if (!ms)
+ return CMD_WARNING;
+
+ mncc_retrieve(ms, (argc > 1) ? atoi(argv[1]) : 0);
+
+ 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(test_reselection, test_reselection_cmd, "test re-selection NAME",
+ "Manually trigger cell re-selection\nName of MS (see \"show ms\")")
+{
+ struct osmocom_ms *ms;
+ struct gsm_settings *set;
+ struct msgb *nmsg;
+
+ ms = get_ms(argv[0], vty);
+ if (!ms)
+ return CMD_WARNING;
+ set = &ms->settings;
+
+ if (set->stick) {
+ vty_out(vty, "Cannot trigger cell re-selection, because we "
+ "stick to a cell!%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ nmsg = gsm322_msgb_alloc(GSM322_EVENT_CELL_RESEL);
+ if (!nmsg)
+ return CMD_WARNING;
+ gsm322_c_event(ms, nmsg);
+
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(delete_forbidden_plmn, delete_forbidden_plmn_cmd,
+ "delete forbidden plmn NAME MCC MNC",
+ "Delete\nForbidden\nplmn\nName of MS (see \"show ms\")\n"
+ "Mobile Country Code\nMobile Network Code")
+{
+ struct osmocom_ms *ms;
+ uint16_t mcc = gsm_input_mcc((char *)argv[1]),
+ mnc = gsm_input_mnc((char *)argv[2]);
+
+ ms = get_ms(argv[0], vty);
+ if (!ms)
+ return CMD_WARNING;
+
+ if (mcc == GSM_INPUT_INVALID) {
+ vty_out(vty, "Given MCC invalid%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ if (mnc == GSM_INPUT_INVALID) {
+ vty_out(vty, "Given MNC invalid%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ gsm_subscr_del_forbidden_plmn(&ms->subscr, mcc, mnc);
+
+ 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\")")
+{
+ struct osmocom_ms *ms;
+ struct gsm_settings *set;
+ struct gsm322_plmn *plmn;
+ struct gsm322_plmn_list *temp;
+
+ ms = get_ms(argv[0], vty);
+ if (!ms)
+ return CMD_WARNING;
+ set = &ms->settings;
+ plmn = &ms->plmn;
+
+ if (set->plmn_mode != PLMN_MODE_AUTO
+ && plmn->state != GSM322_M3_NOT_ON_PLMN) {
+ vty_out(vty, "Start network search first!%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ llist_for_each_entry(temp, &plmn->sorted_plmn, entry)
+ vty_out(vty, " Network %s, %s (%s, %s)%s",
+ gsm_print_mcc(temp->mcc), gsm_print_mnc(temp->mnc),
+ gsm_get_mcc(temp->mcc),
+ gsm_get_mnc(temp->mcc, temp->mnc), VTY_NEWLINE);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(network_search, network_search_cmd, "network search MS_NAME",
+ "Network ...\nTrigger network search\nName of MS (see \"show ms\")")
+{
+ struct osmocom_ms *ms;
+ struct msgb *nmsg;
+
+ ms = get_ms(argv[0], vty);
+ if (!ms)
+ return CMD_WARNING;
+
+ nmsg = gsm322_msgb_alloc(GSM322_EVENT_USER_RESEL);
+ if (!nmsg)
+ return CMD_WARNING;
+ gsm322_plmn_sendmsg(ms, nmsg);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_gps_enable, cfg_gps_enable_cmd, "gps enable",
+ "GPS receiver")
+{
+ if (osmo_gps_open()) {
+ g.enable = 1;
+ vty_out(vty, "Failed to open GPS device!%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ g.enable = 1;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_no_gps_enable, cfg_no_gps_enable_cmd, "no gps enable",
+ NO_STR "Disable GPS receiver")
+{
+ 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(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;
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_gps_baud, cfg_gps_baud_cmd, "gps baudrate "
+ "(default|4800|""9600|19200|38400|57600|115200)",
+ "GPS receiver\nSelect baud rate\nDefault, don't modify\n\n\n\n\n\n")
+{
+ if (argv[0][0] == 'd')
+ g.baud = 0;
+ else
+ 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;
+ }
+ }
+
+ 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;
+
+ 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) \
+ if (!hide_default || !set->item) \
+ vty_out(vty, " %s%s%s", (set->item) ? "" : "no ", \
+ cmd, VTY_NEWLINE);
+
+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);
+ break;
+ case GSM_SIM_TYPE_READER:
+ vty_out(vty, " sim reader%s", VTY_NEWLINE);
+ break;
+ case GSM_SIM_TYPE_TEST:
+ vty_out(vty, " sim test%s", VTY_NEWLINE);
+ break;
+ }
+ vty_out(vty, " network-selection-mode %s%s", (set->plmn_mode
+ == PLMN_MODE_AUTO) ? "auto" : "manual", VTY_NEWLINE);
+ vty_out(vty, " imei %s %s%s", set->imei,
+ set->imeisv + strlen(set->imei), VTY_NEWLINE);
+ if (set->imei_random)
+ vty_out(vty, " imei-random %d%s", set->imei_random,
+ VTY_NEWLINE);
+ else
+ 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
+ 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",
+ set->alter_tx_power_value, VTY_NEWLINE);
+ else
+ vty_out(vty, " tx-power full%s", VTY_NEWLINE);
+ else
+ 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
+ if (!hide_default)
+ vty_out(vty, " no simulated-delay%s", VTY_NEWLINE);
+ if (set->stick)
+ vty_out(vty, " stick %d%s%s", set->stick_arfcn & 1023,
+ (set->stick_arfcn & ARFCN_PCS) ? " pcs" : "",
+ VTY_NEWLINE);
+ else
+ 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 (!hide_default || set->no_neighbour)
+ vty_out(vty, " %sneighbour-measurement%s",
+ (set->no_neighbour) ? "no " : "", VTY_NEWLINE);
+ if (set->full_v1 || set->full_v2 || set->full_v3) {
+ /* mandatory anyway */
+ vty_out(vty, " codec full-speed%s%s",
+ (!set->half_prefer) ? " prefer" : "",
+ VTY_NEWLINE);
+ }
+ if (set->half_v1 || set->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);
+ }
+ 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");
+ SUP_WRITE(a5_2, "a5/2");
+ SUP_WRITE(a5_3, "a5/3");
+ SUP_WRITE(a5_4, "a5/4");
+ SUP_WRITE(a5_5, "a5/5");
+ SUP_WRITE(a5_6, "a5/6");
+ SUP_WRITE(a5_7, "a5/7");
+ 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");
+ 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");
+ 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);
+ if (!hide_default || set->skip_max_per_band)
+ vty_out(vty, " %skip-max-per-band%s",
+ (set->skip_max_per_band) ? "" : "no ", 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",
+ osmo_hexdump(set->test_ki, 12), VTY_NEWLINE);
+ break;
+ case GSM_SIM_KEY_COMP128:
+ vty_out(vty, " ki comp128 %s%s",
+ osmo_hexdump(set->test_ki, 16), VTY_NEWLINE);
+ break;
+ }
+ 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));
+ 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);
+ 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(struct vty *vty)
+{
+ struct osmocom_ms *ms;
+
+#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", (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(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 to attach when powering on\nAttach no SIM\n"
+ "Attach SIM from reader\nAttach bulit in test SIM")
+{
+ struct osmocom_ms *ms = vty->index;
+ struct gsm_settings *set = &ms->settings;
+
+ switch (argv[0][0]) {
+ case 'n':
+ set->sim_type = GSM_SIM_TYPE_NONE;
+ break;
+ case 'r':
+ set->sim_type = GSM_SIM_TYPE_READER;
+ break;
+ case 't':
+ set->sim_type = GSM_SIM_TYPE_TEST;
+ break;
+ default:
+ vty_out(vty, "unknown SIM type%s", VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ vty_restart_if_started(vty, ms);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_ms_mode, cfg_ms_mode_cmd, "network-selection-mode (auto|manual)",
+ "Set network selection mode\nAutomatic network selection\n"
+ "Manual network selection")
+{
+ struct osmocom_ms *ms = vty->index;
+ struct gsm_settings *set = &ms->settings;
+ struct msgb *nmsg;
+
+ if (!ms->started) {
+ if (argv[0][0] == 'a')
+ set->plmn_mode = PLMN_MODE_AUTO;
+ else
+ set->plmn_mode = PLMN_MODE_MANUAL;
+ } else {
+ if (argv[0][0] == 'a')
+ nmsg = gsm322_msgb_alloc(GSM322_EVENT_SEL_AUTO);
+ else
+ nmsg = gsm322_msgb_alloc(GSM322_EVENT_SEL_MANUAL);
+ if (!nmsg)
+ return CMD_WARNING;
+ gsm322_plmn_sendmsg(ms, nmsg);
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_ms_imei, cfg_ms_imei_cmd, "imei IMEI [SV]",
+ "Set IMEI (enter without control digit)\n15 Digits IMEI\n"
+ "Software version digit")
+{
+ struct osmocom_ms *ms = vty->index;