[layer23] Correctly report to restart mobile instance after band change
[osmocom-bb.git] / src / host / layer23 / src / mobile / vty_interface.c
index 1aad7ce..f5ccac3 100644 (file)
 #include <unistd.h>
 #include <sys/types.h>
 
 #include <unistd.h>
 #include <sys/types.h>
 
-#include <osmocore/utils.h>
-#include <osmocore/gsm48.h>
-#include <osmocore/talloc.h>
-#include <osmocore/signal.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/gsm/gsm48.h>
+#include <osmocom/core/talloc.h>
+#include <osmocom/core/signal.h>
 
 #include <osmocom/bb/common/osmocom_data.h>
 #include <osmocom/bb/common/networks.h>
 
 #include <osmocom/bb/common/osmocom_data.h>
 #include <osmocom/bb/common/networks.h>
@@ -115,6 +115,7 @@ int vty_check_number(struct vty *vty, const char *number)
 }
 
 int vty_reading = 0;
 }
 
 int vty_reading = 0;
+static int hide_default = 0;
 
 static void vty_restart(struct vty *vty, struct osmocom_ms *ms)
 {
 
 static void vty_restart(struct vty *vty, struct osmocom_ms *ms)
 {
@@ -126,6 +127,13 @@ static void vty_restart(struct vty *vty, struct osmocom_ms *ms)
                "change to take effect!%s", ms->name, VTY_NEWLINE);
 }
 
                "change to take effect!%s", ms->name, VTY_NEWLINE);
 }
 
+static void vty_restart_if_started(struct vty *vty, struct osmocom_ms *ms)
+{
+       if (!ms->started)
+               return;
+       vty_restart(vty, ms);
+}
+
 static struct osmocom_ms *get_ms(const char *name, struct vty *vty)
 {
        struct osmocom_ms *ms;
 static struct osmocom_ms *get_ms(const char *name, struct vty *vty)
 {
        struct osmocom_ms *ms;
@@ -195,32 +203,46 @@ static void gsm_ms_dump(struct osmocom_ms *ms, struct vty *vty)
                return;
 
        if (set->plmn_mode == PLMN_MODE_AUTO)
                return;
 
        if (set->plmn_mode == PLMN_MODE_AUTO)
-               vty_out(vty, "  automatic network selection state: %s%s", 
-                       plmn_a_state_names[ms->plmn.state], VTY_NEWLINE);
+               vty_out(vty, "  automatic network selection state: %s%s",
+                       get_a_state_name(ms->plmn.state), VTY_NEWLINE);
        else
        else
-               vty_out(vty, "  manual network selection state: %s%s", 
-                       plmn_m_state_names[ms->plmn.state], VTY_NEWLINE);
-       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 %d)", ms->cellsel.sel_arfcn);
-       vty_out(vty, "%s", VTY_NEWLINE);
-       vty_out(vty, "  radio ressource layer state: %s%s", 
+               vty_out(vty, "  manual network selection state   : %s%s",
+                       get_m_state_name(ms->plmn.state), VTY_NEWLINE);
+       if (ms->plmn.mcc)
+               vty_out(vty, "                                     MCC=%s "
+                       "MNC=%s (%s, %s)%s", gsm_print_mcc(ms->plmn.mcc),
+                       gsm_print_mnc(ms->plmn.mnc), gsm_get_mcc(ms->plmn.mcc),
+                       gsm_get_mnc(ms->plmn.mcc, ms->plmn.mnc), VTY_NEWLINE);
+       vty_out(vty, "  cell selection state: %s%s",
+               get_cs_state_name(ms->cellsel.state), VTY_NEWLINE);
+       if (ms->cellsel.sel_mcc) {
+               vty_out(vty, "                        ARFCN=%s MCC=%s MNC=%s "
+                       "LAC=0x%04x CELLID=0x%04x%s",
+                       gsm_print_arfcn(ms->cellsel.sel_arfcn),
+                       gsm_print_mcc(ms->cellsel.sel_mcc),
+                       gsm_print_mnc(ms->cellsel.sel_mnc),
+                       ms->cellsel.sel_lac, ms->cellsel.sel_id, VTY_NEWLINE);
+               vty_out(vty, "                        (%s, %s)%s",
+                       gsm_get_mcc(ms->cellsel.sel_mcc),
+                       gsm_get_mnc(ms->cellsel.sel_mcc, ms->cellsel.sel_mnc),
+                       VTY_NEWLINE);
+       }
+       vty_out(vty, "  radio ressource layer state: %s%s",
                gsm48_rr_state_names[ms->rrlayer.state], VTY_NEWLINE);
                gsm48_rr_state_names[ms->rrlayer.state], VTY_NEWLINE);
-       vty_out(vty, "  mobility management layer state: %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)
                gsm48_mm_state_names[ms->mmlayer.state]);
        if (ms->mmlayer.state == GSM48_MM_ST_MM_IDLE)
-               vty_out(vty, ", %s", 
+               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) {
                        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 state: %s%s", 
+               vty_out(vty, "  call control state: %s%s",
                        gsm48_cc_state_name(trans->cc.state), VTY_NEWLINE);
        }
 }
 
 
                        gsm48_cc_state_name(trans->cc.state), VTY_NEWLINE);
        }
 }
 
 
