summaryrefslogtreecommitdiffstats
path: root/src/host/layer23/src
diff options
context:
space:
mode:
authorAndreas.Eversberg <jolly@eversberg.eu>2010-11-13 18:45:09 +0000
committerAndreas.Eversberg <jolly@eversberg.eu>2010-11-13 18:45:09 +0000
commit6f2b172780195e0af780ecd0a4fff0fac9b8438b (patch)
tree44423a4d31fa2767e26c988a258a960e7e51e5a1 /src/host/layer23/src
parent4df881932c30c2d3deb88c53a55a21fd342068d8 (diff)
[layer23] Added support for multiple MS instances
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.
Diffstat (limited to 'src/host/layer23/src')
-rw-r--r--src/host/layer23/src/common/l1l2_interface.c1
-rw-r--r--src/host/layer23/src/mobile/Makefile.am2
-rw-r--r--src/host/layer23/src/mobile/app_mobile.c100
-rw-r--r--src/host/layer23/src/mobile/gsm322.c12
-rw-r--r--src/host/layer23/src/mobile/gsm48_mm.c15
-rw-r--r--src/host/layer23/src/mobile/main.c325
-rw-r--r--src/host/layer23/src/mobile/settings.c12
-rw-r--r--src/host/layer23/src/mobile/vty_interface.c271
8 files changed, 634 insertions, 104 deletions
diff --git a/src/host/layer23/src/common/l1l2_interface.c b/src/host/layer23/src/common/l1l2_interface.c
index 28356daa..9d31532b 100644
--- a/src/host/layer23/src/common/l1l2_interface.c
+++ b/src/host/layer23/src/common/l1l2_interface.c
@@ -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;
}
diff --git a/src/host/layer23/src/mobile/Makefile.am b/src/host/layer23/src/mobile/Makefile.am
index bd98bafd..12f0f76b 100644
--- a/src/host/layer23/src/mobile/Makefile.am
+++ b/src/host/layer23/src/mobile/Makefile.am
@@ -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)
diff --git a/src/host/layer23/src/mobile/app_mobile.c b/src/host/layer23/src/mobile/app_mobile.c
index 6abb8703..293d1355 100644
--- a/src/host/layer23/src/mobile/app_mobile.c
+++ b/src/host/layer23/src/mobile/app_mobile.c
@@ -24,14 +24,12 @@
#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>
@@ -39,18 +37,10 @@
#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;
}
diff --git a/src/host/layer23/src/mobile/gsm322.c b/src/host/layer23/src/mobile/gsm322.c
index 0b45f605..751b8b4b 100644
--- a/src/host/layer23/src/mobile/gsm322.c
+++ b/src/host/layer23/src/mobile/gsm322.c
@@ -33,12 +33,12 @@
#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);
diff --git a/src/host/layer23/src/mobile/gsm48_mm.c b/src/host/layer23/src/mobile/gsm48_mm.c
index b77f4335..d4444cf2 100644
--- a/src/host/layer23/src/mobile/gsm48_mm.c
+++ b/src/host/layer23/src/mobile/gsm48_mm.c
@@ -33,12 +33,12 @@
#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
index 00000000..9fd4ff78
--- /dev/null
+++ b/src/host/layer23/src/mobile/main.c
@@ -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;
+}
diff --git a/src/host/layer23/src/mobile/settings.c b/src/host/layer23/src/mobile/settings.c
index 6294ec65..89672a25 100644
--- a/src/host/layer23/src/mobile/settings.c
+++ b/src/host/layer23/src/mobile/settings.c
@@ -28,16 +28,26 @@
#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;
diff --git a/src/host/layer23/src/mobile/vty_interface.c b/src/host/layer23/src/mobile/vty_interface.c
index c1d00f44..8a13a5dc 100644
--- a/src/host/layer23/src/mobile/vty_interface.c
+++ b/src/host/layer23/src/mobile/vty_interface.c
@@ -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>
@@ -38,6 +39,10 @@
#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;
}