+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;
+ struct gsm_settings *set = &ms->settings;
+ char *error, *sv = "0";
+
+ if (argc >= 2)
+ sv = (char *)argv[1];
+
+ error = gsm_check_imei(argv[0], sv);
+ if (error) {
+ vty_out(vty, "%s%s", error, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+
+ strcpy(set->imei, argv[0]);
+ strcpy(set->imeisv, argv[0]);
+ strcpy(set->imeisv + 15, sv);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_ms_imei_fixed, cfg_ms_imei_fixed_cmd, "imei-fixed",
+ "Use fixed IMEI on every power on")
+{
+ struct osmocom_ms *ms = vty->index;
+ struct gsm_settings *set = &ms->settings;
+
+ set->imei_random = 0;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_ms_imei_random, cfg_ms_imei_random_cmd, "imei-random <0-15>",
+ "Use random IMEI on every power on\n"
+ "Number of trailing digits to randomize")
+{
+ struct osmocom_ms *ms = vty->index;
+ struct gsm_settings *set = &ms->settings;
+
+ set->imei_random = atoi(argv[0]);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_ms_emerg_imsi, cfg_ms_emerg_imsi_cmd, "emergency-imsi IMSI",
+ "Use special IMSI for emergency calls\n15 digits IMSI")
+{
+ struct osmocom_ms *ms = vty->index;
+ struct gsm_settings *set = &ms->settings;
+ char *error;
+
+ error = gsm_check_imsi(argv[0]);
+ if (error) {
+ vty_out(vty, "%s%s", error, VTY_NEWLINE);
+ return CMD_WARNING;
+ }
+ strcpy(set->emergency_imsi, argv[0]);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_ms_no_emerg_imsi, cfg_ms_no_emerg_imsi_cmd, "no emergency-imsi",
+ NO_STR "Use IMSI of SIM or IMEI for emergency calls")
+{
+ struct osmocom_ms *ms = vty->index;
+ struct gsm_settings *set = &ms->settings;
+
+ set->emergency_imsi[0] = '\0';
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_no_cw, cfg_ms_no_cw_cmd, "no call-waiting",
+ NO_STR "Disallow waiting calls")
+{
+ struct osmocom_ms *ms = vty->index;
+ struct gsm_settings *set = &ms->settings;
+
+ set->cw = 0;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_cw, cfg_ms_cw_cmd, "call-waiting",
+ "Allow waiting calls")
+{
+ struct osmocom_ms *ms = vty->index;
+ struct gsm_settings *set = &ms->settings;
+
+ set->cw = 1;
+
+ 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")
+{
+ struct osmocom_ms *ms = vty->index;
+ struct gsm_settings *set = &ms->settings;
+
+ set->clip = 1;
+ set->clir = 0;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_clir, cfg_ms_clir_cmd, "clir",
+ "Force caller ID restriction")
+{
+ struct osmocom_ms *ms = vty->index;
+ struct gsm_settings *set = &ms->settings;
+
+ set->clip = 0;
+ set->clir = 1;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_no_clip, cfg_ms_no_clip_cmd, "no clip",
+ NO_STR "Disable forcing of caller ID presentation")
+{
+ struct osmocom_ms *ms = vty->index;
+ struct gsm_settings *set = &ms->settings;
+
+ set->clip = 0;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_no_clir, cfg_ms_no_clir_cmd, "no clir",
+ NO_STR "Disable forcing of caller ID restriction")
+{
+ struct osmocom_ms *ms = vty->index;
+ struct gsm_settings *set = &ms->settings;
+
+ set->clir = 0;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_ms_tx_power, cfg_ms_tx_power_cmd, "tx-power (auto|full)",
+ "Set the way to choose transmit power\nControlled by BTS\n"
+ "Always full power\nFixed GSM power value if supported")
+{
+ struct osmocom_ms *ms = vty->index;
+ struct gsm_settings *set = &ms->settings;
+
+ switch (argv[0][0]) {
+ case 'a':
+ set->alter_tx_power = 0;
+ break;
+ case 'f':
+ set->alter_tx_power = 1;
+ set->alter_tx_power_value = 0;
+ break;
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_ms_tx_power_val, cfg_ms_tx_power_val_cmd, "tx-power <0-31>",
+ "Set the way to choose transmit power\n"
+ "Fixed GSM power value if supported")
+{
+ struct osmocom_ms *ms = vty->index;
+ struct gsm_settings *set = &ms->settings;
+
+ set->alter_tx_power = 1;
+ set->alter_tx_power_value = atoi(argv[0]);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_ms_sim_delay, cfg_ms_sim_delay_cmd, "simulated-delay <-128-127>",
+ "Simulate a lower or higher distance from the BTS\n"
+ "Delay in half bits (distance in 553.85 meter steps)")
+{
+ struct osmocom_ms *ms = vty->index;
+ struct gsm_settings *set = &ms->settings;
+
+ set->alter_delay = atoi(argv[0]);
+ gsm48_rr_alter_delay(ms);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_ms_no_sim_delay, cfg_ms_no_sim_delay_cmd, "no simulated-delay",
+ NO_STR "Do not simulate a lower or higher distance from the BTS")
+{
+ struct osmocom_ms *ms = vty->index;
+ struct gsm_settings *set = &ms->settings;
+
+ set->alter_delay = 0;
+ gsm48_rr_alter_delay(ms);
+
+ return CMD_SUCCESS;
+}
+
+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 = arfcn;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_ms_no_stick, cfg_ms_no_stick_cmd, "no stick",
+ NO_STR "Do not stick to any cell")