-DEFUN(show_ms, show_ms_cmd, "show ms [ms_name]",
+DEFUN(show_ms, show_ms_cmd, "show ms [MS_NAME]",
        SHOW_STR "Display available MS entities\n")
 {
        struct osmocom_ms *ms;
        SHOW_STR "Display available MS entities\n")
 {
        struct osmocom_ms *ms;
@@ -245,7 +267,7 @@ DEFUN(show_ms, show_ms_cmd, "show ms [ms_name]",
        return CMD_SUCCESS;
 }
 
        return CMD_SUCCESS;
 }
 
-DEFUN(show_support, show_support_cmd, "show support [ms_name]",
+DEFUN(show_support, show_support_cmd, "show support [MS_NAME]",
        SHOW_STR "Display information about MS support\n"
        "Name of MS (see \"show ms\")")
 {
        SHOW_STR "Display information about MS support\n"
        "Name of MS (see \"show ms\")")
 {
@@ -266,7 +288,7 @@ DEFUN(show_support, show_support_cmd, "show support [ms_name]",
        return CMD_SUCCESS;
 }
 
        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\")")
 {
        SHOW_STR "Display information about subscriber\n"
        "Name of MS (see \"show ms\")")
 {
@@ -299,43 +321,62 @@ DEFUN(show_cell, show_cell_cmd, "show cell MS_NAME",
        if (!ms)
                return CMD_WARNING;
 
        if (!ms)
                return CMD_WARNING;
 
-       gsm322_dump_cs_list(&ms->cellsel, GSM322_CS_FLAG_SYSINFO, print_vty,
+       gsm322_dump_cs_list(&ms->cellsel, GSM322_CS_FLAG_SUPPORT, print_vty,
                vty);
 
        return CMD_SUCCESS;
 }
 
                vty);
 
        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"
        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;
 {
        struct osmocom_ms *ms;
-       int i;
        struct gsm48_sysinfo *s;
        struct gsm48_sysinfo *s;
+       uint16_t arfcn = atoi(argv[1]);
 
        ms = get_ms(argv[0], vty);
        if (!ms)
                return CMD_WARNING;
 
 
        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;
        }
 
        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;
 }
 
 
        return CMD_SUCCESS;
 }
 
-DEFUN(show_ba, show_ba_cmd, "show ba MS_NAME [mcc] [mnc]",
+DEFUN(show_nbcells, show_nbcells_cmd, "show neighbour-cells MS_NAME",
+       SHOW_STR "Display information about current neighbour cells\n"
+       "Name of MS (see \"show ms\")")
+{
+       struct osmocom_ms *ms;
+
+       ms = get_ms(argv[0], vty);
+       if (!ms)
+               return CMD_WARNING;
+
+       gsm322_dump_nb_list(&ms->cellsel, print_vty, vty);
+
+       return CMD_SUCCESS;
+}
+
+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")
        SHOW_STR "Display information about band allocations\n"
        "Name of MS (see \"show ms\")\nMobile Country Code\n"
        "Mobile Network Code")
@@ -424,10 +465,10 @@ DEFUN(no_monitor_network, no_monitor_network_cmd, "no monitor network MS_NAME",
        return CMD_SUCCESS;
 }
 
        return CMD_SUCCESS;
 }
 
