Check for osmo_fsm_register() error return value
[osmocom-bb.git] / src / host / trxcon / trxcon.c
blobecee518c826070420e45f6f4620cfdd8ebcebe1e
1 /*
2 * OsmocomBB <-> SDR connection bridge
4 * (C) 2016-2019 by Vadim Yanitskiy <axilirator@gmail.com>
6 * All Rights Reserved
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <stdint.h>
27 #include <string.h>
28 #include <getopt.h>
29 #include <unistd.h>
30 #include <signal.h>
31 #include <time.h>
33 #include <arpa/inet.h>
35 #include <osmocom/core/fsm.h>
36 #include <osmocom/core/msgb.h>
37 #include <osmocom/core/talloc.h>
38 #include <osmocom/core/signal.h>
39 #include <osmocom/core/select.h>
40 #include <osmocom/core/application.h>
41 #include <osmocom/core/gsmtap_util.h>
42 #include <osmocom/core/gsmtap.h>
44 #include <osmocom/gsm/gsm_utils.h>
46 #include "trxcon.h"
47 #include "trx_if.h"
48 #include "logging.h"
49 #include "l1ctl.h"
50 #include "l1ctl_link.h"
51 #include "l1ctl_proto.h"
52 #include "scheduler.h"
53 #include "sched_trx.h"
55 #define COPYRIGHT \
56 "Copyright (C) 2016-2019 by Vadim Yanitskiy <axilirator@gmail.com>\n" \
57 "License GPLv2+: GNU GPL version 2 or later " \
58 "<http://gnu.org/licenses/gpl.html>\n" \
59 "This is free software: you are free to change and redistribute it.\n" \
60 "There is NO WARRANTY, to the extent permitted by law.\n\n"
62 static struct {
63 const char *debug_mask;
64 int daemonize;
65 int quit;
67 /* L1CTL specific */
68 struct l1ctl_link *l1l;
69 const char *bind_socket;
71 /* TRX specific */
72 struct trx_instance *trx;
73 const char *trx_bind_ip;
74 const char *trx_remote_ip;
75 uint16_t trx_base_port;
76 uint32_t trx_fn_advance;
77 const char *gsmtap_ip;
78 } app_data;
80 static void *tall_trxcon_ctx = NULL;
81 struct gsmtap_inst *gsmtap = NULL;
82 struct osmo_fsm_inst *trxcon_fsm;
84 static void trxcon_fsm_idle_action(struct osmo_fsm_inst *fi,
85 uint32_t event, void *data)
87 if (event == L1CTL_EVENT_CONNECT)
88 osmo_fsm_inst_state_chg(trxcon_fsm, TRXCON_STATE_MANAGED, 0, 0);
91 static void trxcon_fsm_managed_action(struct osmo_fsm_inst *fi,
92 uint32_t event, void *data)
94 switch (event) {
95 case L1CTL_EVENT_DISCONNECT:
96 osmo_fsm_inst_state_chg(trxcon_fsm, TRXCON_STATE_IDLE, 0, 0);
98 if (app_data.trx->fsm->state != TRX_STATE_OFFLINE) {
99 /* Reset scheduler and clock counter */
100 sched_trx_reset(app_data.trx, true);
102 /* TODO: implement trx_if_reset() */
103 trx_if_cmd_poweroff(app_data.trx);
104 trx_if_cmd_echo(app_data.trx);
106 break;
107 case TRX_EVENT_RSP_ERROR:
108 case TRX_EVENT_OFFLINE:
109 /* TODO: notify L2 & L3 about that */
110 break;
111 default:
112 LOGPFSML(fi, LOGL_ERROR, "Unhandled event %u\n", event);
116 static struct osmo_fsm_state trxcon_fsm_states[] = {
117 [TRXCON_STATE_IDLE] = {
118 .in_event_mask = GEN_MASK(L1CTL_EVENT_CONNECT),
119 .out_state_mask = GEN_MASK(TRXCON_STATE_MANAGED),
120 .name = "IDLE",
121 .action = trxcon_fsm_idle_action,
123 [TRXCON_STATE_MANAGED] = {
124 .in_event_mask = (
125 GEN_MASK(L1CTL_EVENT_DISCONNECT) |
126 GEN_MASK(TRX_EVENT_RSP_ERROR) |
127 GEN_MASK(TRX_EVENT_OFFLINE)),
128 .out_state_mask = GEN_MASK(TRXCON_STATE_IDLE),
129 .name = "MANAGED",
130 .action = trxcon_fsm_managed_action,
134 static const struct value_string app_evt_names[] = {
135 OSMO_VALUE_STRING(L1CTL_EVENT_CONNECT),
136 OSMO_VALUE_STRING(L1CTL_EVENT_DISCONNECT),
137 OSMO_VALUE_STRING(TRX_EVENT_OFFLINE),
138 OSMO_VALUE_STRING(TRX_EVENT_RSP_ERROR),
139 { 0, NULL }
142 static struct osmo_fsm trxcon_fsm_def = {
143 .name = "trxcon_app_fsm",
144 .states = trxcon_fsm_states,
145 .num_states = ARRAY_SIZE(trxcon_fsm_states),
146 .log_subsys = DAPP,
147 .event_names = app_evt_names,
150 static void print_usage(const char *app)
152 printf("Usage: %s\n", app);
155 static void print_help(void)
157 printf(" Some help...\n");
158 printf(" -h --help this text\n");
159 printf(" -d --debug Change debug flags. Default: %s\n", DEBUG_DEFAULT);
160 printf(" -b --trx-bind TRX bind IP address (default 0.0.0.0)\n");
161 printf(" -i --trx-remote TRX remote IP address (default 127.0.0.1)\n");
162 printf(" -p --trx-port Base port of TRX instance (default 6700)\n");
163 printf(" -f --trx-advance Scheduler clock advance (default 20)\n");
164 printf(" -s --socket Listening socket for layer23 (default /tmp/osmocom_l2)\n");
165 printf(" -g --gsmtap-ip The destination IP used for GSMTAP (disabled by default)\n");
166 printf(" -D --daemonize Run as daemon\n");
169 static void handle_options(int argc, char **argv)
171 while (1) {
172 int option_index = 0, c;
173 static struct option long_options[] = {
174 {"help", 0, 0, 'h'},
175 {"debug", 1, 0, 'd'},
176 {"socket", 1, 0, 's'},
177 {"trx-bind", 1, 0, 'b'},
178 /* NOTE: 'trx-ip' is now an alias for 'trx-remote'
179 * due to backward compatibility reasons! */
180 {"trx-ip", 1, 0, 'i'},
181 {"trx-remote", 1, 0, 'i'},
182 {"trx-port", 1, 0, 'p'},
183 {"trx-advance", 1, 0, 'f'},
184 {"gsmtap-ip", 1, 0, 'g'},
185 {"daemonize", 0, 0, 'D'},
186 {0, 0, 0, 0}
189 c = getopt_long(argc, argv, "d:b:i:p:f:s:g:Dh",
190 long_options, &option_index);
191 if (c == -1)
192 break;
194 switch (c) {
195 case 'h':
196 print_usage(argv[0]);
197 print_help();
198 exit(0);
199 break;
200 case 'd':
201 app_data.debug_mask = optarg;
202 break;
203 case 'b':
204 app_data.trx_bind_ip = optarg;
205 break;
206 case 'i':
207 app_data.trx_remote_ip = optarg;
208 break;
209 case 'p':
210 app_data.trx_base_port = atoi(optarg);
211 break;
212 case 'f':
213 app_data.trx_fn_advance = atoi(optarg);
214 break;
215 case 's':
216 app_data.bind_socket = optarg;
217 break;
218 case 'g':
219 app_data.gsmtap_ip = optarg;
220 break;
221 case 'D':
222 app_data.daemonize = 1;
223 break;
224 default:
225 break;
230 static void init_defaults(void)
232 app_data.bind_socket = "/tmp/osmocom_l2";
233 app_data.trx_remote_ip = "127.0.0.1";
234 app_data.trx_bind_ip = "0.0.0.0";
235 app_data.trx_base_port = 6700;
236 app_data.trx_fn_advance = 20;
238 app_data.debug_mask = NULL;
239 app_data.gsmtap_ip = NULL;
240 app_data.daemonize = 0;
241 app_data.quit = 0;
244 static void signal_handler(int signal)
246 fprintf(stderr, "signal %u received\n", signal);
248 switch (signal) {
249 case SIGINT:
250 app_data.quit++;
251 break;
252 case SIGABRT:
253 case SIGUSR1:
254 case SIGUSR2:
255 talloc_report_full(tall_trxcon_ctx, stderr);
256 break;
257 default:
258 break;
262 int main(int argc, char **argv)
264 int rc = 0;
266 printf("%s", COPYRIGHT);
267 init_defaults();
268 handle_options(argc, argv);
270 /* Track the use of talloc NULL memory contexts */
271 talloc_enable_null_tracking();
273 /* Init talloc memory management system */
274 tall_trxcon_ctx = talloc_init("trxcon context");
275 msgb_talloc_ctx_init(tall_trxcon_ctx, 0);
277 /* Setup signal handlers */
278 signal(SIGINT, &signal_handler);
279 signal(SIGUSR1, &signal_handler);
280 signal(SIGUSR2, &signal_handler);
281 osmo_init_ignore_signals();
283 /* Init logging system */
284 trx_log_init(tall_trxcon_ctx, app_data.debug_mask);
286 /* Optional GSMTAP */
287 if (app_data.gsmtap_ip != NULL) {
288 gsmtap = gsmtap_source_init(app_data.gsmtap_ip, GSMTAP_UDP_PORT, 1);
289 if (!gsmtap) {
290 LOGP(DAPP, LOGL_ERROR, "Failed to init GSMTAP\n");
291 goto exit;
293 /* Suppress ICMP "destination unreachable" errors */
294 gsmtap_source_add_sink(gsmtap);
297 /* Allocate the application state machine */
298 OSMO_ASSERT(osmo_fsm_register(&trxcon_fsm_def) == 0);
299 trxcon_fsm = osmo_fsm_inst_alloc(&trxcon_fsm_def, tall_trxcon_ctx,
300 NULL, LOGL_DEBUG, "main");
302 /* Init L1CTL server */
303 app_data.l1l = l1ctl_link_init(tall_trxcon_ctx,
304 app_data.bind_socket);
305 if (app_data.l1l == NULL)
306 goto exit;
308 /* Init transceiver interface */
309 app_data.trx = trx_if_open(tall_trxcon_ctx,
310 app_data.trx_bind_ip, app_data.trx_remote_ip,
311 app_data.trx_base_port);
312 if (!app_data.trx)
313 goto exit;
315 /* Bind L1CTL with TRX and vice versa */
316 app_data.l1l->trx = app_data.trx;
317 app_data.trx->l1l = app_data.l1l;
319 /* Init scheduler */
320 rc = sched_trx_init(app_data.trx, app_data.trx_fn_advance);
321 if (rc)
322 goto exit;
324 LOGP(DAPP, LOGL_NOTICE, "Init complete\n");
326 if (app_data.daemonize) {
327 rc = osmo_daemonize();
328 if (rc < 0) {
329 perror("Error during daemonize");
330 goto exit;
334 /* Initialize pseudo-random generator */
335 srand(time(NULL));
337 while (!app_data.quit)
338 osmo_select_main(0);
340 exit:
341 /* Close active connections */
342 l1ctl_link_shutdown(app_data.l1l);
343 sched_trx_shutdown(app_data.trx);
344 trx_if_close(app_data.trx);
346 /* Shutdown main state machine */
347 osmo_fsm_inst_free(trxcon_fsm);
349 /* Deinitialize logging */
350 log_fini();
353 * Print report for the root talloc context in order
354 * to be able to find and fix potential memory leaks.
356 talloc_report_full(tall_trxcon_ctx, stderr);
357 talloc_free(tall_trxcon_ctx);
359 /* Make both Valgrind and ASAN happy */
360 talloc_report_full(NULL, stderr);
361 talloc_disable_null_tracking();
363 return rc;