blob: 7a44d17837306ab96e1c20e21960c814129be83b [file] [log] [blame]
Holger Hans Peter Freyther9e2c5f52010-06-15 18:44:42 +08001/* BSC Multiplexer/NAT */
2
3/*
4 * (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
5 * (C) 2010 by on-waves.com
Holger Hans Peter Freyther49d80682010-01-12 21:34:54 +01006 * (C) 2009 by Harald Welte <laforge@gnumonks.org>
Holger Hans Peter Freyther9e2c5f52010-06-15 18:44:42 +08007 * All Rights Reserved
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 *
23 */
24#include <sys/socket.h>
25#include <netinet/in.h>
26#include <arpa/inet.h>
27
Holger Hans Peter Freyther49d80682010-01-12 21:34:54 +010028#include <errno.h>
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +010029#include <signal.h>
Holger Hans Peter Freyther9e2c5f52010-06-15 18:44:42 +080030#include <stdio.h>
31#include <stdlib.h>
Holger Hans Peter Freyther5aa25ae2010-01-12 21:36:08 +010032#include <time.h>
Holger Hans Peter Freyther9e2c5f52010-06-15 18:44:42 +080033#include <unistd.h>
34
35#define _GNU_SOURCE
36#include <getopt.h>
37
38#include <openbsc/debug.h>
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +010039#include <openbsc/msgb.h>
40#include <openbsc/bsc_msc.h>
Holger Hans Peter Freyther6a97b8d2010-06-15 18:45:26 +080041#include <openbsc/bsc_nat.h>
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +010042#include <openbsc/ipaccess.h>
43#include <openbsc/abis_nm.h>
44#include <openbsc/talloc.h>
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +010045#include <openbsc/linuxlist.h>
Holger Hans Peter Freyther9e2c5f52010-06-15 18:44:42 +080046
Holger Hans Peter Freyther6a97b8d2010-06-15 18:45:26 +080047#include <sccp/sccp.h>
48
Holger Hans Peter Freyther9e2c5f52010-06-15 18:44:42 +080049static const char *config_file = "openbsc.cfg";
50static char *msc_address = "127.0.0.1";
51static struct in_addr local_addr;
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +010052static struct bsc_fd msc_connection;
Holger Hans Peter Freyther49d80682010-01-12 21:34:54 +010053static struct bsc_fd bsc_connection;
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +010054
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +010055
56/*
57 * Per BSC data structure
58 */
59struct bsc_connection {
60 struct llist_head list_entry;
61
62 /* do we know anything about this BSC? */
63 int authenticated;
64
65 /* the fd we use to communicate */
66 struct bsc_fd bsc_fd;
67};
68
69static LLIST_HEAD(bsc_connections);
70
Holger Hans Peter Freyther6a97b8d2010-06-15 18:45:26 +080071
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +010072/*
73 * below are stubs we need to link
74 */
75int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
76 struct gsm_nm_state *old_state, struct gsm_nm_state *new_state)
77{
78 return -1;
79}
80
81void input_event(int event, enum e1inp_sign_type type, struct gsm_bts_trx *trx)
82{}
83
84int gsm0408_rcvmsg(struct msgb *msg, u_int8_t link_id)
85{
86 return -1;
87}
88
89/*
90 * Below is the handling of messages coming
91 * from the MSC and need to be forwarded to
92 * a real BSC.
93 */
94static void initialize_msc_if_needed()
95{
96 static int init = 0;
97 init = 1;
98
99 /* do we need to send a GSM 08.08 message here? */
100}
101
102static void forward_sccp_to_bts(struct msgb *msg)
103{
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100104 struct bsc_connection *bsc;
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +0800105 struct bsc_nat_parsed *parsed;
Holger Hans Peter Freyther60046642010-01-25 10:01:30 +0100106 int rc;
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100107
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +0100108 /* filter, drop, patch the message? */
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +0800109 parsed = bsc_nat_parse(msg);
110 if (!parsed) {
111 LOGP(DNAT, LOGL_ERROR, "Can not parse msg from BSC.\n");
Holger Hans Peter Freyther6a97b8d2010-06-15 18:45:26 +0800112 return;
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +0800113 }
114
Holger Hans Peter Freyther1d6fb182010-01-30 11:53:30 +0100115 if (bsc_nat_filter_ipa(DIR_BSC, msg, parsed))
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +0800116 goto exit;
Holger Hans Peter Freyther6a97b8d2010-06-15 18:45:26 +0800117
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100118 /* currently send this to every BSC connected */
119 llist_for_each_entry(bsc, &bsc_connections, list_entry) {
Holger Hans Peter Freyther60046642010-01-25 10:01:30 +0100120 rc = write(bsc->bsc_fd.fd, msg->data, msg->len);
121
122 /* try the next one */
123 if (rc < msg->len)
Holger Hans Peter Freyther418f3942010-01-29 05:58:43 +0100124 LOGP(DNAT, LOGL_ERROR, "Failed to write message to BTS: %d\n", rc);
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100125 }
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +0800126
127exit:
128 talloc_free(parsed);
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +0100129}
130
131static int ipaccess_msc_cb(struct bsc_fd *bfd, unsigned int what)
132{
133 int error;
134 struct msgb *msg = ipaccess_read_msg(bfd, &error);
135 struct ipaccess_head *hh;
136
137 if (!msg) {
138 if (error == 0) {
Holger Hans Peter Freyther418f3942010-01-29 05:58:43 +0100139 LOGP(DNAT, LOGL_FATAL, "The connection the MSC was lost, exiting\n");
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +0100140 exit(-2);
141 }
142
Holger Hans Peter Freyther418f3942010-01-29 05:58:43 +0100143 LOGP(DNAT, LOGL_ERROR, "Failed to parse ip access message: %d\n", error);
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +0100144 return -1;
145 }
146
Holger Hans Peter Freyther418f3942010-01-29 05:58:43 +0100147 LOGP(DNAT, LOGL_DEBUG, "MSG from MSC: %s proto: %d\n", hexdump(msg->data, msg->len), msg->l2h[0]);
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +0100148
149 /* handle base message handling */
150 hh = (struct ipaccess_head *) msg->data;
151 ipaccess_rcvmsg_base(msg, bfd);
152
153 /* initialize the networking. This includes sending a GSM08.08 message */
154 if (hh->proto == IPAC_PROTO_IPACCESS && msg->l2h[0] == IPAC_MSGT_ID_ACK)
155 initialize_msc_if_needed();
156 else if (hh->proto == IPAC_PROTO_SCCP)
157 forward_sccp_to_bts(msg);
158
159 return 0;
160}
Holger Hans Peter Freyther9e2c5f52010-06-15 18:44:42 +0800161
Holger Hans Peter Freyther49d80682010-01-12 21:34:54 +0100162/*
163 * Below is the handling of messages coming
164 * from the BSC and need to be forwarded to
165 * a real BSC.
166 */
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100167
168/*
169 * Remove the connection from the connections list,
170 * remove it from the patching of SCCP header lists
171 * as well. Maybe in the future even close connection..
172 */
173static void remove_bsc_connection(struct bsc_connection *connection)
174{
Holger Hans Peter Freyther76255062010-01-13 09:51:23 +0100175 bsc_unregister_fd(&connection->bsc_fd);
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100176 llist_del(&connection->list_entry);
177 talloc_free(connection);
178}
179
180static int forward_sccp_to_msc(struct msgb *msg)
181{
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +0800182 struct bsc_nat_parsed *parsed;
183 int rc = -1;
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100184
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +0800185 /* Parse and filter messages */
186 parsed = bsc_nat_parse(msg);
187 if (!parsed) {
188 LOGP(DNAT, LOGL_ERROR, "Can not parse msg from BSC.\n");
189 return -1;
190 }
191
Holger Hans Peter Freyther1d6fb182010-01-30 11:53:30 +0100192 if (bsc_nat_filter_ipa(DIR_MSC, msg, parsed))
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +0800193 goto exit;
Holger Hans Peter Freyther6a97b8d2010-06-15 18:45:26 +0800194
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100195 /* send the non-filtered but maybe modified msg */
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +0800196 rc = write(msc_connection.fd, msg->data, msg->len);
197
198exit:
199 talloc_free(parsed);
200 return rc;
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100201}
202
203static int ipaccess_bsc_cb(struct bsc_fd *bfd, unsigned int what)
204{
205 int error;
206 struct msgb *msg = ipaccess_read_msg(bfd, &error);
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100207
208 if (!msg) {
209 if (error == 0) {
Holger Hans Peter Freyther418f3942010-01-29 05:58:43 +0100210 LOGP(DNAT, LOGL_ERROR, "The connection to the BSC was lost. Cleaning it\n");
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100211 remove_bsc_connection((struct bsc_connection *) bfd->data);
Holger Hans Peter Freyther418f3942010-01-29 05:58:43 +0100212 } else {
213 LOGP(DNAT, LOGL_ERROR, "Failed to parse ip access message: %d\n", error);
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100214 }
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100215 return -1;
216 }
217
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100218
Holger Hans Peter Freyther418f3942010-01-29 05:58:43 +0100219 LOGP(DNAT, LOGL_DEBUG, "MSG from BSC: %s proto: %d\n", hexdump(msg->data, msg->len), msg->l2h[0]);
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100220
221 /* Handle messages from the BSC */
222 /* FIXME: Currently no PONG is sent to the BSC */
223 /* FIXME: Currently no ID ACK is sent to the BSC */
Holger Hans Peter Freyther6a97b8d2010-06-15 18:45:26 +0800224 forward_sccp_to_msc(msg);
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100225
226 return 0;
227}
228
Holger Hans Peter Freyther49d80682010-01-12 21:34:54 +0100229static int ipaccess_listen_bsc_cb(struct bsc_fd *bfd, unsigned int what)
230{
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100231 struct bsc_connection *bsc;
Holger Hans Peter Freyther49d80682010-01-12 21:34:54 +0100232 int ret;
233 struct sockaddr_in sa;
234 socklen_t sa_len = sizeof(sa);
235
236 if (!(what & BSC_FD_READ))
237 return 0;
238
239 ret = accept(bfd->fd, (struct sockaddr *) &sa, &sa_len);
240 if (ret < 0) {
241 perror("accept");
242 return ret;
243 }
244
245 /* todo... do something with the connection */
Holger Hans Peter Freytherda86c0a2010-01-12 21:35:32 +0100246 /* todo... use GNUtls to see if we want to trust this as a BTS */
Holger Hans Peter Freyther49d80682010-01-12 21:34:54 +0100247
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100248 /*
249 *
250 */
251 bsc = talloc_zero(tall_bsc_ctx, struct bsc_connection);
252 if (!bsc) {
Holger Hans Peter Freyther418f3942010-01-29 05:58:43 +0100253 LOGP(DNAT, LOGL_ERROR, "Failed to allocate BSC struct.\n");
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100254 close(ret);
255 return -1;
256 }
257
258 bsc->bsc_fd.data = bsc;
259 bsc->bsc_fd.fd = ret;
260 bsc->bsc_fd.cb = ipaccess_bsc_cb;
Holger Hans Peter Freytherc7641c92010-01-13 09:52:29 +0100261 bsc->bsc_fd.when = BSC_FD_READ;
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100262 if (bsc_register_fd(&bsc->bsc_fd) < 0) {
Holger Hans Peter Freyther418f3942010-01-29 05:58:43 +0100263 LOGP(DNAT, LOGL_ERROR, "Failed to register BSC fd.\n");
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100264 close(ret);
265 talloc_free(bsc);
266 return -2;
267 }
268
Holger Hans Peter Freyther418f3942010-01-29 05:58:43 +0100269 LOGP(DNAT, LOGL_INFO, "Registered new BSC\n");
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100270 llist_add(&bsc->list_entry, &bsc_connections);
271 ipaccess_send_id_ack(ret);
Holger Hans Peter Freyther49d80682010-01-12 21:34:54 +0100272 return 0;
273}
274
275static int listen_for_bsc(struct bsc_fd *bfd, struct in_addr *in_addr, int port)
276{
277 struct sockaddr_in addr;
278 int ret, on = 1;
279
280 bfd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
281 bfd->cb = ipaccess_listen_bsc_cb;
282 bfd->when = BSC_FD_READ;
283
284 memset(&addr, 0, sizeof(addr));
285 addr.sin_family = AF_INET;
286 addr.sin_port = htons(port);
287 addr.sin_addr.s_addr = in_addr->s_addr;
288
289 setsockopt(bfd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
290
291 ret = bind(bfd->fd, (struct sockaddr *) &addr, sizeof(addr));
292 if (ret < 0) {
293 fprintf(stderr, "Could not bind the BSC socket %s\n",
294 strerror(errno));
295 return -EIO;
296 }
297
298 ret = listen(bfd->fd, 1);
299 if (ret < 0) {
300 perror("listen");
301 return ret;
302 }
303
304 ret = bsc_register_fd(bfd);
305 if (ret < 0) {
306 perror("register_listen_fd");
307 return ret;
308 }
309 return 0;
310}
311
Holger Hans Peter Freyther9e2c5f52010-06-15 18:44:42 +0800312static void print_usage()
313{
314 printf("Usage: bsc_nat\n");
315}
316
317static void print_help()
318{
319 printf(" Some useful help...\n");
320 printf(" -h --help this text\n");
321 printf(" -d option --debug=DRLL:DCC:DMM:DRR:DRSL:DNM enable debugging\n");
322 printf(" -s --disable-color\n");
323 printf(" -c --config-file filename The config file to use.\n");
324 printf(" -m --msc=IP. The address of the MSC.\n");
Holger Hans Peter Freyther49d80682010-01-12 21:34:54 +0100325 printf(" -l --local=IP. The local address of this BSC.\n");
Holger Hans Peter Freyther9e2c5f52010-06-15 18:44:42 +0800326}
327
328static void handle_options(int argc, char** argv)
329{
330 while (1) {
331 int option_index = 0, c;
332 static struct option long_options[] = {
333 {"help", 0, 0, 'h'},
334 {"debug", 1, 0, 'd'},
335 {"config-file", 1, 0, 'c'},
336 {"disable-color", 0, 0, 's'},
337 {"timestamp", 0, 0, 'T'},
338 {"msc", 1, 0, 'm'},
339 {"local", 1, 0, 'l'},
340 {0, 0, 0, 0}
341 };
342
343 c = getopt_long(argc, argv, "hd:sTPc:m:l:",
344 long_options, &option_index);
345 if (c == -1)
346 break;
347
348 switch (c) {
349 case 'h':
350 print_usage();
351 print_help();
352 exit(0);
353 case 's':
354 debug_use_color(0);
355 break;
356 case 'd':
357 debug_parse_category_mask(optarg);
358 break;
359 case 'c':
360 config_file = strdup(optarg);
361 break;
362 case 'T':
363 debug_timestamp(1);
364 break;
365 case 'm':
366 msc_address = strdup(optarg);
367 break;
368 case 'l':
369 inet_aton(optarg, &local_addr);
370 break;
371 default:
372 /* ignore */
373 break;
374 }
375 }
376}
377
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +0100378static void signal_handler(int signal)
379{
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +0100380 switch (signal) {
381 case SIGABRT:
382 /* in case of abort, we want to obtain a talloc report
383 * and then return to the caller, who will abort the process */
384 case SIGUSR1:
385 talloc_report_full(tall_bsc_ctx, stderr);
386 break;
387 default:
388 break;
389 }
390}
391
Holger Hans Peter Freyther9e2c5f52010-06-15 18:44:42 +0800392int main(int argc, char** argv)
393{
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +0100394 int rc;
395
Holger Hans Peter Freyther9e2c5f52010-06-15 18:44:42 +0800396 /* parse options */
Holger Hans Peter Freyther49d80682010-01-12 21:34:54 +0100397 local_addr.s_addr = INADDR_ANY;
Holger Hans Peter Freyther9e2c5f52010-06-15 18:44:42 +0800398 handle_options(argc, argv);
399
400 /* seed the PRNG */
401 srand(time(NULL));
402
Holger Hans Peter Freyther49d80682010-01-12 21:34:54 +0100403 /* connect to the MSC */
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +0100404 msc_connection.cb = ipaccess_msc_cb;
405 rc = connect_to_msc(&msc_connection, msc_address, 5000);
406 if (rc < 0) {
407 fprintf(stderr, "Opening the MSC connection failed.\n");
408 exit(1);
409 }
410
Holger Hans Peter Freyther49d80682010-01-12 21:34:54 +0100411 /* wait for the BSC */
412 if (listen_for_bsc(&bsc_connection, &local_addr, 5000) < 0) {
413 fprintf(stderr, "Failed to listen for BSC.\n");
414 exit(1);
415 }
416
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +0100417 signal(SIGINT, &signal_handler);
418 signal(SIGABRT, &signal_handler);
419 signal(SIGUSR1, &signal_handler);
420 signal(SIGPIPE, SIG_IGN);
421
422 while (1) {
423 bsc_select_main(0);
424 }
425
Holger Hans Peter Freyther9e2c5f52010-06-15 18:44:42 +0800426 return 0;
427}