-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"
+DEFUN(sim_test, sim_test_cmd, "sim testcard MS_NAME [MCC] [MNC] [LAC] [TMSI]",
+       "SIM actions\nAttach bulit in test SIM\nName of MS (see \"show ms\")\n"
        "Mobile Country Code of RPLMN\nMobile Network Code of RPLMN\n"
        "Mobile Country Code of RPLMN\nMobile Network Code of RPLMN\n"
-       "Optionally locatio area code\nOptionally current assigned TMSI")
+       "Optionally location area code\nOptionally current assigned TMSI")
 {
        struct osmocom_ms *ms;
        uint16_t mcc = 0x001, mnc = 0x01f, lac = 0x0000;
 {
        struct osmocom_ms *ms;
        uint16_t mcc = 0x001, mnc = 0x01f, lac = 0x0000;
@@ -438,7 +479,7 @@ DEFUN(sim_test, sim_test_cmd, "sim testcard MS_NAME [mcc] [mnc] [lac] [tmsi]",
                return CMD_WARNING;
 
        if (ms->subscr.sim_valid) {
                return CMD_WARNING;
 
        if (ms->subscr.sim_valid) {
-               vty_out(vty, "SIM already presend, remove first!%s",
+               vty_out(vty, "SIM already attached, remove first!%s",
                        VTY_NEWLINE);
                return CMD_WARNING;
        }
                        VTY_NEWLINE);
                return CMD_WARNING;
        }
@@ -468,7 +509,7 @@ DEFUN(sim_test, sim_test_cmd, "sim testcard MS_NAME [mcc] [mnc] [lac] [tmsi]",
 }
 
 DEFUN(sim_reader, sim_reader_cmd, "sim reader MS_NAME",
 }
 
 DEFUN(sim_reader, sim_reader_cmd, "sim reader MS_NAME",
-       "SIM actions\nSelect SIM from reader\nName of MS (see \"show ms\")")
+       "SIM actions\nAttach SIM from reader\nName of MS (see \"show ms\")")
 {
        struct osmocom_ms *ms;
 
 {
        struct osmocom_ms *ms;
 
@@ -477,7 +518,7 @@ DEFUN(sim_reader, sim_reader_cmd, "sim reader MS_NAME",
                return CMD_WARNING;
 
        if (ms->subscr.sim_valid) {
                return CMD_WARNING;
 
        if (ms->subscr.sim_valid) {
-               vty_out(vty, "SIM already presend, remove first!%s",
+               vty_out(vty, "SIM already attached, remove first!%s",
                        VTY_NEWLINE);
                return CMD_WARNING;
        }
                        VTY_NEWLINE);
                return CMD_WARNING;
        }
@@ -488,7 +529,7 @@ DEFUN(sim_reader, sim_reader_cmd, "sim reader MS_NAME",
 }
 
 DEFUN(sim_remove, sim_remove_cmd, "sim remove MS_NAME",
 }
 
 DEFUN(sim_remove, sim_remove_cmd, "sim remove MS_NAME",
-       "SIM actions\nRemove SIM card\nName of MS (see \"show ms\")")
+       "SIM actions\nDetach SIM card\nName of MS (see \"show ms\")")
 {
        struct osmocom_ms *ms;
 
 {
        struct osmocom_ms *ms;
 
@@ -497,7 +538,7 @@ DEFUN(sim_remove, sim_remove_cmd, "sim remove MS_NAME",
                return CMD_WARNING;
 
        if (!ms->subscr.sim_valid) {
                return CMD_WARNING;
 
        if (!ms->subscr.sim_valid) {
-               vty_out(vty, "No Sim inserted!%s", VTY_NEWLINE);
+               vty_out(vty, "No SIM attached!%s", VTY_NEWLINE);
                return CMD_WARNING;
        }
 
                return CMD_WARNING;
        }
 
@@ -652,9 +693,11 @@ DEFUN(sim_lai, sim_lai_cmd, "sim lai MS_NAME MCC MNC LAC",
        return CMD_SUCCESS;
 }
 
        return CMD_SUCCESS;
 }
 
-DEFUN(network_select, network_select_cmd, "network select MS_NAME MCC MNC",
+DEFUN(network_select, network_select_cmd,
+       "network select MS_NAME MCC MNC [force]",
        "Select ...\nSelect Network\nName of MS (see \"show ms\")\n"
        "Select ...\nSelect Network\nName of MS (see \"show ms\")\n"
-       "Mobile Country Code\nMobile Network Code")
+       "Mobile Country Code\nMobile Network Code\n"
+       "Force selecting a network that is not in the list")
 {
        struct osmocom_ms *ms;
        struct gsm322_plmn *plmn;
 {
        struct osmocom_ms *ms;
        struct gsm322_plmn *plmn;
@@ -670,6 +713,12 @@ DEFUN(network_select, network_select_cmd, "network select MS_NAME MCC MNC",
                return CMD_WARNING;
        plmn = &ms->plmn;
 
                return CMD_WARNING;
        plmn = &ms->plmn;
 
+       if (ms->settings.plmn_mode != PLMN_MODE_MANUAL) {
+               vty_out(vty, "Not in manual network selection mode%s",
+                       VTY_NEWLINE);
+               return CMD_WARNING;
+       }
+
        if (!mcc) {
                vty_out(vty, "Given MCC invalid%s", VTY_NEWLINE);
                return CMD_WARNING;
        if (!mcc) {
                vty_out(vty, "Given MCC invalid%s", VTY_NEWLINE);
                return CMD_WARNING;
@@ -679,12 +728,16 @@ DEFUN(network_select, network_select_cmd, "network select MS_NAME MCC MNC",
                return CMD_WARNING;
        }
 
                return CMD_WARNING;
        }
 
-       llist_for_each_entry(temp, &plmn->sorted_plmn, entry)
-               if (temp->mcc == mcc &&  temp->mnc == mnc)
-                       found = 1;
-       if (!found) {
-               vty_out(vty, "Network not in list!%s", VTY_NEWLINE);
-               return CMD_WARNING;
+       if (argc < 4) {
+               llist_for_each_entry(temp, &plmn->sorted_plmn, entry)
+                       if (temp->mcc == mcc &&  temp->mnc == mnc)
+                               found = 1;
+               if (!found) {
+                       vty_out(vty, "Network not in list!%s", VTY_NEWLINE);
+                       vty_out(vty, "To force selecting this network, use "
+                               "'force' keyword%s", VTY_NEWLINE);
+                       return CMD_WARNING;
+               }
        }
 
        nmsg = gsm322_msgb_alloc(GSM322_EVENT_CHOOSE_PLMN);
        }
 
        nmsg = gsm322_msgb_alloc(GSM322_EVENT_CHOOSE_PLMN);
@@ -746,7 +799,7 @@ DEFUN(call, call_cmd, "call MS_NAME (NUMBER|emergency|answer|hangup|hold)",
        return CMD_SUCCESS;
 }
 
        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")
 {
        "Make a call\nName of MS (see \"show ms\")\n"
        "Retrieve call on hold\nNumber of call to retrieve")
 {
@@ -784,6 +837,60 @@ DEFUN(call_dtmf, call_dtmf_cmd, "call MS_NAME dtmf DIGITS",
        return CMD_SUCCESS;
 }
 
        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) {
+               vty_out(vty, "Given MCC invalid%s", VTY_NEWLINE);
+               return CMD_WARNING;
+       }
+       if (!mnc) {
+               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\")")
 DEFUN(network_show, network_show_cmd, "network show MS_NAME",
        "Network ...\nShow results of network search (again)\n"
        "Name of MS (see \"show ms\")")
@@ -835,12 +942,12 @@ DEFUN(network_search, network_search_cmd, "network search MS_NAME",
 DEFUN(cfg_gps_enable, cfg_gps_enable_cmd, "gps enable",
        "GPS receiver")
 {
 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;
        }
                vty_out(vty, "Failed to open GPS device!%s", VTY_NEWLINE);
                return CMD_WARNING;
        }
-       gps.enable = 1;
+       g.enable = 1;
 
        return CMD_SUCCESS;
 }
 
        return CMD_SUCCESS;
 }
@@ -848,22 +955,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")
 {
 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;
 }
 
        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/")
 {
 
 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;
                        vty_out(vty, "Failed to open GPS device!%s",
                                VTY_NEWLINE);
                        return CMD_WARNING;
@@ -878,13 +1017,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 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
        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;
                        vty_out(vty, "Failed to open GPS device!%s",
                                VTY_NEWLINE);
                        return CMD_WARNING;
@@ -894,6 +1033,22 @@ DEFUN(cfg_gps_baud, cfg_gps_baud_cmd, "gps baudrate "
        return CMD_SUCCESS;
 }
 
        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\")")
 /* per MS config */
 DEFUN(cfg_ms, cfg_ms_cmd, "ms MS_NAME",
        "Select a mobile station to configure\nName of MS (see \"show ms\")")
@@ -1012,8 +1167,9 @@ DEFUN(cfg_no_ms, cfg_no_ms_cmd, "no ms MS_NAME",
 
 #define SUP_WRITE(item, cmd) \
        if (sup->item) \
 
 #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(struct vty *vty, struct osmocom_ms *ms)
 {
 
 static void config_write_ms(struct vty *vty, struct osmocom_ms *ms)
 {
@@ -1044,17 +1200,26 @@ static void config_write_ms(struct vty *vty, struct osmocom_ms *ms)
                vty_out(vty, " imei-random %d%s", set->imei_random,
                        VTY_NEWLINE);
        else
                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
        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, " %sauto-answer%s", (set->auto_answer) ? "" : "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",
        if (set->alter_tx_power)
                if (set->alter_tx_power_value)
                        vty_out(vty, " tx-power %d%s",
@@ -1062,21 +1227,27 @@ static void config_write_ms(struct vty *vty, struct osmocom_ms *ms)
                else
                        vty_out(vty, " tx-power full%s", VTY_NEWLINE);
        else
                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
        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)
        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_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 (!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",
        if (set->full_v1 || set->full_v2 || set->full_v3) {
                /* mandatory anyway */
                vty_out(vty, " codec full-speed%s%s",
@@ -1091,9 +1262,10 @@ static void config_write_ms(struct vty *vty, struct osmocom_ms *ms)
                else
                        vty_out(vty, " no codec half-speed%s", VTY_NEWLINE);
        }
                else
                        vty_out(vty, " no codec half-speed%s", VTY_NEWLINE);
        }
-       if (llist_empty(&set->abbrev))
-               vty_out(vty, " no abbrev%s", VTY_NEWLINE);
-       else {
+       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]) ? " " : "",
                llist_for_each_entry(abbrev, &set->abbrev, list)
                        vty_out(vty, " abbrev %s %s%s%s%s", abbrev->abbrev,
                                abbrev->number, (abbrev->name[0]) ? " " : "",
@@ -1111,43 +1283,76 @@ static void config_write_ms(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(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(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");
        }
        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);
+       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, " 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:
                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;
        }
                break;
        }
-       vty_out(vty, "  %sbarred-access%s", (set->test_barr) ? "" : "no ",
-               VTY_NEWLINE);
+       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),
        if (set->test_rplmn_valid) {
                vty_out(vty, "  rplmn %s %s",
                        gsm_print_mcc(set->test_rplmn_mcc),
@@ -1158,10 +1363,14 @@ static void config_write_ms(struct vty *vty, struct osmocom_ms *ms)
                        vty_out(vty, " 0x%08x", set->test_tmsi);
                vty_out(vty, "%s", VTY_NEWLINE);
        } else
                        vty_out(vty, " 0x%08x", set->test_tmsi);
                vty_out(vty, "%s", 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);
+               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);
        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, " %sshutdown%s", (ms->shutdown) ? "" : "no ",
                VTY_NEWLINE);
        vty_out(vty, "exit%s", VTY_NEWLINE);
@@ -1172,12 +1381,20 @@ static int config_write(struct vty *vty)
 {
        struct osmocom_ms *ms;
 
 {
        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);
        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)
        vty_out(vty, "!%s", VTY_NEWLINE);
 
        llist_for_each_entry(ms, &ms_list, entity)
@@ -1225,8 +1442,8 @@ DEFUN(cfg_ms_sap, cfg_ms_sap_cmd, "sap-socket PATH",
 }
 
 DEFUN(cfg_ms_sim, cfg_ms_sim_cmd, "sim (none|reader|test)",
 }
 
 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")
+       "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;
 {
        struct osmocom_ms *ms = vty->index;
        struct gsm_settings *set = &ms->settings;
@@ -1246,7 +1463,8 @@ DEFUN(cfg_ms_sim, cfg_ms_sim_cmd, "sim (none|reader|test)",
                return CMD_WARNING;
        }
 
                return CMD_WARNING;
        }
 
-       vty_restart(vty, ms);
+       vty_restart_if_started(vty, ms);
+
        return CMD_SUCCESS;
 }
 
        return CMD_SUCCESS;
 }
 
@@ -1258,21 +1476,20 @@ DEFUN(cfg_ms_mode, cfg_ms_mode_cmd, "network-selection-mode (auto|manual)",
        struct gsm_settings *set = &ms->settings;
        struct msgb *nmsg;
 
        struct gsm_settings *set = &ms->settings;
        struct msgb *nmsg;
 
-       if (!ms->plmn.state) {
+       if (!ms->started) {
                if (argv[0][0] == 'a')
                        set->plmn_mode = PLMN_MODE_AUTO;
                else
                        set->plmn_mode = PLMN_MODE_MANUAL;
                if (argv[0][0] == 'a')
                        set->plmn_mode = PLMN_MODE_AUTO;
                else
                        set->plmn_mode = PLMN_MODE_MANUAL;
-
-               return CMD_SUCCESS;
+       } 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);
        }
        }
-       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;
 }
 
        return CMD_SUCCESS;
 }
@@ -1309,7 +1526,6 @@ DEFUN(cfg_ms_imei_fixed, cfg_ms_imei_fixed_cmd, "imei-fixed",
 
        set->imei_random = 0;
 
 
        set->imei_random = 0;
 
-       vty_restart(vty, ms);
        return CMD_SUCCESS;
 }
 
        return CMD_SUCCESS;
 }
 
@@ -1322,7 +1538,6 @@ DEFUN(cfg_ms_imei_random, cfg_ms_imei_random_cmd, "imei-random <0-15>",
 
        set->imei_random = atoi(argv[0]);
 
 
        set->imei_random = atoi(argv[0]);
 
-       vty_restart(vty, ms);
        return CMD_SUCCESS;
 }
 
        return CMD_SUCCESS;
 }
 
@@ -1502,14 +1717,24 @@ DEFUN(cfg_ms_no_sim_delay, cfg_ms_no_sim_delay_cmd, "no simulated-delay",
        return CMD_SUCCESS;
 }
 
        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;
 {
        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 = 1;
-       set->stick_arfcn = atoi(argv[0]);
+       set->stick_arfcn = arfcn;
 
        return CMD_SUCCESS;
 }
 
        return CMD_SUCCESS;
 }
@@ -1629,7 +1854,7 @@ DEFUN(cfg_no_codec_half, cfg_ms_no_codec_half_cmd, "no codec half-speed",
        return CMD_SUCCESS;
 }
 
        return CMD_SUCCESS;
 }
 
