diff options
-rw-r--r-- | src/host/layer23/include/osmocom/bb/common/osmocom_data.h | 8 | ||||
-rw-r--r-- | src/host/layer23/include/osmocom/bb/mobile/gsm322.h | 2 | ||||
-rw-r--r-- | src/host/layer23/include/osmocom/bb/mobile/gsm48_mm.h | 1 | ||||
-rw-r--r-- | src/host/layer23/include/osmocom/bb/mobile/settings.h | 3 | ||||
-rw-r--r-- | src/host/layer23/src/common/l1l2_interface.c | 1 | ||||
-rw-r--r-- | src/host/layer23/src/mobile/Makefile.am | 2 | ||||
-rw-r--r-- | src/host/layer23/src/mobile/app_mobile.c | 100 | ||||
-rw-r--r-- | src/host/layer23/src/mobile/gsm322.c | 12 | ||||
-rw-r--r-- | src/host/layer23/src/mobile/gsm48_mm.c | 15 | ||||
-rw-r--r-- | src/host/layer23/src/mobile/main.c | 325 | ||||
-rw-r--r-- | src/host/layer23/src/mobile/settings.c | 12 | ||||
-rw-r--r-- | src/host/layer23/src/mobile/vty_interface.c | 271 |
12 files changed, 646 insertions, 106 deletions
diff --git a/src/host/layer23/include/osmocom/bb/common/osmocom_data.h b/src/host/layer23/include/osmocom/bb/common/osmocom_data.h index 77a60672..da35cdb0 100644 --- a/src/host/layer23/include/osmocom/bb/common/osmocom_data.h +++ b/src/host/layer23/include/osmocom/bb/common/osmocom_data.h @@ -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; diff --git a/src/host/layer23/include/osmocom/bb/mobile/gsm322.h b/src/host/layer23/include/osmocom/bb/mobile/gsm322.h index 78e380fe..467ff39a 100644 --- a/src/host/layer23/include/osmocom/bb/mobile/gsm322.h +++ b/src/host/layer23/include/osmocom/bb/mobile/gsm322.h @@ -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); diff --git a/src/host/layer23/include/osmocom/bb/mobile/gsm48_mm.h b/src/host/layer23/include/osmocom/bb/mobile/gsm48_mm.h index 0d181824..447dc95f 100644 --- a/src/host/layer23/include/osmocom/bb/mobile/gsm48_mm.h +++ b/src/host/layer23/include/osmocom/bb/mobile/gsm48_mm.h @@ -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 */ }; diff --git a/src/host/layer23/include/osmocom/bb/mobile/settings.h b/src/host/layer23/include/osmocom/bb/mobile/settings.h index 178ef081..d0848a82 100644 --- a/src/host/layer23/include/osmocom/bb/mobile/settings.h +++ b/src/host/layer23/include/osmocom/bb/mobile/settings.h @@ -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]; 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; } |