blob: 890444cfcc16a38bae5369799f6f3e30eb99b3ce [file] [log] [blame]
Alexander Couzensc0d02cc2020-12-14 02:36:53 +01001
2#include <errno.h>
3#include <stdlib.h>
4#include <stdio.h>
5#include <getopt.h>
6#include <signal.h>
7
8#include <osmocom/core/select.h>
9#include <osmocom/core/application.h>
10#include <osmocom/core/stats.h>
Maxa9ddb832022-11-23 16:01:07 +030011#include <osmocom/ctrl/control_if.h>
12#include <osmocom/ctrl/control_vty.h>
Alexander Couzensc0d02cc2020-12-14 02:36:53 +010013#include <osmocom/gprs/gprs_ns2.h>
14#include <osmocom/vty/vty.h>
15#include <osmocom/vty/telnet_interface.h>
16#include <osmocom/vty/command.h>
17#include <osmocom/vty/ports.h>
18#include <osmocom/vty/tdef_vty.h>
19#include <osmocom/vty/logging.h>
20#include <osmocom/vty/stats.h>
21#include <osmocom/vty/misc.h>
22
23#include "config.h"
24
25void *tall_nsdummy_ctx = NULL;
26static struct log_info log_info = {};
27static bool quit = false;
28static bool config_given = false;
29static bool daemonize = false;
30static int vty_port = 0;
Maxa9ddb832022-11-23 16:01:07 +030031static int ctrl_port = 0;
Alexander Couzensc0d02cc2020-12-14 02:36:53 +010032static char *config_file = NULL;
Harald Welte9bbb7032021-01-31 16:44:46 +010033struct gprs_ns2_inst *g_nsi;
Alexander Couzensc0d02cc2020-12-14 02:36:53 +010034
35static const char vty_copyright[] =
36 "Copyright (C) 2020 by by sysmocom - s.f.m.c. GmbH\r\n"
37 "Author: Alexander Couzens <lynxis@fe80.eu>\r\n"
38 "License GNU GPL version 2 or later\r\n"
39 "This is free software: you are free to change and redistribute it.\r\n"
40 "There is NO WARRANTY, to the extent permitted by law.\r\n";
41
42static struct vty_app_info vty_info = {
43 .name = "OsmoNSdummy",
44 .version = PACKAGE_VERSION,
45 .copyright = vty_copyright,
46};
47
Harald Weltee61d4592022-11-03 11:05:58 +010048static void print_help(void)
Alexander Couzensc0d02cc2020-12-14 02:36:53 +010049{
50 printf( "Some useful options:\n"
51 " -h --help This text\n"
52 " -c --config-file Specify the filename of the config file\n"
53 " -V --version Print version\n"
54 " -D --daemonize Fork the process into a background daemon\n"
55 " -p --vty-port PORT Set the vty port to listen on.\n"
Maxa9ddb832022-11-23 16:01:07 +030056 " -r --ctrl-port PORT Set the ctrl port to listen on.\n"
Alexander Couzensc0d02cc2020-12-14 02:36:53 +010057 "\nVTY reference generation:\n"
58 " --vty-ref-mode MODE VTY reference generation mode (e.g. 'expert').\n"
59 " --vty-ref-xml Generate the VTY reference XML output and exit.\n"
60 );
61}
62
63static void handle_long_options(const char *prog_name, const int long_option)
64{
65 static int vty_ref_mode = VTY_REF_GEN_MODE_DEFAULT;
66
67 switch (long_option) {
68 case 1:
69 vty_ref_mode = get_string_value(vty_ref_gen_mode_names, optarg);
70 if (vty_ref_mode < 0) {
71 fprintf(stderr, "%s: Unknown VTY reference generation "
72 "mode '%s'\n", prog_name, optarg);
73 exit(2);
74 }
75 break;
76 case 2:
77 fprintf(stderr, "Generating the VTY reference in mode '%s' (%s)\n",
78 get_value_string(vty_ref_gen_mode_names, vty_ref_mode),
79 get_value_string(vty_ref_gen_mode_desc, vty_ref_mode));
80 vty_dump_xml_ref_mode(stdout, (enum vty_ref_gen_mode) vty_ref_mode);
81 exit(0);
82 default:
83 fprintf(stderr, "%s: error parsing cmdline options\n", prog_name);
84 exit(2);
85 }
86}
87
88static void handle_options(int argc, char **argv)
89{
90 while (1) {
91 int option_idx = 0, c;
92 static int long_option = 0;
93 static const struct option long_options[] = {
94 { "help", 0, 0, 'h' },
95 { "config-file", 1, 0, 'c' },
96 { "version", 0, 0, 'V' },
97 { "daemonize", 0, 0, 'D' },
98 { "vty-port", 1, 0, 'p' },
Maxa9ddb832022-11-23 16:01:07 +030099 { "ctrl-port", 1, 0, 'r' },
Alexander Couzensc0d02cc2020-12-14 02:36:53 +0100100 { "vty-ref-mode", 1, &long_option, 1 },
101 { "vty-ref-xml", 0, &long_option, 2 },
102 { 0, 0, 0, 0 }
103 };
104
Maxa9ddb832022-11-23 16:01:07 +0300105 c = getopt_long(argc, argv, "hc:p:r:VD",
Alexander Couzensc0d02cc2020-12-14 02:36:53 +0100106 long_options, &option_idx);
107 if (c == -1)
108 break;
109
110 switch (c) {
111 case 'h':
112 print_help();
113 exit(0);
114 break;
115 case 0:
116 handle_long_options(argv[0], long_option);
117 break;
118 case 'c':
119 if (config_file)
120 free(config_file);
121 config_file = optarg;
122 config_given = true;
123 break;
124 case 'p':
125 vty_port = atoi(optarg);
126 if (vty_port < 0 || vty_port > 65535) {
Maxa9ddb832022-11-23 16:01:07 +0300127 fprintf(stderr, "Invalid VTY port %d given!\n", vty_port);
128 exit(1);
129 }
130 break;
131 case 'r':
132 ctrl_port = atoi(optarg);
133 if (ctrl_port < 0 || ctrl_port > 65535) {
134 fprintf(stderr, "Invalid CTRL port %d given!\n", ctrl_port);
Alexander Couzensc0d02cc2020-12-14 02:36:53 +0100135 exit(1);
136 }
137 break;
138 case 'V':
139 print_version(1);
140 exit(0);
141 break;
142 case 'D':
143 daemonize = true;
144 break;
145 default:
146 fprintf(stderr, "Unknown option '%c'\n", c);
147 exit(0);
148 break;
149 }
150 }
151
152 if (!config_file)
153 config_file = "osmo-ns-dummy.cfg";
154 if (!vty_port) {
155 fprintf(stderr, "A vty port need to be specified (-p)\n");
156 exit(1);
157 }
158}
159
160void sighandler(int sigset)
161{
162 if (sigset == SIGPIPE)
163 return;
164
165 fprintf(stderr, "Signal %d received.\n", sigset);
166
167 switch (sigset) {
168 case SIGINT:
169 case SIGTERM:
170 /* If another signal is received afterwards, the program
171 * is terminated without finishing shutdown process.
172 */
173 signal(SIGINT, SIG_DFL);
174 signal(SIGTERM, SIG_DFL);
175 signal(SIGPIPE, SIG_DFL);
176 signal(SIGABRT, SIG_DFL);
177 signal(SIGUSR1, SIG_DFL);
178 signal(SIGUSR2, SIG_DFL);
179
180 quit = 1;
181 break;
182 case SIGABRT:
183 /* in case of abort, we want to obtain a talloc report and
184 * then run default SIGABRT handler, who will generate coredump
185 * and abort the process. abort() should do this for us after we
186 * return, but program wouldn't exit if an external SIGABRT is
187 * received.
188 */
189 talloc_report_full(tall_nsdummy_ctx, stderr);
190 signal(SIGABRT, SIG_DFL);
191 raise(SIGABRT);
192 break;
193 case SIGUSR1:
194 case SIGUSR2:
195 talloc_report_full(tall_nsdummy_ctx, stderr);
196 break;
197 }
198}
199
Harald Welte9bbb7032021-01-31 16:44:46 +0100200extern int g_mirror_mode;
201
Alexander Couzensc0d02cc2020-12-14 02:36:53 +0100202/* called by the ns layer */
203int gprs_ns_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
204{
Harald Welte9bbb7032021-01-31 16:44:46 +0100205 struct osmo_gprs_ns2_prim *nsp = container_of(oph, struct osmo_gprs_ns2_prim, oph);
206
207 switch (oph->primitive) {
208 case GPRS_NS2_PRIM_UNIT_DATA:
209 if (g_mirror_mode) {
210 /* simply switch indication->request and resubmit */
211 oph->operation = PRIM_OP_REQUEST;
212 msgb_pull_to_l3(oph->msg);
213 nsp->u.unitdata.link_selector = rand(); /* ensure random distribution */
214 return gprs_ns2_recv_prim(g_nsi, oph);
215 }
216 break;
217 default:
218 break;
219 }
220
Alexander Couzensfd96dc52021-01-18 13:43:44 +0100221 if (oph->msg)
222 msgb_free(oph->msg);
223
Alexander Couzensc0d02cc2020-12-14 02:36:53 +0100224 return 0;
225}
226
227int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx)
228{
229 return 0;
230}
231
Harald Welte9bbb7032021-01-31 16:44:46 +0100232extern int nsdummy_vty_init(void);
Alexander Couzensc0d02cc2020-12-14 02:36:53 +0100233
234int main (int argc, char *argv[])
235{
236 void *ctx = tall_nsdummy_ctx = talloc_named_const(NULL, 0, "osmo-ns-dummy");
Maxa9ddb832022-11-23 16:01:07 +0300237 struct ctrl_handle *ctrl;
Alexander Couzensc0d02cc2020-12-14 02:36:53 +0100238 int rc = 0;
239
240 osmo_init_logging2(ctx, &log_info);
241 log_set_use_color(osmo_stderr_target, 0);
Pau Espin Pedrol01e0d3e2021-02-18 19:25:44 +0100242 log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE);
Alexander Couzensc0d02cc2020-12-14 02:36:53 +0100243 log_set_log_level(osmo_stderr_target, LOGL_INFO);
244 msgb_talloc_ctx_init(ctx, 0);
245 osmo_stats_init(ctx);
246 rate_ctr_init(ctx);
247
248 vty_info.tall_ctx = ctx;
249 vty_init(&vty_info);
Maxa9ddb832022-11-23 16:01:07 +0300250 ctrl_vty_init(ctx);
Alexander Couzensc0d02cc2020-12-14 02:36:53 +0100251 logging_vty_add_cmds();
252 osmo_stats_vty_add_cmds();
253 osmo_talloc_vty_add_cmds();
254
255 handle_options(argc, argv);
256
Harald Welte9bbb7032021-01-31 16:44:46 +0100257 g_nsi = gprs_ns2_instantiate(ctx, gprs_ns_prim_cb, NULL);
258 if (!g_nsi) {
Alexander Couzensc0d02cc2020-12-14 02:36:53 +0100259 LOGP(DLNS, LOGL_ERROR, "Failed to create NS instance\n");
260 exit(1);
261 }
262
Harald Welte9bbb7032021-01-31 16:44:46 +0100263 gprs_ns2_vty_init(g_nsi);
264 nsdummy_vty_init();
Alexander Couzensc0d02cc2020-12-14 02:36:53 +0100265 rc = vty_read_config_file(config_file, NULL);
266 if (rc < 0 && config_given) {
267 fprintf(stderr, "Failed to parse the config file: '%s'\n",
268 config_file);
269 exit(1);
270 }
271 if (rc < 0)
272 fprintf(stderr, "No config file: '%s' Using default config.\n",
273 config_file);
274
arehbein0aa84cf2023-01-27 00:49:45 +0100275 rc = telnet_init_default(ctx, NULL, vty_port);
Alexander Couzensc0d02cc2020-12-14 02:36:53 +0100276 if (rc < 0) {
277 fprintf(stderr, "Error initializing telnet\n");
278 exit(1);
279 }
280
Maxa9ddb832022-11-23 16:01:07 +0300281 if (ctrl_port > 0) {
Max3f79ce82022-12-03 17:59:19 +0300282 ctrl = ctrl_interface_setup(NULL, ctrl_port, NULL);
Maxa9ddb832022-11-23 16:01:07 +0300283 if (!ctrl) {
284 fprintf(stderr, "Failed to initialize control interface. Exiting.\n");
285 exit(1);
286 }
287 }
288
Alexander Couzensc0d02cc2020-12-14 02:36:53 +0100289 signal(SIGINT, sighandler);
290 signal(SIGTERM, sighandler);
291 signal(SIGPIPE, sighandler);
292 signal(SIGABRT, sighandler);
293 signal(SIGUSR1, sighandler);
294 signal(SIGUSR2, sighandler);
295 osmo_init_ignore_signals();
296
297 if (daemonize) {
298 rc = osmo_daemonize();
299 if (rc < 0) {
300 perror("Error during daemonize");
301 exit(1);
302 }
303 }
304
305 while (!quit) {
306 osmo_select_main(0);
307 }
308
309 telnet_exit();
Harald Welte9bbb7032021-01-31 16:44:46 +0100310 gprs_ns2_free(g_nsi);
Alexander Couzensc0d02cc2020-12-14 02:36:53 +0100311
312 talloc_report_full(tall_nsdummy_ctx, stderr);
313 talloc_free(tall_nsdummy_ctx);
314
315 return 0;
316}