-DEFUN(cfg_abbrev, cfg_ms_abbrev_cmd, "abbrev ABBREVIATION NUMBER [name]",
+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"
        "Store given abbreviation number\n1-3 digits abbreviation\n"
        "Number to store for the abbreviation "
        "(Use digits '0123456789*#abc', and '+' to dial international)\n"
@@ -1678,7 +1903,7 @@ DEFUN(cfg_abbrev, cfg_ms_abbrev_cmd, "abbrev ABBREVIATION NUMBER [name]",
        return CMD_SUCCESS;
 }
 
        return CMD_SUCCESS;
 }
 
-DEFUN(cfg_no_abbrev, cfg_ms_no_abbrev_cmd, "no abbrev [abbreviation]",
+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")
 {
        NO_STR "Remove given abbreviation number or all numbers\n"
        "Abbreviation number to remove")
 {
@@ -1703,6 +1928,33 @@ DEFUN(cfg_no_abbrev, cfg_ms_no_abbrev_cmd, "no abbrev [abbreviation]",
        return CMD_SUCCESS;
 }
 
        return CMD_SUCCESS;
 }
 
+DEFUN(cfg_ms_neighbour, cfg_ms_neighbour_cmd, "neighbour-measurement",
+       "Allow neighbour cell measurement in idle mode")
+{
+       struct osmocom_ms *ms = vty->index;
+       struct gsm_settings *set = &ms->settings;
+
+       set->no_neighbour = 0;
+
+       vty_restart_if_started(vty, ms);
+
+
+       return CMD_SUCCESS;
+}
+
+DEFUN(cfg_ms_no_neighbour, cfg_ms_no_neighbour_cmd, "no neighbour-measurement",
+       NO_STR "Do not allow neighbour cell measurement in idle mode")
+{
+       struct osmocom_ms *ms = vty->index;
+       struct gsm_settings *set = &ms->settings;
+
+       set->no_neighbour = 1;
+
+       vty_restart_if_started(vty, ms);
+
+       return CMD_SUCCESS;
+}
+
 static int config_write_dummy(struct vty *vty)
 {
        return CMD_SUCCESS;
 static int config_write_dummy(struct vty *vty)
 {
        return CMD_SUCCESS;
@@ -1792,7 +2044,7 @@ SUP_DI(cfg_ms_sup_no_a5_5, cfg_ms_sup_no_a5_5_cmd, a5_5, "a5/5", "A5/5", 0);
 SUP_EN(cfg_ms_sup_a5_6, cfg_ms_sup_a5_6_cmd, a5_6, "a5/6", "A5/6", 0);
 SUP_DI(cfg_ms_sup_no_a5_6, cfg_ms_sup_no_a5_6_cmd, a5_6, "a5/6", "A5/6", 0);
 SUP_EN(cfg_ms_sup_a5_7, cfg_ms_sup_a5_7_cmd, a5_7, "a5/7", "A5/7", 0);
 SUP_EN(cfg_ms_sup_a5_6, cfg_ms_sup_a5_6_cmd, a5_6, "a5/6", "A5/6", 0);
 SUP_DI(cfg_ms_sup_no_a5_6, cfg_ms_sup_no_a5_6_cmd, a5_6, "a5/6", "A5/6", 0);
 SUP_EN(cfg_ms_sup_a5_7, cfg_ms_sup_a5_7_cmd, a5_7, "a5/7", "A5/7", 0);
-SUP_DI(cfg_ms_sup_no_a5_7, cfg_ms_sup_no_a5_7_cmd, a5_7, "a5/7", "A5/7", 1);
+SUP_DI(cfg_ms_sup_no_a5_7, cfg_ms_sup_no_a5_7_cmd, a5_7, "a5/7", "A5/7", 0);
 SUP_EN(cfg_ms_sup_p_gsm, cfg_ms_sup_p_gsm_cmd, p_gsm, "p-gsm", "P-GSM (900)",
        1);
 SUP_DI(cfg_ms_sup_no_p_gsm, cfg_ms_sup_no_p_gsm_cmd, p_gsm, "p-gsm",
 SUP_EN(cfg_ms_sup_p_gsm, cfg_ms_sup_p_gsm_cmd, p_gsm, "p-gsm", "P-GSM (900)",
        1);
 SUP_DI(cfg_ms_sup_no_p_gsm, cfg_ms_sup_no_p_gsm_cmd, p_gsm, "p-gsm",
@@ -1805,11 +2057,25 @@ SUP_EN(cfg_ms_sup_r_gsm, cfg_ms_sup_r_gsm_cmd, r_gsm, "r-gsm", "R-GSM (850)",
        1);
 SUP_DI(cfg_ms_sup_no_r_gsm, cfg_ms_sup_no_r_gsm_cmd, r_gsm, "r-gsm",
        "R-GSM (850)", 1);
        1);
 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_dcs, cfg_ms_sup_dcs_cmd, dcs, "dcs", "DCS (1800)", 1);
+SUP_DI(cfg_ms_sup_no_dcs, cfg_ms_sup_no_dcs_cmd, dcs, "dcs", "DCS (1800)", 1);
+SUP_EN(cfg_ms_sup_gsm_850, cfg_ms_sup_gsm_850_cmd, gsm_850, "gsm-850",
+       "GSM 850", 1);
+SUP_DI(cfg_ms_sup_no_gsm_850, cfg_ms_sup_no_gsm_850_cmd, gsm_850, "gsm-850",
+       "GSM 850", 1);
+SUP_EN(cfg_ms_sup_pcs, cfg_ms_sup_pcs_cmd, pcs, "pcs", "PCS (1900)", 1);
+SUP_DI(cfg_ms_sup_no_pcs, cfg_ms_sup_no_pcs_cmd, pcs, "pcs", "PCS (1900)", 1);
+SUP_EN(cfg_ms_sup_gsm_480, cfg_ms_sup_gsm_480_cmd, gsm_480, "gsm-480",
+       "GSM 480", 1);
+SUP_DI(cfg_ms_sup_no_gsm_480, cfg_ms_sup_no_gsm_480_cmd, gsm_480, "gsm-480",
+       "GSM 480", 1);
+SUP_EN(cfg_ms_sup_gsm_450, cfg_ms_sup_gsm_450_cmd, gsm_450, "gsm-450",
+       "GSM 450", 1);
+SUP_DI(cfg_ms_sup_no_gsm_450, cfg_ms_sup_no_gsm_450_cmd, gsm_450, "gsm-450",
+       "GSM 450", 1);
 
 DEFUN(cfg_ms_sup_class_900, cfg_ms_sup_class_900_cmd, "class-900 (1|2|3|4|5)",
 
 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"
        "20 Watts\n"
        "8 Watts\n"
        "5 Watts\n"
@@ -1823,7 +2089,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)
        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;
                        " by hardware!%s", VTY_NEWLINE);
 
        return CMD_SUCCESS;
@@ -1843,7 +2151,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)
 
        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"
+       "2 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;
                        " by hardware!%s", VTY_NEWLINE);
 
        return CMD_SUCCESS;
