blob: 2461f9e7030cbfdb822d9bbaae0ecbbcc0e393ad [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 Freyther38a77d02010-01-30 12:45:10 +010042#include <openbsc/bssap.h>
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +010043#include <openbsc/ipaccess.h>
44#include <openbsc/abis_nm.h>
45#include <openbsc/talloc.h>
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +010046#include <openbsc/linuxlist.h>
Holger Hans Peter Freyther9e2c5f52010-06-15 18:44:42 +080047
Holger Hans Peter Freyther6a97b8d2010-06-15 18:45:26 +080048#include <sccp/sccp.h>
49
Holger Hans Peter Freyther9e2c5f52010-06-15 18:44:42 +080050static const char *config_file = "openbsc.cfg";
51static char *msc_address = "127.0.0.1";
52static struct in_addr local_addr;
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +010053static struct bsc_fd msc_connection;
Holger Hans Peter Freyther49d80682010-01-12 21:34:54 +010054static struct bsc_fd bsc_connection;
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +010055
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +010056
57/*
58 * Per BSC data structure
59 */
60struct bsc_connection {
61 struct llist_head list_entry;
62
63 /* do we know anything about this BSC? */
64 int authenticated;
65
66 /* the fd we use to communicate */
67 struct bsc_fd bsc_fd;
68};
69
Holger Hans Peter Freyther058eeb72010-01-31 09:46:21 +010070/*
71 * Per SCCP source local reference patch table. It needs to
72 * be updated on new SCCP connections, connection confirm and reject,
73 * and on the loss of the BSC connection.
74 */
75struct sccp_connections {
76 struct llist_head list_entry;
77
78 struct bsc_connection *bsc;
79
80 struct sccp_source_reference real_ref;
81 struct sccp_source_reference patched_ref;
82};
83
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +010084static LLIST_HEAD(bsc_connections);
Holger Hans Peter Freyther058eeb72010-01-31 09:46:21 +010085static LLIST_HEAD(sccp_connections);
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +010086
Holger Hans Peter Freyther6a97b8d2010-06-15 18:45:26 +080087
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +010088/*
89 * below are stubs we need to link
90 */
91int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
92 struct gsm_nm_state *old_state, struct gsm_nm_state *new_state)
93{
94 return -1;
95}
96
97void input_event(int event, enum e1inp_sign_type type, struct gsm_bts_trx *trx)
98{}
99
100int gsm0408_rcvmsg(struct msgb *msg, u_int8_t link_id)
101{
102 return -1;
103}
104
Holger Hans Peter Freyther38a77d02010-01-30 12:45:10 +0100105static int send_reset_ack(struct bsc_fd *bfd)
106{
107 static const u_int8_t gsm_reset_ack[] = {
108 0x00, 0x13, 0xfd,
109 0x09, 0x00, 0x03, 0x07, 0x0b, 0x04, 0x43, 0x01,
110 0x00, 0xfe, 0x04, 0x43, 0x5c, 0x00, 0xfe, 0x03,
111 0x00, 0x01, 0x31,
112 };
113
114 return write(bfd->fd, gsm_reset_ack, sizeof(gsm_reset_ack));
115}
116
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +0100117/*
Holger Hans Peter Freyther058eeb72010-01-31 09:46:21 +0100118 * SCCP patching below
119 */
120
121/* check if we are using this ref for patched already */
122static int sccp_ref_is_free(struct sccp_source_reference *ref)
123{
124 struct sccp_connections *conn;
125
126 llist_for_each_entry(conn, &sccp_connections, list_entry) {
127 if (memcmp(ref, &conn->patched_ref, sizeof(*ref)) == 0)
128 return -1;
129 }
130
131 return 0;
132}
133
134/* copied from sccp.c */
135static int assign_src_local_reference(struct sccp_source_reference *ref)
136{
137 static u_int32_t last_ref = 0x50000;
138 int wrapped = 0;
139
140 do {
141 struct sccp_source_reference reference;
142 reference.octet1 = (last_ref >> 0) & 0xff;
143 reference.octet2 = (last_ref >> 8) & 0xff;
144 reference.octet3 = (last_ref >> 16) & 0xff;
145
146 ++last_ref;
147 /* do not use the reversed word and wrap around */
148 if ((last_ref & 0x00FFFFFF) == 0x00FFFFFF) {
149 LOGP(DNAT, LOGL_NOTICE, "Wrapped searching for a free code\n");
150 last_ref = 0;
151 ++wrapped;
152 }
153
154 if (sccp_ref_is_free(&reference) == 0) {
155 *ref = reference;
156 return 0;
157 }
158 } while (wrapped != 2);
159
160 LOGP(DNAT, LOGL_ERROR, "Finding a free reference failed\n");
161 return -1;
162}
163int create_sccp_src_ref(struct bsc_connection *bsc, struct msgb *msg, struct bsc_nat_parsed *parsed)
164{
165 struct sccp_connections *conn;
166
167 conn = talloc_zero(tall_bsc_ctx, struct sccp_connections);
168 if (!conn) {
169 LOGP(DNAT, LOGL_ERROR, "Memory allocation failure.\n");
170 return -1;
171 }
172
173 conn->real_ref = *parsed->src_local_ref;
174 if (assign_src_local_reference(&conn->patched_ref) != 0) {
175 LOGP(DNAT, LOGL_ERROR, "Failed to assign a ref.\n");
176 talloc_free(conn);
177 return -1;
178 }
179
180 return 0;
181}
182
183void remove_sccp_src_ref(struct bsc_connection *bsc, struct msgb *msg, struct bsc_nat_parsed *parsed)
184{
185 struct sccp_connections *conn;
186
187 llist_for_each_entry(conn, &sccp_connections, list_entry) {
188 if (memcmp(parsed->src_local_ref,
189 &conn->real_ref, sizeof(conn->real_ref)) == 0) {
190 if (bsc != conn->bsc) {
191 LOGP(DNAT, LOGL_ERROR, "Someone else...\n");
192 continue;
193 }
194
195
196 llist_del(&conn->list_entry);
197 talloc_free(conn);
198 return;
199 }
200 }
201
202 LOGP(DNAT, LOGL_ERROR, "Unknown connection.\n");
203}
204
205struct bsc_connection *patch_sccp_src_ref_to_bsc(struct msgb *msg, struct bsc_nat_parsed *parsed)
206{
207 struct sccp_connections *conn;
208 llist_for_each_entry(conn, &sccp_connections, list_entry) {
209 if (memcmp(parsed->dest_local_ref,
210 &conn->real_ref, sizeof(*parsed->dest_local_ref)) == 0) {
211 memcpy(parsed->dest_local_ref,
212 &conn->patched_ref, sizeof(*parsed->dest_local_ref));
213 return conn->bsc;
214 }
215 }
216
217 return NULL;
218}
219
220struct bsc_connection *patch_sccp_src_ref_to_msc(struct msgb *msg, struct bsc_nat_parsed *parsed)
221{
222 struct sccp_connections *conn;
223 llist_for_each_entry(conn, &sccp_connections, list_entry) {
224 if (memcmp(parsed->src_local_ref,
225 &conn->real_ref, sizeof(*parsed->src_local_ref)) == 0) {
226 memcpy(parsed->src_local_ref,
227 &conn->patched_ref, sizeof(*parsed->src_local_ref));
228 return conn->bsc;
229 }
230 }
231
232 return NULL;
233}
234
235/*
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +0100236 * Below is the handling of messages coming
237 * from the MSC and need to be forwarded to
238 * a real BSC.
239 */
240static void initialize_msc_if_needed()
241{
242 static int init = 0;
243 init = 1;
244
245 /* do we need to send a GSM 08.08 message here? */
246}
247
Holger Hans Peter Freyther058eeb72010-01-31 09:46:21 +0100248static int forward_sccp_to_bts(struct msgb *msg)
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +0100249{
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100250 struct bsc_connection *bsc;
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +0800251 struct bsc_nat_parsed *parsed;
Holger Hans Peter Freyther60046642010-01-25 10:01:30 +0100252 int rc;
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100253
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +0100254 /* filter, drop, patch the message? */
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +0800255 parsed = bsc_nat_parse(msg);
256 if (!parsed) {
257 LOGP(DNAT, LOGL_ERROR, "Can not parse msg from BSC.\n");
Holger Hans Peter Freyther058eeb72010-01-31 09:46:21 +0100258 return -1;
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +0800259 }
260
Holger Hans Peter Freyther1d6fb182010-01-30 11:53:30 +0100261 if (bsc_nat_filter_ipa(DIR_BSC, msg, parsed))
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +0800262 goto exit;
Holger Hans Peter Freyther6a97b8d2010-06-15 18:45:26 +0800263
Holger Hans Peter Freyther058eeb72010-01-31 09:46:21 +0100264 /* Route and modify the SCCP packet */
265 if (parsed->ipa_proto == IPAC_PROTO_SCCP) {
266 switch (parsed->sccp_type) {
267 case SCCP_MSG_TYPE_UDT:
268 /* forward UDT messages to every BSC */
269 goto send_to_all;
270 break;
271 case SCCP_MSG_TYPE_RLSD:
272 case SCCP_MSG_TYPE_CREF:
273 case SCCP_MSG_TYPE_DT1:
274 case SCCP_MSG_TYPE_CC:
275 bsc = patch_sccp_src_ref_to_bsc(msg, parsed);
276 break;
277 case SCCP_MSG_TYPE_CR:
278 case SCCP_MSG_TYPE_RLC:
279 /* MSC never opens a SCCP connection, fall through */
280 default:
281 goto exit;
282 }
283 }
284
285 talloc_free(parsed);
286 if (!bsc)
287 return -1;
288 return write(bsc->bsc_fd.fd, msg->data, msg->len);
289
290send_to_all:
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100291 /* currently send this to every BSC connected */
292 llist_for_each_entry(bsc, &bsc_connections, list_entry) {
Holger Hans Peter Freyther60046642010-01-25 10:01:30 +0100293 rc = write(bsc->bsc_fd.fd, msg->data, msg->len);
294
295 /* try the next one */
296 if (rc < msg->len)
Holger Hans Peter Freyther418f3942010-01-29 05:58:43 +0100297 LOGP(DNAT, LOGL_ERROR, "Failed to write message to BTS: %d\n", rc);
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100298 }
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +0800299
300exit:
301 talloc_free(parsed);
Holger Hans Peter Freyther058eeb72010-01-31 09:46:21 +0100302 return 0;
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +0100303}
304
305static int ipaccess_msc_cb(struct bsc_fd *bfd, unsigned int what)
306{
307 int error;
308 struct msgb *msg = ipaccess_read_msg(bfd, &error);
309 struct ipaccess_head *hh;
310
311 if (!msg) {
312 if (error == 0) {
Holger Hans Peter Freyther418f3942010-01-29 05:58:43 +0100313 LOGP(DNAT, LOGL_FATAL, "The connection the MSC was lost, exiting\n");
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +0100314 exit(-2);
315 }
316
Holger Hans Peter Freyther418f3942010-01-29 05:58:43 +0100317 LOGP(DNAT, LOGL_ERROR, "Failed to parse ip access message: %d\n", error);
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +0100318 return -1;
319 }
320
Holger Hans Peter Freyther418f3942010-01-29 05:58:43 +0100321 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 +0100322
323 /* handle base message handling */
324 hh = (struct ipaccess_head *) msg->data;
325 ipaccess_rcvmsg_base(msg, bfd);
326
327 /* initialize the networking. This includes sending a GSM08.08 message */
328 if (hh->proto == IPAC_PROTO_IPACCESS && msg->l2h[0] == IPAC_MSGT_ID_ACK)
329 initialize_msc_if_needed();
330 else if (hh->proto == IPAC_PROTO_SCCP)
331 forward_sccp_to_bts(msg);
332
333 return 0;
334}
Holger Hans Peter Freyther9e2c5f52010-06-15 18:44:42 +0800335
Holger Hans Peter Freyther49d80682010-01-12 21:34:54 +0100336/*
337 * Below is the handling of messages coming
338 * from the BSC and need to be forwarded to
339 * a real BSC.
340 */
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100341
342/*
343 * Remove the connection from the connections list,
344 * remove it from the patching of SCCP header lists
345 * as well. Maybe in the future even close connection..
346 */
347static void remove_bsc_connection(struct bsc_connection *connection)
348{
Holger Hans Peter Freyther058eeb72010-01-31 09:46:21 +0100349 struct sccp_connections *sccp_patch, *tmp;
Holger Hans Peter Freyther76255062010-01-13 09:51:23 +0100350 bsc_unregister_fd(&connection->bsc_fd);
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100351 llist_del(&connection->list_entry);
Holger Hans Peter Freyther058eeb72010-01-31 09:46:21 +0100352
353 /* remove all SCCP connections */
354 llist_for_each_entry_safe(sccp_patch, tmp, &sccp_connections, list_entry) {
355 if (sccp_patch->bsc != connection)
356 continue;
357
358 llist_del(&sccp_patch->list_entry);
359 talloc_free(sccp_patch);
360 }
361
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100362 talloc_free(connection);
363}
364
Holger Hans Peter Freyther38a77d02010-01-30 12:45:10 +0100365static int forward_sccp_to_msc(struct bsc_fd *bfd, struct msgb *msg)
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100366{
Holger Hans Peter Freyther058eeb72010-01-31 09:46:21 +0100367 struct bsc_connection *bsc;
368 struct bsc_connection *found_bsc;
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +0800369 struct bsc_nat_parsed *parsed;
370 int rc = -1;
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100371
Holger Hans Peter Freyther058eeb72010-01-31 09:46:21 +0100372 bsc = bfd->data;
373
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +0800374 /* Parse and filter messages */
375 parsed = bsc_nat_parse(msg);
376 if (!parsed) {
377 LOGP(DNAT, LOGL_ERROR, "Can not parse msg from BSC.\n");
378 return -1;
379 }
380
Holger Hans Peter Freyther1d6fb182010-01-30 11:53:30 +0100381 if (bsc_nat_filter_ipa(DIR_MSC, msg, parsed))
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +0800382 goto exit;
Holger Hans Peter Freyther6a97b8d2010-06-15 18:45:26 +0800383
Holger Hans Peter Freyther058eeb72010-01-31 09:46:21 +0100384 /* modify the SCCP entries */
385 if (parsed->ipa_proto == IPAC_PROTO_SCCP) {
386 switch (parsed->sccp_type) {
387 case SCCP_MSG_TYPE_CR:
388 if (create_sccp_src_ref(bsc, msg, parsed) != 0)
389 goto exit2;
390 found_bsc = patch_sccp_src_ref_to_msc(msg, parsed);
391 break;
392 case SCCP_MSG_TYPE_RLSD:
393 case SCCP_MSG_TYPE_CREF:
394 case SCCP_MSG_TYPE_DT1:
395 case SCCP_MSG_TYPE_CC:
396 found_bsc = patch_sccp_src_ref_to_msc(msg, parsed);
397 break;
398 case SCCP_MSG_TYPE_RLC:
399 found_bsc = patch_sccp_src_ref_to_msc(msg, parsed);
400 remove_sccp_src_ref(bsc, msg, parsed);
401 break;
402 case SCCP_MSG_TYPE_UDT:
403 /* simply forward everything */
404 break;
405 default:
406 goto exit2;
407 break;
408 }
409 }
410
411 if (found_bsc != bsc) {
412 LOGP(DNAT, LOGL_ERROR, "Found the wrong entry.\n");
413 goto exit2;
414 }
415
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100416 /* send the non-filtered but maybe modified msg */
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +0800417 rc = write(msc_connection.fd, msg->data, msg->len);
Holger Hans Peter Freyther38a77d02010-01-30 12:45:10 +0100418 talloc_free(parsed);
419 return rc;
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +0800420
421exit:
Holger Hans Peter Freyther38a77d02010-01-30 12:45:10 +0100422 /* if we filter out the reset send an ack to the BSC */
423 if (parsed->bssap == 0 && parsed->gsm_type == BSS_MAP_MSG_RESET) {
424 send_reset_ack(bfd);
425 send_reset_ack(bfd);
426 }
427
Holger Hans Peter Freyther058eeb72010-01-31 09:46:21 +0100428exit2:
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +0800429 talloc_free(parsed);
430 return rc;
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100431}
432
433static int ipaccess_bsc_cb(struct bsc_fd *bfd, unsigned int what)
434{
435 int error;
436 struct msgb *msg = ipaccess_read_msg(bfd, &error);
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100437
438 if (!msg) {
439 if (error == 0) {
Holger Hans Peter Freyther418f3942010-01-29 05:58:43 +0100440 LOGP(DNAT, LOGL_ERROR, "The connection to the BSC was lost. Cleaning it\n");
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100441 remove_bsc_connection((struct bsc_connection *) bfd->data);
Holger Hans Peter Freyther418f3942010-01-29 05:58:43 +0100442 } else {
443 LOGP(DNAT, LOGL_ERROR, "Failed to parse ip access message: %d\n", error);
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100444 }
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100445 return -1;
446 }
447
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100448
Holger Hans Peter Freyther418f3942010-01-29 05:58:43 +0100449 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 +0100450
451 /* Handle messages from the BSC */
452 /* FIXME: Currently no PONG is sent to the BSC */
453 /* FIXME: Currently no ID ACK is sent to the BSC */
Holger Hans Peter Freyther38a77d02010-01-30 12:45:10 +0100454 forward_sccp_to_msc(bfd, msg);
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100455
456 return 0;
457}
458
Holger Hans Peter Freyther49d80682010-01-12 21:34:54 +0100459static int ipaccess_listen_bsc_cb(struct bsc_fd *bfd, unsigned int what)
460{
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100461 struct bsc_connection *bsc;
Holger Hans Peter Freyther49d80682010-01-12 21:34:54 +0100462 int ret;
463 struct sockaddr_in sa;
464 socklen_t sa_len = sizeof(sa);
465
466 if (!(what & BSC_FD_READ))
467 return 0;
468
469 ret = accept(bfd->fd, (struct sockaddr *) &sa, &sa_len);
470 if (ret < 0) {
471 perror("accept");
472 return ret;
473 }
474
475 /* todo... do something with the connection */
Holger Hans Peter Freytherda86c0a2010-01-12 21:35:32 +0100476 /* todo... use GNUtls to see if we want to trust this as a BTS */
Holger Hans Peter Freyther49d80682010-01-12 21:34:54 +0100477
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100478 /*
479 *
480 */
481 bsc = talloc_zero(tall_bsc_ctx, struct bsc_connection);
482 if (!bsc) {
Holger Hans Peter Freyther418f3942010-01-29 05:58:43 +0100483 LOGP(DNAT, LOGL_ERROR, "Failed to allocate BSC struct.\n");
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100484 close(ret);
485 return -1;
486 }
487
488 bsc->bsc_fd.data = bsc;
489 bsc->bsc_fd.fd = ret;
490 bsc->bsc_fd.cb = ipaccess_bsc_cb;
Holger Hans Peter Freytherc7641c92010-01-13 09:52:29 +0100491 bsc->bsc_fd.when = BSC_FD_READ;
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100492 if (bsc_register_fd(&bsc->bsc_fd) < 0) {
Holger Hans Peter Freyther418f3942010-01-29 05:58:43 +0100493 LOGP(DNAT, LOGL_ERROR, "Failed to register BSC fd.\n");
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100494 close(ret);
495 talloc_free(bsc);
496 return -2;
497 }
498
Holger Hans Peter Freyther418f3942010-01-29 05:58:43 +0100499 LOGP(DNAT, LOGL_INFO, "Registered new BSC\n");
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100500 llist_add(&bsc->list_entry, &bsc_connections);
501 ipaccess_send_id_ack(ret);
Holger Hans Peter Freyther49d80682010-01-12 21:34:54 +0100502 return 0;
503}
504
505static int listen_for_bsc(struct bsc_fd *bfd, struct in_addr *in_addr, int port)
506{
507 struct sockaddr_in addr;
508 int ret, on = 1;
509
510 bfd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
511 bfd->cb = ipaccess_listen_bsc_cb;
512 bfd->when = BSC_FD_READ;
513
514 memset(&addr, 0, sizeof(addr));
515 addr.sin_family = AF_INET;
516 addr.sin_port = htons(port);
517 addr.sin_addr.s_addr = in_addr->s_addr;
518
519 setsockopt(bfd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
520
521 ret = bind(bfd->fd, (struct sockaddr *) &addr, sizeof(addr));
522 if (ret < 0) {
523 fprintf(stderr, "Could not bind the BSC socket %s\n",
524 strerror(errno));
525 return -EIO;
526 }
527
528 ret = listen(bfd->fd, 1);
529 if (ret < 0) {
530 perror("listen");
531 return ret;
532 }
533
534 ret = bsc_register_fd(bfd);
535 if (ret < 0) {
536 perror("register_listen_fd");
537 return ret;
538 }
539 return 0;
540}
541
Holger Hans Peter Freyther9e2c5f52010-06-15 18:44:42 +0800542static void print_usage()
543{
544 printf("Usage: bsc_nat\n");
545}
546
547static void print_help()
548{
549 printf(" Some useful help...\n");
550 printf(" -h --help this text\n");
551 printf(" -d option --debug=DRLL:DCC:DMM:DRR:DRSL:DNM enable debugging\n");
552 printf(" -s --disable-color\n");
553 printf(" -c --config-file filename The config file to use.\n");
554 printf(" -m --msc=IP. The address of the MSC.\n");
Holger Hans Peter Freyther49d80682010-01-12 21:34:54 +0100555 printf(" -l --local=IP. The local address of this BSC.\n");
Holger Hans Peter Freyther9e2c5f52010-06-15 18:44:42 +0800556}
557
558static void handle_options(int argc, char** argv)
559{
560 while (1) {
561 int option_index = 0, c;
562 static struct option long_options[] = {
563 {"help", 0, 0, 'h'},
564 {"debug", 1, 0, 'd'},
565 {"config-file", 1, 0, 'c'},
566 {"disable-color", 0, 0, 's'},
567 {"timestamp", 0, 0, 'T'},
568 {"msc", 1, 0, 'm'},
569 {"local", 1, 0, 'l'},
570 {0, 0, 0, 0}
571 };
572
573 c = getopt_long(argc, argv, "hd:sTPc:m:l:",
574 long_options, &option_index);
575 if (c == -1)
576 break;
577
578 switch (c) {
579 case 'h':
580 print_usage();
581 print_help();
582 exit(0);
583 case 's':
584 debug_use_color(0);
585 break;
586 case 'd':
587 debug_parse_category_mask(optarg);
588 break;
589 case 'c':
590 config_file = strdup(optarg);
591 break;
592 case 'T':
593 debug_timestamp(1);
594 break;
595 case 'm':
596 msc_address = strdup(optarg);
597 break;
598 case 'l':
599 inet_aton(optarg, &local_addr);
600 break;
601 default:
602 /* ignore */
603 break;
604 }
605 }
606}
607
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +0100608static void signal_handler(int signal)
609{
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +0100610 switch (signal) {
611 case SIGABRT:
612 /* in case of abort, we want to obtain a talloc report
613 * and then return to the caller, who will abort the process */
614 case SIGUSR1:
615 talloc_report_full(tall_bsc_ctx, stderr);
616 break;
617 default:
618 break;
619 }
620}
621
Holger Hans Peter Freyther9e2c5f52010-06-15 18:44:42 +0800622int main(int argc, char** argv)
623{
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +0100624 int rc;
625
Holger Hans Peter Freyther9e2c5f52010-06-15 18:44:42 +0800626 /* parse options */
Holger Hans Peter Freyther49d80682010-01-12 21:34:54 +0100627 local_addr.s_addr = INADDR_ANY;
Holger Hans Peter Freyther9e2c5f52010-06-15 18:44:42 +0800628 handle_options(argc, argv);
629
630 /* seed the PRNG */
631 srand(time(NULL));
632
Holger Hans Peter Freyther49d80682010-01-12 21:34:54 +0100633 /* connect to the MSC */
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +0100634 msc_connection.cb = ipaccess_msc_cb;
635 rc = connect_to_msc(&msc_connection, msc_address, 5000);
636 if (rc < 0) {
637 fprintf(stderr, "Opening the MSC connection failed.\n");
638 exit(1);
639 }
640
Holger Hans Peter Freyther49d80682010-01-12 21:34:54 +0100641 /* wait for the BSC */
642 if (listen_for_bsc(&bsc_connection, &local_addr, 5000) < 0) {
643 fprintf(stderr, "Failed to listen for BSC.\n");
644 exit(1);
645 }
646
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +0100647 signal(SIGINT, &signal_handler);
648 signal(SIGABRT, &signal_handler);
649 signal(SIGUSR1, &signal_handler);
650 signal(SIGPIPE, SIG_IGN);
651
652 while (1) {
653 bsc_select_main(0);
654 }
655
Holger Hans Peter Freyther9e2c5f52010-06-15 18:44:42 +0800656 return 0;
657}