[layer23] Added support for multiple MS instances
authorAndreas.Eversberg <jolly@eversberg.eu>
Sat, 13 Nov 2010 18:45:09 +0000 (18:45 +0000)
committerAndreas.Eversberg <jolly@eversberg.eu>
Sat, 13 Nov 2010 18:45:09 +0000 (18:45 +0000)
To create another instance: 'ms <name> create'

To remove an instance: 'no ms <name>'

If no instance exists, 'ms 1' is created automatically on startup.

Each instance can be enabled / disabled by using 'shutdown' or
'no shutdown'. Multiple instances may share the same layer2 socket (same
phone hardware), but in this case only one instance can be enabled at the
same time. This makes it much easier to select different settings without
modifying them.

A 'shutdown' initiates the IMSI detach procedure before shutdown is
completed. A 'shutdown force' will immidiately shutdown.

There is no need to restart the software anymore, if fundamental settings
are changed. In this case, a 'shutdown' followed by a 'no shutdown' will
do the job.

If you already have an old osmocom.cfg, you need to "no shutdown" it.
Everything else behaves as before.

12 files changed:
src/host/layer23/include/osmocom/bb/common/osmocom_data.h
src/host/layer23/include/osmocom/bb/mobile/gsm322.h
src/host/layer23/include/osmocom/bb/mobile/gsm48_mm.h
src/host/layer23/include/osmocom/bb/mobile/settings.h
src/host/layer23/src/common/l1l2_interface.c
src/host/layer23/src/mobile/Makefile.am
src/host/layer23/src/mobile/app_mobile.c
src/host/layer23/src/mobile/gsm322.c
src/host/layer23/src/mobile/gsm48_mm.c
src/host/layer23/src/mobile/main.c [new file with mode: 0644]
src/host/layer23/src/mobile/settings.c
src/host/layer23/src/mobile/vty_interface.c