@@ -1871,9 +2199,9 @@ DEFUN(cfg_ms_sup_ch_cap, cfg_ms_sup_ch_cap_cmd, "channel-capability "
                return CMD_WARNING;
        }
 
                return CMD_WARNING;
        }
 
-       if (ch_cap != set->ch_cap
+       if (ms->started && ch_cap != set->ch_cap
         && (ch_cap == GSM_CAP_SDCCH || set->ch_cap == GSM_CAP_SDCCH))
         && (ch_cap == GSM_CAP_SDCCH || set->ch_cap == GSM_CAP_SDCCH))
-               vty_restart(vty, ms);
+               vty_restart_if_started(vty, ms);
 
        set->ch_cap = ch_cap;
 
 
        set->ch_cap = ch_cap;
 
@@ -1927,6 +2255,30 @@ DEFUN(cfg_ms_sup_dsc_max, cfg_ms_sup_dsc_max_cmd, "dsc-max <90-500>",
        return CMD_SUCCESS;
 }
 
        return CMD_SUCCESS;
 }
 
+DEFUN(cfg_ms_sup_skip_max_per_band, cfg_ms_sup_skip_max_per_band_cmd,
+       "skip-max-per-band",
+       "Scan all frequencies per band, not only a maximum number")
+{
+       struct osmocom_ms *ms = vty->index;
+       struct gsm_settings *set = &ms->settings;
+
+       set->skip_max_per_band = 1;
+
+       return CMD_SUCCESS;
+}
+
+DEFUN(cfg_ms_sup_no_skip_max_per_band, cfg_ms_sup_no_skip_max_per_band_cmd,
+       "no skip-max-per-band",
+       NO_STR "Scan only a maximum number of frequencies per band")
+{
+       struct osmocom_ms *ms = vty->index;
+       struct gsm_settings *set = &ms->settings;
+
+       set->skip_max_per_band = 0;
+
+       return CMD_SUCCESS;
+}
+
 /* per testsim config */
 DEFUN(cfg_ms_testsim, cfg_ms_testsim_cmd, "test-sim",
        "Configure test SIM emulation")
 /* per testsim config */
 DEFUN(cfg_ms_testsim, cfg_ms_testsim_cmd, "test-sim",
        "Configure test SIM emulation")
