blob: 6aed7c98201de08479692a095cb25116a1b5dfd1 [file] [log] [blame]
Holger Hans Peter Freyther89d9fd92010-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 Freythere8fa0f12010-01-12 21:34:54 +01006 * (C) 2009 by Harald Welte <laforge@gnumonks.org>
Holger Hans Peter Freyther89d9fd92010-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 Freythere8fa0f12010-01-12 21:34:54 +010028#include <errno.h>
Holger Hans Peter Freythere907cb22010-01-12 21:15:08 +010029#include <signal.h>
Holger Hans Peter Freyther89d9fd92010-06-15 18:44:42 +080030#include <stdio.h>
31#include <stdlib.h>
Holger Hans Peter Freytherfd012d52010-01-12 21:36:08 +010032#include <time.h>
Holger Hans Peter Freyther89d9fd92010-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 Freythere907cb22010-01-12 21:15:08 +010039#include <openbsc/msgb.h>
40#include <openbsc/bsc_msc.h>
41#include <openbsc/ipaccess.h>
42#include <openbsc/abis_nm.h>
43#include <openbsc/talloc.h>
Holger Hans Peter Freyther4a629602010-01-13 09:28:12 +010044#include <openbsc/linuxlist.h>
Holger Hans Peter Freyther89d9fd92010-06-15 18:44:42 +080045
46static const char *config_file = "openbsc.cfg";
47static char *msc_address = "127.0.0.1";
48static struct in_addr local_addr;
Holger Hans Peter Freythere907cb22010-01-12 21:15:08 +010049static struct bsc_fd msc_connection;
Holger Hans Peter Freythere8fa0f12010-01-12 21:34:54 +010050static struct bsc_fd bsc_connection;
Holger Hans Peter Freythere907cb22010-01-12 21:15:08 +010051
Holger Hans Peter Freyther4a629602010-01-13 09:28:12 +010052
53/*
54 * Per BSC data structure
55 */
56struct bsc_connection {
57 struct llist_head list_entry;
58
59 /* do we know anything about this BSC? */
60 int authenticated;
61
62 /* the fd we use to communicate */
63 struct bsc_fd bsc_fd;
64};
65
66static LLIST_HEAD(bsc_connections);
67
Holger Hans Peter Freythere907cb22010-01-12 21:15:08 +010068/*
69 * below are stubs we need to link
70 */
71int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
72 struct gsm_nm_state *old_state, struct gsm_nm_state *new_state)
73{
74 return -1;
75}
76
77void input_event(int event, enum e1inp_sign_type type, struct gsm_bts_trx *trx)
78{}
79
80int gsm0408_rcvmsg(struct msgb *msg, u_int8_t link_id)
81{
82 return -1;
83}
84
85/*
86 * Below is the handling of messages coming
87 * from the MSC and need to be forwarded to
88 * a real BSC.
89 */
90static void initialize_msc_if_needed()
91{
92 static int init = 0;
93 init = 1;
94
95 /* do we need to send a GSM 08.08 message here? */
96}
97
98static void forward_sccp_to_bts(struct msgb *msg)
99{
Holger Hans Peter Freyther4a629602010-01-13 09:28:12 +0100100 struct bsc_connection *bsc;
101
Holger Hans Peter Freythere907cb22010-01-12 21:15:08 +0100102 /* filter, drop, patch the message? */
Holger Hans Peter Freyther4a629602010-01-13 09:28:12 +0100103
104 /* currently send this to every BSC connected */
105 llist_for_each_entry(bsc, &bsc_connections, list_entry) {
Holger Hans Peter Freyther57a6ac82010-01-13 15:22:20 +0100106 write(bsc->bsc_fd.fd, msg->data, msg->len);
Holger Hans Peter Freyther4a629602010-01-13 09:28:12 +0100107 }
Holger Hans Peter Freythere907cb22010-01-12 21:15:08 +0100108}
109
110static int ipaccess_msc_cb(struct bsc_fd *bfd, unsigned int what)
111{
112 int error;
113 struct msgb *msg = ipaccess_read_msg(bfd, &error);
114 struct ipaccess_head *hh;
115
116 if (!msg) {
117 if (error == 0) {
118 fprintf(stderr, "The connection to the MSC was lost, exiting\n");
119 exit(-2);
120 }
121
122 fprintf(stderr, "Failed to parse ip access message: %d\n", error);
123 return -1;
124 }
125
126 DEBUGP(DMSC, "MSG from MSC: %s proto: %d\n", hexdump(msg->data, msg->len), msg->l2h[0]);
127
128 /* handle base message handling */
129 hh = (struct ipaccess_head *) msg->data;
130 ipaccess_rcvmsg_base(msg, bfd);
131
132 /* initialize the networking. This includes sending a GSM08.08 message */
133 if (hh->proto == IPAC_PROTO_IPACCESS && msg->l2h[0] == IPAC_MSGT_ID_ACK)
134 initialize_msc_if_needed();
135 else if (hh->proto == IPAC_PROTO_SCCP)
136 forward_sccp_to_bts(msg);
137
138 return 0;
139}
Holger Hans Peter Freyther89d9fd92010-06-15 18:44:42 +0800140
Holger Hans Peter Freythere8fa0f12010-01-12 21:34:54 +0100141/*
142 * Below is the handling of messages coming
143 * from the BSC and need to be forwarded to
144 * a real BSC.
145 */
Holger Hans Peter Freyther4a629602010-01-13 09:28:12 +0100146
147/*
148 * Remove the connection from the connections list,
149 * remove it from the patching of SCCP header lists
150 * as well. Maybe in the future even close connection..
151 */
152static void remove_bsc_connection(struct bsc_connection *connection)
153{
Holger Hans Peter Freytherb8567c82010-01-13 09:51:23 +0100154 bsc_unregister_fd(&connection->bsc_fd);
Holger Hans Peter Freyther4a629602010-01-13 09:28:12 +0100155 llist_del(&connection->list_entry);
156 talloc_free(connection);
157}
158
159static int forward_sccp_to_msc(struct msgb *msg)
160{
161 /* FIXME: We need to filter out certain messages */
162
163 /* send the non-filtered but maybe modified msg */
Holger Hans Peter Freyther57a6ac82010-01-13 15:22:20 +0100164 return write(msc_connection.fd, msg->data, msg->len);
Holger Hans Peter Freyther4a629602010-01-13 09:28:12 +0100165}
166
167static int ipaccess_bsc_cb(struct bsc_fd *bfd, unsigned int what)
168{
169 int error;
170 struct msgb *msg = ipaccess_read_msg(bfd, &error);
171 struct ipaccess_head *hh;
172
173 if (!msg) {
174 if (error == 0) {
175 fprintf(stderr, "The connection to the BSC was lost. Cleaning it\n");
176 remove_bsc_connection((struct bsc_connection *) bfd->data);
177 }
178
179 fprintf(stderr, "Failed to parse ip access message: %d\n", error);
180 return -1;
181 }
182
183 DEBUGP(DMSC, "MSG from BSC: %s proto: %d\n", hexdump(msg->data, msg->len), msg->l2h[0]);
184
185 /* handle base message handling */
186 hh = (struct ipaccess_head *) msg->data;
187
188 /* Handle messages from the BSC */
189 /* FIXME: Currently no PONG is sent to the BSC */
190 /* FIXME: Currently no ID ACK is sent to the BSC */
191 if (hh->proto == IPAC_PROTO_SCCP)
192 forward_sccp_to_msc(msg);
193
194 return 0;
195}
196
Holger Hans Peter Freythere8fa0f12010-01-12 21:34:54 +0100197static int ipaccess_listen_bsc_cb(struct bsc_fd *bfd, unsigned int what)
198{
Holger Hans Peter Freyther4a629602010-01-13 09:28:12 +0100199 struct bsc_connection *bsc;
Holger Hans Peter Freythere8fa0f12010-01-12 21:34:54 +0100200 int ret;
201 struct sockaddr_in sa;
202 socklen_t sa_len = sizeof(sa);
203
204 if (!(what & BSC_FD_READ))
205 return 0;
206
207 ret = accept(bfd->fd, (struct sockaddr *) &sa, &sa_len);
208 if (ret < 0) {
209 perror("accept");
210 return ret;
211 }
212
213 /* todo... do something with the connection */
Holger Hans Peter Freyther738dbdf2010-01-12 21:35:32 +0100214 /* todo... use GNUtls to see if we want to trust this as a BTS */
Holger Hans Peter Freythere8fa0f12010-01-12 21:34:54 +0100215
Holger Hans Peter Freyther4a629602010-01-13 09:28:12 +0100216 /*
217 *
218 */
219 bsc = talloc_zero(tall_bsc_ctx, struct bsc_connection);
220 if (!bsc) {
221 DEBUGP(DMSC, "Failed to allocate BSC struct.\n");
222 close(ret);
223 return -1;
224 }
225
226 bsc->bsc_fd.data = bsc;
227 bsc->bsc_fd.fd = ret;
228 bsc->bsc_fd.cb = ipaccess_bsc_cb;
Holger Hans Peter Freyther058519d2010-01-13 09:52:29 +0100229 bsc->bsc_fd.when = BSC_FD_READ;
Holger Hans Peter Freyther4a629602010-01-13 09:28:12 +0100230 if (bsc_register_fd(&bsc->bsc_fd) < 0) {
231 DEBUGP(DMSC, "Failed to register BSC fd.\n");
232 close(ret);
233 talloc_free(bsc);
234 return -2;
235 }
236
237 DEBUGP(DMSC, "Registered new BSC\n");
238 llist_add(&bsc->list_entry, &bsc_connections);
239 ipaccess_send_id_ack(ret);
Holger Hans Peter Freythere8fa0f12010-01-12 21:34:54 +0100240 return 0;
241}
242
243static int listen_for_bsc(struct bsc_fd *bfd, struct in_addr *in_addr, int port)
244{
245 struct sockaddr_in addr;
246 int ret, on = 1;
247
248 bfd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
249 bfd->cb = ipaccess_listen_bsc_cb;
250 bfd->when = BSC_FD_READ;
251
252 memset(&addr, 0, sizeof(addr));
253 addr.sin_family = AF_INET;
254 addr.sin_port = htons(port);
255 addr.sin_addr.s_addr = in_addr->s_addr;
256
257 setsockopt(bfd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
258
259 ret = bind(bfd->fd, (struct sockaddr *) &addr, sizeof(addr));
260 if (ret < 0) {
261 fprintf(stderr, "Could not bind the BSC socket %s\n",
262 strerror(errno));
263 return -EIO;
264 }
265
266 ret = listen(bfd->fd, 1);
267 if (ret < 0) {
268 perror("listen");
269 return ret;
270 }
271
272 ret = bsc_register_fd(bfd);
273 if (ret < 0) {
274 perror("register_listen_fd");
275 return ret;
276 }
277 return 0;
278}
279
Holger Hans Peter Freyther89d9fd92010-06-15 18:44:42 +0800280static void print_usage()
281{
282 printf("Usage: bsc_nat\n");
283}
284
285static void print_help()
286{
287 printf(" Some useful help...\n");
288 printf(" -h --help this text\n");
289 printf(" -d option --debug=DRLL:DCC:DMM:DRR:DRSL:DNM enable debugging\n");
290 printf(" -s --disable-color\n");
291 printf(" -c --config-file filename The config file to use.\n");
292 printf(" -m --msc=IP. The address of the MSC.\n");
Holger Hans Peter Freythere8fa0f12010-01-12 21:34:54 +0100293 printf(" -l --local=IP. The local address of this BSC.\n");
Holger Hans Peter Freyther89d9fd92010-06-15 18:44:42 +0800294}
295
296static void handle_options(int argc, char** argv)
297{
298 while (1) {
299 int option_index = 0, c;
300 static struct option long_options[] = {
301 {"help", 0, 0, 'h'},
302 {"debug", 1, 0, 'd'},
303 {"config-file", 1, 0, 'c'},
304 {"disable-color", 0, 0, 's'},
305 {"timestamp", 0, 0, 'T'},
306 {"msc", 1, 0, 'm'},
307 {"local", 1, 0, 'l'},
308 {0, 0, 0, 0}
309 };
310
311 c = getopt_long(argc, argv, "hd:sTPc:m:l:",
312 long_options, &option_index);
313 if (c == -1)
314 break;
315
316 switch (c) {
317 case 'h':
318 print_usage();
319 print_help();
320 exit(0);
321 case 's':
322 debug_use_color(0);
323 break;
324 case 'd':
325 debug_parse_category_mask(optarg);
326 break;
327 case 'c':
328 config_file = strdup(optarg);
329 break;
330 case 'T':
331 debug_timestamp(1);
332 break;
333 case 'm':
334 msc_address = strdup(optarg);
335 break;
336 case 'l':
337 inet_aton(optarg, &local_addr);
338 break;
339 default:
340 /* ignore */
341 break;
342 }
343 }
344}
345
Holger Hans Peter Freythere907cb22010-01-12 21:15:08 +0100346static void signal_handler(int signal)
347{
348 fprintf(stdout, "signal %u received\n", signal);
349
350 switch (signal) {
351 case SIGABRT:
352 /* in case of abort, we want to obtain a talloc report
353 * and then return to the caller, who will abort the process */
354 case SIGUSR1:
355 talloc_report_full(tall_bsc_ctx, stderr);
356 break;
357 default:
358 break;
359 }
360}
361
Holger Hans Peter Freyther89d9fd92010-06-15 18:44:42 +0800362int main(int argc, char** argv)
363{
Holger Hans Peter Freythere907cb22010-01-12 21:15:08 +0100364 int rc;
365
Holger Hans Peter Freyther89d9fd92010-06-15 18:44:42 +0800366 /* parse options */
Holger Hans Peter Freythere8fa0f12010-01-12 21:34:54 +0100367 local_addr.s_addr = INADDR_ANY;
Holger Hans Peter Freyther89d9fd92010-06-15 18:44:42 +0800368 handle_options(argc, argv);
369
370 /* seed the PRNG */
371 srand(time(NULL));
372
Holger Hans Peter Freythere8fa0f12010-01-12 21:34:54 +0100373 /* connect to the MSC */
Holger Hans Peter Freythere907cb22010-01-12 21:15:08 +0100374 msc_connection.cb = ipaccess_msc_cb;
375 rc = connect_to_msc(&msc_connection, msc_address, 5000);
376 if (rc < 0) {
377 fprintf(stderr, "Opening the MSC connection failed.\n");
378 exit(1);
379 }
380
Holger Hans Peter Freythere8fa0f12010-01-12 21:34:54 +0100381 /* wait for the BSC */
382 if (listen_for_bsc(&bsc_connection, &local_addr, 5000) < 0) {
383 fprintf(stderr, "Failed to listen for BSC.\n");
384 exit(1);
385 }
386
Holger Hans Peter Freythere907cb22010-01-12 21:15:08 +0100387 signal(SIGINT, &signal_handler);
388 signal(SIGABRT, &signal_handler);
389 signal(SIGUSR1, &signal_handler);
390 signal(SIGPIPE, SIG_IGN);
391
392 while (1) {
393 bsc_select_main(0);
394 }
395
Holger Hans Peter Freyther89d9fd92010-06-15 18:44:42 +0800396 return 0;
397}