index 77a6067..da35cdb 100644 (file)
@@ -53,6 +53,7 @@ struct osmocom_ms {
        struct write_queue l2_wq, sap_wq;
        uint16_t test_arfcn;
 
+       uint8_t delete, shutdown, started;
        struct gsm_support support;
        struct gsm_settings settings;
        struct gsm_subscriber subscr;
@@ -70,9 +71,10 @@ struct osmocom_ms {
 
 enum osmobb_sig_subsys {
        SS_L1CTL,
+       SS_GLOBAL,
 };
 
-enum osmobb_meas_sig {
+enum osmobb_l1ctl_sig {
        S_L1CTL_FBSB_ERR,
        S_L1CTL_FBSB_RESP,
        S_L1CTL_RESET,
@@ -83,6 +85,10 @@ enum osmobb_meas_sig {
        S_L1CTL_LOSS_IND,
 };
 
+enum osmobb_global_sig {
+       S_GLOBAL_SHUTDOWN,
+};
+
 struct osmobb_fbsb_res {
        struct osmocom_ms *ms;
        int8_t snr;
index 78e380f..467ff39 100644 (file)
@@ -196,6 +196,8 @@ void start_loss_timer(struct gsm322_cellsel *cs, int sec, int micro);
 extern const char *plmn_a_state_names[];
 extern const char *plmn_m_state_names[];
 extern const char *cs_state_names[];
+int gsm322_l1_signal(unsigned int subsys, unsigned int signal,
+                    void *handler_data, void *signal_data);
 
 char *gsm_print_rxlev(uint8_t rxlev); 
 
index 0d18182..447dc95 100644 (file)
@@ -191,7 +191,6 @@ struct gsm48_mmlayer {
        /* other */
        uint8_t                 est_cause; /* cause of establishment msg */
        int                     mr_substate;    /* rem most recent substate */
-       uint8_t                 power_off; /* set, if power off after detach */
        uint8_t                 power_off_idle; /* waits for IDLE before po */
 };
 
index 178ef08..d0848a8 100644 (file)
@@ -8,6 +8,9 @@ enum {
 };
 
 struct gsm_settings {
+       char                    layer2_socket_path[128];
+       char                    sap_socket_path[128];
+
        /* IMEI */
        char                    imei[16];
        char                    imeisv[17];
index 28356da..9d31532 100644 (file)
@@ -131,6 +131,7 @@ int layer2_open(struct osmocom_ms *ms, const char *socket_path)
        rc = bsc_register_fd(&ms->l2_wq.bfd);
        if (rc != 0) {
                fprintf(stderr, "Failed to register fd.\n");
+               close(ms->l2_wq.bfd.fd);
                return rc;
        }
 
index bd98baf..12f0f76 100644 (file)
@@ -9,7 +9,7 @@ libmobile_a_SOURCES = gsm322.c gsm48_cc.c gsm48_mm.c gsm48_rr.c \
 
 bin_PROGRAMS = mobile
 
-mobile_SOURCES = ../common/main.c app_mobile.c
+mobile_SOURCES = main.c app_mobile.c
 mobile_LDADD = libmobile.a $(LDADD)
 
 
index 6abb870..293d135 100644 (file)
 
 #include <errno.h>
 #include <signal.h>
-#include <time.h>
 
 #include <osmocom/bb/common/osmocom_data.h>
+#include <osmocom/bb/common/l1l2_interface.h>
 #include <osmocom/bb/common/l1ctl.h>
-#include <osmocom/bb/common/l23_app.h>
 #include <osmocom/bb/common/lapdm.h>
 #include <osmocom/bb/common/logging.h>
-#include <osmocom/bb/common/gps.h>
 #include <osmocom/bb/mobile/gsm48_rr.h>
 #include <osmocom/bb/mobile/vty.h>
 #include <osmocom/vty/telnet_interface.h>
 #include <osmocore/msgb.h>
 #include <osmocore/talloc.h>
 #include <osmocore/select.h>
-#include <osmocore/signal.h>
-
-extern struct log_target *stderr_target;
-static const char *config_file = "/etc/osmocom/osmocom.cfg";
-extern void *l23_ctx;
-extern unsigned short vty_port;
-extern int vty_reading;
-
-int mobile_started = 0;
 
 int mncc_recv_mobile(struct osmocom_ms *ms, int msg_type, void *arg);
 int mncc_recv_dummy(struct osmocom_ms *ms, int msg_type, void *arg);
+extern int (*l23_app_exit) (struct osmocom_ms *ms, int force);
 
 int mobile_work(struct osmocom_ms *ms)
 {
@@ -73,7 +63,7 @@ int mobile_work(struct osmocom_ms *ms)
        return work;
 }
 
-static int signal_cb(unsigned int subsys, unsigned int signal,
+int mobile_signal_cb(unsigned int subsys, unsigned int signal,
                     void *handler_data, void *signal_data)
 {
        struct osmocom_ms *ms;
@@ -85,12 +75,12 @@ static int signal_cb(unsigned int subsys, unsigned int signal,
 
        switch (signal) {
        case S_L1CTL_RESET:
-               if (mobile_started)
-                       break;
-
                ms = signal_data;
                set = &ms->settings;
 
+               if (ms->started)
+                       break;
+
                /* insert test card, if enabled */
                switch (set->sim_type) {
                case GSM_SIM_TYPE_READER:
@@ -113,19 +103,19 @@ static int signal_cb(unsigned int subsys, unsigned int signal,
                        gsm322_cs_sendmsg(ms, nmsg);
                }
 
-               mobile_started = 1;
+               ms->started = 1;
        }
        return 0;
 }
 
-int mobile_exit(struct osmocom_ms *ms)
+int mobile_exit(struct osmocom_ms *ms, int force)
 {
        struct gsm48_mmlayer *mm = &ms->mmlayer;
 
-       if (!mm->power_off && mobile_started) {
+       if (!force && ms->started) {
                struct msgb *nmsg;
 
-               mm->power_off = 1;
+               ms->shutdown = 1; /* going down */
                nmsg = gsm48_mmevent_msgb_alloc(GSM48_MM_EVENT_IMSI_DETACH);
                if (!nmsg)
                        return -ENOMEM;
@@ -134,48 +124,30 @@ int mobile_exit(struct osmocom_ms *ms)
                return -EBUSY;
        }
 
-       /* in case there is a lockup during exit */
-       signal(SIGINT, SIG_DFL);
-       signal(SIGHUP, SIG_DFL);
-       signal(SIGTERM, SIG_DFL);
-       signal(SIGPIPE, SIG_DFL);
-
-       unregister_signal_handler(SS_L1CTL, &signal_cb, NULL);
-       gps_close();
        gsm322_exit(ms);
        gsm48_mm_exit(ms);
        gsm48_rr_exit(ms);
        gsm_subscr_exit(ms);
        gsm48_cc_exit(ms);
        gsm_sim_exit(ms);
-       gsm_settings_exit(ms);
+       lapdm_exit(&ms->l2_entity.lapdm_acch);
+       lapdm_exit(&ms->l2_entity.lapdm_dcch);
 
-       printf("Power off!\n");
+       ms->shutdown = 2; /* being down */
+       vty_notify(ms, NULL);
+       vty_notify(ms, "Power off!\n");
+       printf("Power off! (MS %s)\n", ms->name);
 
        return 0;
 }
 
-static struct vty_app_info vty_info = {
-       .name = "OsmocomBB",
-       .version = PACKAGE_VERSION,
-       .go_parent_cb = ms_vty_go_parent,
-};
-
 int l23_app_init(struct osmocom_ms *ms)
 {
        int rc;
-       struct telnet_connection dummy_conn;
 
-//     log_parse_category_mask(stderr_target, "DL1C:DRSL:DLAPDM:DCS:DPLMN:DRR:DMM:DSIM:DCC:DMNCC:DPAG:DSUM");
-       log_parse_category_mask(stderr_target, "DCS:DPLMN:DRR:DMM:DSIM:DCC:DMNCC:DPAG:DSUM");
-       log_set_log_level(stderr_target, LOGL_INFO);
-
-       srand(time(NULL));
-
-       gps_init();
-       gsm_support_init(ms);
+       lapdm_init(&ms->l2_entity.lapdm_dcch, ms);
+       lapdm_init(&ms->l2_entity.lapdm_acch, ms);
        gsm_sim_init(ms);
-       gsm_settings_init(ms);
        gsm48_cc_init(ms);
        gsm_subscr_init(ms);
        gsm48_rr_init(ms);
@@ -183,38 +155,36 @@ int l23_app_init(struct osmocom_ms *ms)
        INIT_LLIST_HEAD(&ms->trans_list);
        gsm322_init(ms);
 
-       l23_app_work = mobile_work;
-       register_signal_handler(SS_L1CTL, &signal_cb, NULL);
-       l23_app_exit = mobile_exit;
-
-       vty_init(&vty_info);
-       ms_vty_init();
-       dummy_conn.priv = NULL;
-       vty_reading = 1;
-       rc = vty_read_config_file(config_file, &dummy_conn);
+       rc = layer2_open(ms, ms->settings.layer2_socket_path);
        if (rc < 0) {
-               fprintf(stderr, "Failed to parse the config file: '%s'\n",
-                       config_file);
-               fprintf(stderr, "Please check or create config file using: "
-                       "'touch %s'\n", config_file);
+               fprintf(stderr, "Failed during layer2_open()\n");
+               ms->l2_wq.bfd.fd = -1;
+               l23_app_exit(ms, 1);
                return rc;
        }
-       vty_reading = 0;
-       telnet_init(l23_ctx, NULL, vty_port);
-       if (rc < 0)
+
+#if 0
+       rc = sap_open(ms, ms->settings.sap_socket_path);
+       if (rc < 0) {
+               fprintf(stderr, "Failed during sap_open(), no SIM reader\n");
+               ms->sap_wq.bfd.fd = -1;
+               l23_app_exit(ms, 1);
                return rc;
+       }
+#endif
 
        if (ms->settings.ch_cap == GSM_CAP_SDCCH)
                ms->cclayer.mncc_recv = mncc_recv_dummy;
        else
                ms->cclayer.mncc_recv = mncc_recv_mobile;
 
-       printf("VTY available on port %u.\n", vty_port);
-
        gsm_random_imei(&ms->settings);
 
+       ms->shutdown = 0;
+       ms->started = 0;
+
        l1ctl_tx_reset_req(ms, L1CTL_RES_T_FULL);
-       printf("Mobile initialized, please start phone now!\n");
+       printf("Mobile '%s' initialized, please start phone now!\n", ms->name);
        return 0;
 }
 
index 0b45f60..751b8b4 100644 (file)
 
 #include <osmocom/bb/common/logging.h>
 #include <osmocom/bb/common/l1ctl.h>
-#include <osmocom/bb/common/l23_app.h>
 #include <osmocom/bb/common/osmocom_data.h>
 #include <osmocom/bb/common/networks.h>
 #include <osmocom/bb/mobile/vty.h>
 
 extern void *l23_ctx;
+extern int (*l23_app_exit) (struct osmocom_ms *ms, int force);
 
 static void gsm322_cs_timeout(void *arg);
 static void gsm322_cs_loss(void *arg);
@@ -2376,7 +2376,7 @@ static int gsm322_cs_powerscan(struct osmocom_ms *ms)
        return l1ctl_tx_pm_req_range(ms, s, e);
 }
 
-static int gsm322_l1_signal(unsigned int subsys, unsigned int signal,
+int gsm322_l1_signal(unsigned int subsys, unsigned int signal,
                     void *handler_data, void *signal_data)
 {
        struct osmocom_ms *ms;
@@ -2489,8 +2489,8 @@ static int gsm322_l1_signal(unsigned int subsys, unsigned int signal,
        case S_L1CTL_RESET:
                ms = signal_data;
                if (ms->mmlayer.power_off_idle) {
-                       l23_app_exit(ms);
-                       exit(0);
+                       l23_app_exit(ms, 1);
+                       return 0;
                }
                break;
        }
@@ -3525,8 +3525,6 @@ int gsm322_init(struct osmocom_ms *ms)
        } else
                LOGP(DCS, LOGL_INFO, "No stored BA list\n");
 
-       register_signal_handler(SS_L1CTL, &gsm322_l1_signal, NULL);
-
        return 0;
 }
 
@@ -3545,8 +3543,6 @@ int gsm322_exit(struct osmocom_ms *ms)
        LOGP(DPLMN, LOGL_INFO, "exit PLMN process\n");
        LOGP(DCS, LOGL_INFO, "exit Cell Selection process\n");
 
-       unregister_signal_handler(SS_L1CTL, &gsm322_l1_signal, NULL);
-
        /* stop cell selection process (if any) */
        new_c_state(cs, GSM322_C0_NULL);
 
index b77f433..d4444cf 100644 (file)
 
 #include <osmocom/bb/common/logging.h>
 #include <osmocom/bb/common/osmocom_data.h>
-#include <osmocom/bb/common/l23_app.h>
 #include <osmocom/bb/common/networks.h>
 #include <osmocom/bb/common/l1ctl.h>
 #include <osmocom/bb/mobile/gsm48_cc.h>
 
 extern void *l23_ctx;
+extern int (*l23_app_exit) (struct osmocom_ms *ms, int force);
 
 void mm_conn_free(struct gsm48_mm_conn *conn);
 static int gsm48_rcv_rr(struct osmocom_ms *ms, struct msgb *msg);
@@ -1741,11 +1741,12 @@ static int gsm48_mm_imsi_detach_end(struct osmocom_ms *ms, struct msgb *msg)
        subscr->sim_valid = 0;
 
        /* wait for RR idle and then power off when IMSI is detached */
-       if (mm->power_off) {
+       if (ms->shutdown) {
                if (mm->state == GSM48_MM_ST_MM_IDLE) {
-                       l23_app_exit(ms);
-                       exit(0);
+                       l23_app_exit(ms, 1);
+                       return 0;
                }
+               /* power off when MM idle */
                mm->power_off_idle = 1;
 
                return 0;
@@ -1816,9 +1817,9 @@ static int gsm48_mm_imsi_detach_release(struct osmocom_ms *ms, struct msgb *msg)
                new_mm_state(mm, GSM48_MM_ST_WAIT_NETWORK_CMD, 0);
 
                /* power off */
-               if (mm->power_off) {
-                       l23_app_exit(ms);
-                       exit(0);
+               if (ms->shutdown) {
+                       l23_app_exit(ms, 1);
+                       return 0;
                }
 
                return 0;
diff --git a/src/host/layer23/src/mobile/main.c b/src/host/layer23/src/mobile/main.c
new file mode 100644 (file)
index 0000000..9fd4ff7
--- /dev/null
@@ -0,0 +1,325 @@
+/* Main method of the layer2/3 stack */
+
+/* (C) 2010 by Holger Hans Peter Freyther
+ * (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <osmocom/bb/common/osmocom_data.h>
+#include <osmocom/bb/common/l1l2_interface.h>
+#include <osmocom/bb/common/l1ctl.h>
+#include <osmocom/bb/common/sap_interface.h>
+#include <osmocom/bb/misc/layer3.h>
+#include <osmocom/bb/common/lapdm.h>
+#include <osmocom/bb/common/logging.h>
+#include <osmocom/bb/common/gps.h>
+#include <osmocom/bb/mobile/vty.h>
+#include <osmocom/vty/telnet_interface.h>
+
+#include <osmocore/msgb.h>
+#include <osmocore/talloc.h>
+#include <osmocore/select.h>
+#include <osmocore/linuxlist.h>
+#include <osmocore/gsmtap_util.h>
+#include <osmocore/signal.h>
+
+#include <arpa/inet.h>
+
+#define _GNU_SOURCE
+#include <getopt.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <time.h>
+
+struct log_target *stderr_target;
+
+void *l23_ctx = NULL;
+static const char *config_file = "/etc/osmocom/osmocom.cfg";
+struct llist_head ms_list;
+static uint32_t gsmtap_ip = 0;
+unsigned short vty_port = 4247;
+int (*l23_app_work) (struct osmocom_ms *ms) = NULL;
+int (*l23_app_exit) (struct osmocom_ms *ms, int force) = NULL;
+int quit = 0;
+
+int mobile_delete(struct osmocom_ms *ms, int force);
+int mobile_signal_cb(unsigned int subsys, unsigned int signal,
+                    void *handler_data, void *signal_data);
+int mobile_work(struct osmocom_ms *ms);
+int mobile_exit(struct osmocom_ms *ms, int force);
+extern int vty_reading;
+
+
+const char *openbsc_copyright =
+       "Copyright (C) 2008-2010 ...\n"
+       "Contributions by ...\n\n"
+       "License GPLv2+: GNU GPL version 2 or later "
+               "<http://gnu.org/licenses/gpl.html>\n"
+       "This is free software: you are free to change and redistribute it.\n"
+       "There is NO WARRANTY, to the extent permitted by law.\n";
+
+static void print_usage(const char *app)
+{
+       printf("Usage: %s\n", app);
+}
+
+static void print_help()
+{
+       printf(" Some help...\n");
+       printf("  -h --help             this text\n");
+       printf("  -i --gsmtap-ip        The destination IP used for GSMTAP.\n");
+       printf("  -v --vty-port         The VTY port number to telnet to. "
+               "(default %u)\n", vty_port);
+       printf("  -d --debug            Change debug flags.\n");
+}
+
+static void handle_options(int argc, char **argv)
+{
+       struct sockaddr_in gsmtap;
+       while (1) {
+               int option_index = 0, c;
+               static struct option long_options[] = {
+                       {"help", 0, 0, 'h'},
+                       {"gsmtap-ip", 1, 0, 'i'},
+                       {"vty-port", 1, 0, 'v'},
+                       {"debug", 1, 0, 'd'},
+                       {0, 0, 0, 0},
+               };
+
+               c = getopt_long(argc, argv, "hi:v:d:",
+                               long_options, &option_index);
+               if (c == -1)
+                       break;
+
+               switch (c) {
+               case 'h':
+                       print_usage(argv[0]);
+                       print_help();
+                       exit(0);
+                       break;
+               case 'i':
+                       if (!inet_aton(optarg, &gsmtap.sin_addr)) {
+                               perror("inet_aton");
+                               exit(2);
+                       }
+                       gsmtap_ip = ntohl(gsmtap.sin_addr.s_addr);
+                       break;
+               case 'v':
+                       vty_port = atoi(optarg);
+                       break;
+               case 'd':
+                       log_parse_category_mask(stderr_target, optarg);
+                       break;
+               default:
+                       break;
+               }
+       }
+}
+
+void sighandler(int sigset)
+{
+       if (sigset == SIGHUP || sigset == SIGPIPE)
+               return;
+
+       fprintf(stderr, "Signal %d recevied.\n", sigset);
+
+       /* in case there is a lockup during exit */
+       signal(SIGINT, SIG_DFL);
+       signal(SIGHUP, SIG_DFL);
+       signal(SIGTERM, SIG_DFL);
+       signal(SIGPIPE, SIG_DFL);
+
+       dispatch_signal(SS_GLOBAL, S_GLOBAL_SHUTDOWN, NULL);
+}
+
+int global_signal_cb(unsigned int subsys, unsigned int signal,
+                    void *handler_data, void *signal_data)
+{
+       struct osmocom_ms *ms, *ms2;
+
+       if (subsys != SS_GLOBAL)
+               return 0;
+
+       switch (signal) {
+       case S_GLOBAL_SHUTDOWN:
+               llist_for_each_entry_safe(ms, ms2, &ms_list, entity)
+                       mobile_delete(ms, quit);
+
+               /* if second signal is received, force to exit */
+               quit = 1;
+               break;
+       }
+       return 0;
+}
+
+struct osmocom_ms *mobile_new(char *name)
+{
+       static struct osmocom_ms *ms;
+
+       ms = talloc_zero(l23_ctx, struct osmocom_ms);
+       if (!ms) {
+               fprintf(stderr, "Failed to allocate MS\n");
+               exit(1);
+       }
+       llist_add_tail(&ms->entity, &ms_list);
+
+       strcpy(ms->name, name);
+
+       ms->l2_wq.bfd.fd = -1;
+       ms->sap_wq.bfd.fd = -1;
+
+       gsm_support_init(ms);
+       gsm_settings_init(ms);
+
+       ms->shutdown = 2; /* being down */
+
+       return ms;
+}
+
+int mobile_delete(struct osmocom_ms *ms, int force)
+{
+       int rc;
+
+       ms->delete = 1;
+
+       if (ms->shutdown == 0 || (ms->shutdown == 1 && force)) {
+               rc = l23_app_exit(ms, force);
+               if (rc < 0)
+                       return rc;
+       }
+
+       return 0;
+}
+
+static struct vty_app_info vty_info = {
+       .name = "OsmocomBB",
+       .version = PACKAGE_VERSION,
+       .go_parent_cb = ms_vty_go_parent,
+};
+
+int main(int argc, char **argv)
+{
+       struct osmocom_ms *ms, *ms2;
+       struct telnet_connection dummy_conn;
+       int rc;
+
+       printf("%s\n", openbsc_copyright);
+
+       srand(time(NULL));
+
+       INIT_LLIST_HEAD(&ms_list);
+       log_init(&log_info);
+       stderr_target = log_target_create_stderr();
+       log_add_target(stderr_target);
+       log_set_all_filter(stderr_target, 1);
+
+       l23_ctx = talloc_named_const(NULL, 1, "layer2 context");
+
+       handle_options(argc, argv);
+
+//     log_parse_category_mask(stderr_target, "DL1C:DRSL:DLAPDM:DCS:DPLMN:DRR:DMM:DSIM:DCC:DMNCC:DPAG:DSUM");
+       log_parse_category_mask(stderr_target, "DCS:DPLMN:DRR:DMM:DSIM:DCC:DMNCC:DPAG:DSUM");
+       log_set_log_level(stderr_target, LOGL_INFO);
+
+       gps_init();
+
+       l23_app_work = mobile_work;
+       register_signal_handler(SS_GLOBAL, &global_signal_cb, NULL);
+       register_signal_handler(SS_L1CTL, &mobile_signal_cb, NULL);
+       register_signal_handler(SS_L1CTL, &gsm322_l1_signal, NULL);
+       l23_app_exit = mobile_exit;
+
+       vty_init(&vty_info);
+       ms_vty_init();
+       dummy_conn.priv = NULL;
+       vty_reading = 1;
+       rc = vty_read_config_file(config_file, &dummy_conn);
+       if (rc < 0) {
+               fprintf(stderr, "Failed to parse the config file: '%s'\n",
+                       config_file);
+               fprintf(stderr, "Please check or create config file using: "
+                       "'touch %s'\n", config_file);
+               return rc;
+       }
+       vty_reading = 0;
+       telnet_init(l23_ctx, NULL, vty_port);
+       if (rc < 0)
+               return rc;
+       printf("VTY available on port %u.\n", vty_port);
+
+       if (llist_empty(&ms_list)) {
+               struct osmocom_ms *ms;
+
+               printf("No Mobile Station defined, creating: MS '1'\n");
+               ms = mobile_new("1");
+               if (ms)
+                       l23_app_init(ms);
+       }
+
+       if (gsmtap_ip) {
+               rc = gsmtap_init(gsmtap_ip);
+               if (rc < 0) {
+                       fprintf(stderr, "Failed during gsmtap_init()\n");
+                       exit(1);
+               }
+       }
+
+       signal(SIGINT, sighandler);
+       signal(SIGHUP, sighandler);
+       signal(SIGTERM, sighandler);
+       signal(SIGPIPE, sighandler);
+
+       while (1) {
+               llist_for_each_entry_safe(ms, ms2, &ms_list, entity) {
+                       if (ms->shutdown != 2)
+                               l23_app_work(ms);
+                       if (ms->shutdown == 2) {
+                               if (ms->l2_wq.bfd.fd > -1) {
+                                       layer2_close(ms);
+                                       ms->l2_wq.bfd.fd = -1;
+                               }
+
+                               if (ms->sap_wq.bfd.fd > -1) {
+                                       sap_close(ms);
+                                       ms->sap_wq.bfd.fd = -1;
+                               }
+
+                               if (ms->delete) {
+                                       gsm_settings_exit(ms);
+                                       llist_del(&ms->entity);
+                                       talloc_free(ms);
+                               }
+                       }
+               }
+               if (quit && llist_empty(&ms_list))
+                       break;
+               bsc_select_main(0);
+       }
+
+       unregister_signal_handler(SS_L1CTL, &gsm322_l1_signal, NULL);
+       unregister_signal_handler(SS_L1CTL, &mobile_signal_cb, NULL);
+       unregister_signal_handler(SS_GLOBAL, &global_signal_cb, NULL);
+
+       gps_close();
+
+       return 0;
+}
index 6294ec6..89672a2 100644 (file)
 #include <osmocom/bb/common/osmocom_data.h>
 #include <osmocom/bb/common/networks.h>
 
+static char *layer2_socket_path = "/tmp/osmocom_l2";
+static char *sap_socket_path = "/tmp/osmocom_sap";
+
 int gsm_settings_init(struct osmocom_ms *ms)
 {
        struct gsm_settings *set = &ms->settings;
        struct gsm_support *sup = &ms->support;
 
+       strcpy(set->layer2_socket_path, layer2_socket_path);
+       strcpy(set->sap_socket_path, sap_socket_path);
+
        /* IMEI */
        sprintf(set->imei,   "000000000000000");
        sprintf(set->imeisv, "0000000000000000");
 
-       /* test sim */
+       /* SIM type */
+#warning TODO: Enable after SIM reader is available in master branch.
+//     set->sim_type = SIM_TYPE_READER;
+
+       /* test SIM */
        strcpy(set->test_imsi, "001010000000000");
        set->test_rplmn_mcc = set->test_rplmn_mnc = 1;
 
index c1d00f4..8a13a5d 100644 (file)
@@ -28,6 +28,7 @@
 #include <osmocore/utils.h>
 #include <osmocore/gsm48.h>
 #include <osmocore/talloc.h>
+#include <osmocore/signal.h>
 
 #include <osmocom/bb/common/osmocom_data.h>
 #include <osmocom/bb/common/networks.h>
 #include <osmocom/vty/telnet_interface.h>
 
 void *l23_ctx;
+extern int l23_app_init(struct osmocom_ms *ms);
+extern int (*l23_app_exit) (struct osmocom_ms *ms, int force);
+extern struct osmocom_ms *mobile_new(char *name);
+extern int mobile_delete(struct osmocom_ms *ms, int force);
 
 int mncc_call(struct osmocom_ms *ms, char *number);
 int mncc_hangup(struct osmocom_ms *ms);
@@ -114,12 +119,14 @@ int vty_check_number(struct vty *vty, const char *number)
 
 int vty_reading = 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)
@@ -128,6 +135,10 @@ static struct osmocom_ms *get_ms(const char *name, struct vty *vty)
 
        llist_for_each_entry(ms, &ms_list, entity) {
                if (!strcmp(ms->name, name))
+                       if (ms->shutdown) {
+                               vty_out(vty, "MS '%s' is admin down.%s", name,
+                                       VTY_NEWLINE);
+                       }
                        return ms;
        }
        vty_out(vty, "MS name '%s' does not exits.%s", name, VTY_NEWLINE);
@@ -224,8 +235,10 @@ DEFUN(show_states, show_states_cmd, "show states [ms_name]",
                gsm_states_dump(ms, vty);
        } else {
                llist_for_each_entry(ms, &ms_list, entity) {
-                       gsm_states_dump(ms, vty);
-                       vty_out(vty, "%s", VTY_NEWLINE);
+                       if (!ms->shutdown) {
+                               gsm_states_dump(ms, vty);
+                               vty_out(vty, "%s", VTY_NEWLINE);
+                       }
                }
        }
 
@@ -245,8 +258,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);
+                       }
                }
        }
 
@@ -855,10 +870,29 @@ 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;
@@ -866,6 +900,87 @@ DEFUN(cfg_ms, cfg_ms_cmd, "ms MS_NAME",
        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, \
@@ -878,6 +993,9 @@ static void config_write_ms_single(struct vty *vty, struct osmocom_ms *ms)
        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);
@@ -1011,6 +1129,8 @@ static void config_write_ms_single(struct vty *vty, struct osmocom_ms *ms)
        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, " %sshutdown%s", (ms->shutdown) ? "" : "no ",
+               VTY_NEWLINE);
        vty_out(vty, "exit%s", VTY_NEWLINE);
        vty_out(vty, "!%s", VTY_NEWLINE);
 }
@@ -1033,6 +1153,34 @@ static int config_write_ms(struct vty *vty)
        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")
@@ -1055,7 +1203,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;
 }
 
@@ -1118,7 +1266,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;
 }
 
@@ -1131,7 +1279,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;
 }
 
@@ -1539,7 +1687,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; \
 }
@@ -1557,7 +1705,7 @@ 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; \
 }