@@ -1950,7 +2302,8 @@ DEFUN(cfg_test_imsi, cfg_test_imsi_cmd, "imsi IMSI",
 
        strcpy(set->test_imsi, argv[0]);
 
 
        strcpy(set->test_imsi, argv[0]);
 
-       vty_restart(vty, ms);
+       vty_restart_if_started(vty, ms);
+
        return CMD_SUCCESS;
 }
 
        return CMD_SUCCESS;
 }
 
@@ -2042,11 +2395,12 @@ DEFUN(cfg_test_no_rplmn, cfg_test_no_rplmn_cmd, "no rplmn",
 
        set->test_rplmn_valid = 0;
 
 
        set->test_rplmn_valid = 0;
 
-       vty_restart(vty, ms);
+       vty_restart_if_started(vty, ms);
+
        return CMD_SUCCESS;
 }
 
        return CMD_SUCCESS;
 }
 
-DEFUN(cfg_test_rplmn, cfg_test_rplmn_cmd, "rplmn MCC MNC [lac] [tmsi]",
+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")
        "Set Registered PLMN\nMobile Country Code\nMobile Network Code\n"
        "Optionally set locatio area code\n"
        "Optionally set current assigned TMSI")
@@ -2078,7 +2432,8 @@ DEFUN(cfg_test_rplmn, cfg_test_rplmn_cmd, "rplmn MCC MNC [lac] [tmsi]",
        else
                set->test_tmsi = 0xffffffff;
 
        else
                set->test_tmsi = 0xffffffff;
 
-       vty_restart(vty, ms);
+       vty_restart_if_started(vty, ms);
+
        return CMD_SUCCESS;
 }
 
        return CMD_SUCCESS;
 }
 
