2 * OsmocomBB <-> SDR connection bridge
4 * (C) 2016-2019 by Vadim Yanitskiy <axilirator@gmail.com>
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.
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>
50 #include "l1ctl_link.h"
51 #include "l1ctl_proto.h"
52 #include "scheduler.h"
53 #include "sched_trx.h"
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"
63 const char *debug_mask
;
68 struct l1ctl_link
*l1l
;
69 const char *bind_socket
;
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
;
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
)
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
);
107 case TRX_EVENT_RSP_ERROR
:
108 case TRX_EVENT_OFFLINE
:
109 /* TODO: notify L2 & L3 about that */
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
),
121 .action
= trxcon_fsm_idle_action
,
123 [TRXCON_STATE_MANAGED
] = {
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
),
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
),
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
),
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
)
172 int option_index
= 0, c
;
173 static struct option long_options
[] = {
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'},
189 c
= getopt_long(argc
, argv
, "d:b:i:p:f:s:g:Dh",
190 long_options
, &option_index
);
196 print_usage(argv
[0]);
201 app_data
.debug_mask
= optarg
;
204 app_data
.trx_bind_ip
= optarg
;
207 app_data
.trx_remote_ip
= optarg
;
210 app_data
.trx_base_port
= atoi(optarg
);
213 app_data
.trx_fn_advance
= atoi(optarg
);
216 app_data
.bind_socket
= optarg
;
219 app_data
.gsmtap_ip
= optarg
;
222 app_data
.daemonize
= 1;
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;
244 static void signal_handler(int signal
)
246 fprintf(stderr
, "signal %u received\n", signal
);
255 talloc_report_full(tall_trxcon_ctx
, stderr
);
262 int main(int argc
, char **argv
)
266 printf("%s", COPYRIGHT
);
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);
290 LOGP(DAPP
, LOGL_ERROR
, "Failed to init GSMTAP\n");
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
)
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
);
315 /* Bind L1CTL with TRX and vice versa */
316 app_data
.l1l
->trx
= app_data
.trx
;
317 app_data
.trx
->l1l
= app_data
.l1l
;
320 rc
= sched_trx_init(app_data
.trx
, app_data
.trx_fn_advance
);
324 LOGP(DAPP
, LOGL_NOTICE
, "Init complete\n");
326 if (app_data
.daemonize
) {
327 rc
= osmo_daemonize();
329 perror("Error during daemonize");
334 /* Initialize pseudo-random generator */
337 while (!app_data
.quit
)
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 */
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();