@@ -1568,7 +1716,7 @@ 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); \
+               vty_restart(vty, ms); \
        set->item = 1; \
        return CMD_SUCCESS; \
 }
@@ -1579,7 +1727,7 @@ 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); \
+               vty_restart(vty, ms); \
        set->item = 0; \
        return CMD_SUCCESS; \
 }
@@ -1682,7 +1830,7 @@ DEFUN(cfg_ms_sup_ch_cap, cfg_ms_sup_ch_cap_cmd, "channel-capability "
 
        if (ch_cap != set->ch_cap
         && (ch_cap == GSM_CAP_SDCCH || set->ch_cap == GSM_CAP_SDCCH))
-               vty_restart(vty);
+               vty_restart(vty, ms);
 
        set->ch_cap = ch_cap;
 
@@ -1759,7 +1907,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;
 }
 
@@ -1851,7 +1999,7 @@ 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;
 }
 
@@ -1875,7 +2023,7 @@ DEFUN(cfg_test_rplmn, cfg_test_rplmn_cmd, "rplmn MCC MNC",
        set->test_rplmn_mcc = mcc;
        set->test_rplmn_mnc = mnc;
 
-       vty_restart(vty);
+       vty_restart(vty, ms);
        return CMD_SUCCESS;
 }
 
@@ -1896,7 +2044,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 = l23_app_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)
+               l23_app_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)
+               l23_app_exit(ms, 1);
+
        return CMD_SUCCESS;
 }
 
@@ -1962,6 +2172,14 @@ gDEFUN(ournode_end,
        return CMD_SUCCESS;
 }
 
+DEFUN(off, off_cmd, "off",
+       "Turn mobiles off (shutdown) and exit")
+{
+       dispatch_signal(SS_GLOBAL, S_GLOBAL_SHUTDOWN, NULL);
+
+       return CMD_SUCCESS;
+}
+
 #define SUP_NODE(item) \
        install_element(SUPPORT_NODE, &cfg_ms_sup_item_cmd);
 
@@ -1978,6 +2196,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);
@@ -2001,11 +2220,16 @@ int ms_vty_init(void)
        install_element(CONFIG_NODE, &cfg_no_gps_enable_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_default(MS_NODE);
        install_element(MS_NODE, &ournode_exit_cmd);
        install_element(MS_NODE, &ournode_end_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);
@@ -2095,6 +2319,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;
 }