@@ -2099,7 +2454,8 @@ DEFUN(cfg_test_hplmn, cfg_test_hplmn_cmd, "hplmn-search (everywhere|foreign-coun
                break;
        }
 
                break;
        }
 
-       vty_restart(vty, ms);
+       vty_restart_if_started(vty, ms);
+
        return CMD_SUCCESS;
 }
 
        return CMD_SUCCESS;
 }
 
@@ -2230,7 +2586,7 @@ gDEFUN(ournode_end,
 DEFUN(off, off_cmd, "off",
        "Turn mobiles off (shutdown) and exit")
 {
 DEFUN(off, off_cmd, "off",
        "Turn mobiles off (shutdown) and exit")
 {
-       dispatch_signal(SS_GLOBAL, S_GLOBAL_SHUTDOWN, NULL);
+       osmo_signal_dispatch(SS_GLOBAL, S_GLOBAL_SHUTDOWN, NULL);
 
        return CMD_SUCCESS;
 }
 
        return CMD_SUCCESS;
 }
@@ -2245,6 +2601,7 @@ int ms_vty_init(void)
        install_element_ve(&show_support_cmd);
        install_element_ve(&show_cell_cmd);
        install_element_ve(&show_cell_si_cmd);
        install_element_ve(&show_support_cmd);
        install_element_ve(&show_cell_cmd);
        install_element_ve(&show_cell_si_cmd);
+       install_element_ve(&show_nbcells_cmd);
        install_element_ve(&show_ba_cmd);
        install_element_ve(&show_forb_la_cmd);
        install_element_ve(&show_forb_plmn_cmd);
        install_element_ve(&show_ba_cmd);
        install_element_ve(&show_forb_la_cmd);
        install_element_ve(&show_forb_plmn_cmd);
@@ -2267,12 +2624,20 @@ int ms_vty_init(void)
        install_element(ENABLE_NODE, &call_cmd);
        install_element(ENABLE_NODE, &call_retr_cmd);
        install_element(ENABLE_NODE, &call_dtmf_cmd);
        install_element(ENABLE_NODE, &call_cmd);
        install_element(ENABLE_NODE, &call_retr_cmd);
        install_element(ENABLE_NODE, &call_dtmf_cmd);
+       install_element(ENABLE_NODE, &test_reselection_cmd);
+       install_element(ENABLE_NODE, &delete_forbidden_plmn_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_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_ms_cmd);
        install_element(CONFIG_NODE, &cfg_ms_create_cmd);
        install_element(CONFIG_NODE, &cfg_ms_rename_cmd);
@@ -2316,6 +2681,8 @@ int ms_vty_init(void)
        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_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_neighbour_cmd);
+       install_element(MS_NODE, &cfg_ms_no_neighbour_cmd);
        install_element(MS_NODE, &cfg_ms_support_cmd);
        install_node(&support_node, config_write_dummy);
        install_default(SUPPORT_NODE);
        install_element(MS_NODE, &cfg_ms_support_cmd);
        install_node(&support_node, config_write_dummy);
        install_default(SUPPORT_NODE);
@@ -2347,8 +2714,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_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_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);
        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);
@@ -2362,6 +2740,8 @@ int ms_vty_init(void)
        install_element(SUPPORT_NODE, &cfg_ms_sup_no_half_v3_cmd);
        install_element(SUPPORT_NODE, &cfg_ms_sup_min_rxlev_cmd);
        install_element(SUPPORT_NODE, &cfg_ms_sup_dsc_max_cmd);
        install_element(SUPPORT_NODE, &cfg_ms_sup_no_half_v3_cmd);
        install_element(SUPPORT_NODE, &cfg_ms_sup_min_rxlev_cmd);
        install_element(SUPPORT_NODE, &cfg_ms_sup_dsc_max_cmd);
+       install_element(SUPPORT_NODE, &cfg_ms_sup_skip_max_per_band_cmd);
+       install_element(SUPPORT_NODE, &cfg_ms_sup_no_skip_max_per_band_cmd);
        install_node(&testsim_node, config_write_dummy);
        install_default(TESTSIM_NODE);
        install_element(TESTSIM_NODE, &ournode_exit_cmd);
        install_node(&testsim_node, config_write_dummy);
        install_default(TESTSIM_NODE);
        install_element(TESTSIM_NODE, &ournode_exit_cmd);