blob: 6d45ac0f067b56199e5cdebd3a4b64d23b70206f [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>
Holger Hans Peter Freyther98e49d42010-06-15 18:46:56 +08005 * (C) 2010 by On-Waves
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/bsc_msc.h>
Holger Hans Peter Freyther57adba52010-06-15 18:45:26 +080040#include <openbsc/bsc_nat.h>
Holger Hans Peter Freyther722ead82010-01-30 12:45:10 +010041#include <openbsc/bssap.h>
Holger Hans Peter Freythere907cb22010-01-12 21:15:08 +010042#include <openbsc/ipaccess.h>
43#include <openbsc/abis_nm.h>
Holger Hans Peter Freyther5e547882010-06-15 18:46:11 +080044#include <openbsc/telnet_interface.h>
45
Holger Hans Peter Freyther3b960892010-06-15 19:06:18 +080046#include <osmocore/talloc.h>
47
Holger Hans Peter Freyther5e547882010-06-15 18:46:11 +080048#include <vty/vty.h>
Holger Hans Peter Freyther89d9fd92010-06-15 18:44:42 +080049
Holger Hans Peter Freyther57adba52010-06-15 18:45:26 +080050#include <sccp/sccp.h>
51
Holger Hans Peter Freyther3b960892010-06-15 19:06:18 +080052struct debug_target *stderr_target;
Holger Hans Peter Freyther5e547882010-06-15 18:46:11 +080053static const char *config_file = "bsc-nat.cfg";
Holger Hans Peter Freyther89d9fd92010-06-15 18:44:42 +080054static char *msc_address = "127.0.0.1";
55static struct in_addr local_addr;
Holger Hans Peter Freyther4a860a02010-06-15 18:47:29 +080056static struct bsc_msc_connection *msc_con;
Holger Hans Peter Freytherbea0ac62010-03-26 06:51:04 +010057static struct bsc_fd bsc_listen;
Holger Hans Peter Freythere907cb22010-01-12 21:15:08 +010058
Holger Hans Peter Freyther4a629602010-01-13 09:28:12 +010059
Holger Hans Peter Freyther5e547882010-06-15 18:46:11 +080060static struct bsc_nat *nat;
Holger Hans Peter Freyther2ec55172010-03-26 09:18:02 +010061static void bsc_write(struct bsc_connection *bsc, const u_int8_t *data, unsigned int length);
Holger Hans Peter Freyther3399df32010-03-29 08:04:09 +020062static void remove_bsc_connection(struct bsc_connection *connection);
Holger Hans Peter Freyther5e547882010-06-15 18:46:11 +080063
64static struct bsc_nat *bsc_nat_alloc(void)
65{
66 struct bsc_nat *nat = talloc_zero(tall_bsc_ctx, struct bsc_nat);
67 if (!nat)
68 return NULL;
69
70 INIT_LLIST_HEAD(&nat->sccp_connections);
71 INIT_LLIST_HEAD(&nat->bsc_connections);
72 INIT_LLIST_HEAD(&nat->bsc_configs);
73 return nat;
74}
75
76static struct bsc_connection *bsc_connection_alloc(void)
77{
78 struct bsc_connection *con = talloc_zero(nat, struct bsc_connection);
79 if (!con)
80 return NULL;
81
82 return con;
83}
84
85struct bsc_config *bsc_config_alloc(struct bsc_nat *nat, const char *token, unsigned int lac)
86{
87 struct bsc_config *conf = talloc_zero(nat, struct bsc_config);
88 if (!conf)
89 return NULL;
90
91 conf->token = talloc_strdup(conf, token);
92 conf->lac = lac;
93 conf->nr = nat->num_bsc;
94 conf->nat = nat;
95
96 llist_add(&conf->entry, &nat->bsc_configs);
97 ++nat->num_bsc;
98
99 return conf;
100}
101
102struct bsc_config *bsc_config_num(struct bsc_nat *nat, int num)
103{
104 struct bsc_config *conf;
105
106 llist_for_each_entry(conf, &nat->bsc_configs, entry)
107 if (conf->nr == num)
108 return conf;
109
110 return NULL;
111}
Holger Hans Peter Freyther4a629602010-01-13 09:28:12 +0100112
Holger Hans Peter Freythere907cb22010-01-12 21:15:08 +0100113/*
114 * below are stubs we need to link
115 */
116int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
117 struct gsm_nm_state *old_state, struct gsm_nm_state *new_state)
118{
119 return -1;
120}
121
122void input_event(int event, enum e1inp_sign_type type, struct gsm_bts_trx *trx)
123{}
124
125int gsm0408_rcvmsg(struct msgb *msg, u_int8_t link_id)
126{
127 return -1;
128}
129
Holger Hans Peter Freyther2ec55172010-03-26 09:18:02 +0100130static void send_reset_ack(struct bsc_connection *bsc)
Holger Hans Peter Freyther722ead82010-01-30 12:45:10 +0100131{
132 static const u_int8_t gsm_reset_ack[] = {
133 0x00, 0x13, 0xfd,
134 0x09, 0x00, 0x03, 0x07, 0x0b, 0x04, 0x43, 0x01,
135 0x00, 0xfe, 0x04, 0x43, 0x5c, 0x00, 0xfe, 0x03,
136 0x00, 0x01, 0x31,
137 };
138
Holger Hans Peter Freyther2ec55172010-03-26 09:18:02 +0100139 bsc_write(bsc, gsm_reset_ack, sizeof(gsm_reset_ack));
Holger Hans Peter Freyther722ead82010-01-30 12:45:10 +0100140}
141
Holger Hans Peter Freyther2ec55172010-03-26 09:18:02 +0100142static void send_id_ack(struct bsc_connection *bsc)
Holger Hans Peter Freyther809d6fa2010-03-26 07:41:54 +0100143{
144 static const u_int8_t id_ack[] = {
145 0, 1, IPAC_PROTO_IPACCESS, IPAC_MSGT_ID_ACK
146 };
147
Holger Hans Peter Freyther2ec55172010-03-26 09:18:02 +0100148 bsc_write(bsc, id_ack, sizeof(id_ack));
Holger Hans Peter Freyther809d6fa2010-03-26 07:41:54 +0100149}
150
Holger Hans Peter Freyther2ec55172010-03-26 09:18:02 +0100151static void send_id_req(struct bsc_connection *bsc)
Holger Hans Peter Freyther809d6fa2010-03-26 07:41:54 +0100152{
153 static const u_int8_t id_req[] = {
154 0, 17, IPAC_PROTO_IPACCESS, IPAC_MSGT_ID_GET,
155 0x01, IPAC_IDTAG_UNIT,
156 0x01, IPAC_IDTAG_MACADDR,
157 0x01, IPAC_IDTAG_LOCATION1,
158 0x01, IPAC_IDTAG_LOCATION2,
159 0x01, IPAC_IDTAG_EQUIPVERS,
160 0x01, IPAC_IDTAG_SWVERSION,
161 0x01, IPAC_IDTAG_UNITNAME,
162 0x01, IPAC_IDTAG_SERNR,
163 };
164
Holger Hans Peter Freyther2ec55172010-03-26 09:18:02 +0100165 bsc_write(bsc, id_req, sizeof(id_req));
Holger Hans Peter Freyther809d6fa2010-03-26 07:41:54 +0100166}
167
Holger Hans Peter Freythere907cb22010-01-12 21:15:08 +0100168/*
Holger Hans Peter Freythere83917d2010-01-31 09:46:21 +0100169 * SCCP patching below
170 */
171
172/* check if we are using this ref for patched already */
173static int sccp_ref_is_free(struct sccp_source_reference *ref)
174{
175 struct sccp_connections *conn;
176
Holger Hans Peter Freyther5e547882010-06-15 18:46:11 +0800177 llist_for_each_entry(conn, &nat->sccp_connections, list_entry) {
Holger Hans Peter Freythere83917d2010-01-31 09:46:21 +0100178 if (memcmp(ref, &conn->patched_ref, sizeof(*ref)) == 0)
179 return -1;
180 }
181
182 return 0;
183}
184
185/* copied from sccp.c */
186static int assign_src_local_reference(struct sccp_source_reference *ref)
187{
188 static u_int32_t last_ref = 0x50000;
189 int wrapped = 0;
190
191 do {
192 struct sccp_source_reference reference;
193 reference.octet1 = (last_ref >> 0) & 0xff;
194 reference.octet2 = (last_ref >> 8) & 0xff;
195 reference.octet3 = (last_ref >> 16) & 0xff;
196
197 ++last_ref;
198 /* do not use the reversed word and wrap around */
199 if ((last_ref & 0x00FFFFFF) == 0x00FFFFFF) {
200 LOGP(DNAT, LOGL_NOTICE, "Wrapped searching for a free code\n");
201 last_ref = 0;
202 ++wrapped;
203 }
204
205 if (sccp_ref_is_free(&reference) == 0) {
206 *ref = reference;
207 return 0;
208 }
209 } while (wrapped != 2);
210
211 LOGP(DNAT, LOGL_ERROR, "Finding a free reference failed\n");
212 return -1;
213}
Holger Hans Peter Freyther0792bb52010-01-31 13:52:32 +0100214
215static int create_sccp_src_ref(struct bsc_connection *bsc, struct msgb *msg, struct bsc_nat_parsed *parsed)
Holger Hans Peter Freythere83917d2010-01-31 09:46:21 +0100216{
217 struct sccp_connections *conn;
218
Holger Hans Peter Freyther5e547882010-06-15 18:46:11 +0800219 conn = talloc_zero(nat, struct sccp_connections);
Holger Hans Peter Freythere83917d2010-01-31 09:46:21 +0100220 if (!conn) {
221 LOGP(DNAT, LOGL_ERROR, "Memory allocation failure.\n");
222 return -1;
223 }
224
225 conn->real_ref = *parsed->src_local_ref;
226 if (assign_src_local_reference(&conn->patched_ref) != 0) {
227 LOGP(DNAT, LOGL_ERROR, "Failed to assign a ref.\n");
228 talloc_free(conn);
229 return -1;
230 }
231
232 return 0;
233}
234
Holger Hans Peter Freyther0792bb52010-01-31 13:52:32 +0100235static void remove_sccp_src_ref(struct bsc_connection *bsc, struct msgb *msg, struct bsc_nat_parsed *parsed)
Holger Hans Peter Freythere83917d2010-01-31 09:46:21 +0100236{
237 struct sccp_connections *conn;
238
Holger Hans Peter Freyther5e547882010-06-15 18:46:11 +0800239 llist_for_each_entry(conn, &nat->sccp_connections, list_entry) {
Holger Hans Peter Freythere83917d2010-01-31 09:46:21 +0100240 if (memcmp(parsed->src_local_ref,
241 &conn->real_ref, sizeof(conn->real_ref)) == 0) {
242 if (bsc != conn->bsc) {
243 LOGP(DNAT, LOGL_ERROR, "Someone else...\n");
244 continue;
245 }
246
247
248 llist_del(&conn->list_entry);
249 talloc_free(conn);
250 return;
251 }
252 }
253
254 LOGP(DNAT, LOGL_ERROR, "Unknown connection.\n");
255}
256
Holger Hans Peter Freyther0792bb52010-01-31 13:52:32 +0100257static struct bsc_connection *patch_sccp_src_ref_to_bsc(struct msgb *msg, struct bsc_nat_parsed *parsed)
Holger Hans Peter Freythere83917d2010-01-31 09:46:21 +0100258{
259 struct sccp_connections *conn;
Holger Hans Peter Freyther5e547882010-06-15 18:46:11 +0800260 llist_for_each_entry(conn, &nat->sccp_connections, list_entry) {
Holger Hans Peter Freythere83917d2010-01-31 09:46:21 +0100261 if (memcmp(parsed->dest_local_ref,
262 &conn->real_ref, sizeof(*parsed->dest_local_ref)) == 0) {
263 memcpy(parsed->dest_local_ref,
264 &conn->patched_ref, sizeof(*parsed->dest_local_ref));
265 return conn->bsc;
266 }
267 }
268
269 return NULL;
270}
271
Holger Hans Peter Freyther0792bb52010-01-31 13:52:32 +0100272static struct bsc_connection *patch_sccp_src_ref_to_msc(struct msgb *msg, struct bsc_nat_parsed *parsed)
Holger Hans Peter Freythere83917d2010-01-31 09:46:21 +0100273{
274 struct sccp_connections *conn;
Holger Hans Peter Freyther5e547882010-06-15 18:46:11 +0800275 llist_for_each_entry(conn, &nat->sccp_connections, list_entry) {
Holger Hans Peter Freythere83917d2010-01-31 09:46:21 +0100276 if (memcmp(parsed->src_local_ref,
277 &conn->real_ref, sizeof(*parsed->src_local_ref)) == 0) {
278 memcpy(parsed->src_local_ref,
279 &conn->patched_ref, sizeof(*parsed->src_local_ref));
280 return conn->bsc;
281 }
282 }
283
284 return NULL;
285}
286
287/*
Holger Hans Peter Freythere907cb22010-01-12 21:15:08 +0100288 * Below is the handling of messages coming
289 * from the MSC and need to be forwarded to
290 * a real BSC.
291 */
292static void initialize_msc_if_needed()
293{
294 static int init = 0;
295 init = 1;
296
297 /* do we need to send a GSM 08.08 message here? */
298}
299
Holger Hans Peter Freyther2ec55172010-03-26 09:18:02 +0100300/*
301 * Currently we are lacking refcounting so we need to copy each message.
302 */
303static void bsc_write(struct bsc_connection *bsc, const u_int8_t *data, unsigned int length)
Holger Hans Peter Freytherad2136b2010-03-26 07:20:59 +0100304{
Holger Hans Peter Freyther2ec55172010-03-26 09:18:02 +0100305 struct msgb *msg;
306
307 if (length > 4096) {
308 LOGP(DINP, LOGL_ERROR, "Can not send message of that size.\n");
309 return;
310 }
311
312 msg = msgb_alloc(4096, "to-bsc");
313 if (!msg) {
314 LOGP(DINP, LOGL_ERROR, "Failed to allocate memory for BSC msg.\n");
315 return;
316 }
317
318 msgb_put(msg, length);
319 memcpy(msg->data, data, length);
320 if (write_queue_enqueue(&bsc->write_queue, msg) != 0) {
321 LOGP(DINP, LOGL_ERROR, "Failed to enqueue the write.\n");
322 msgb_free(msg);
323 }
Holger Hans Peter Freytherad2136b2010-03-26 07:20:59 +0100324}
325
Holger Hans Peter Freythere83917d2010-01-31 09:46:21 +0100326static int forward_sccp_to_bts(struct msgb *msg)
Holger Hans Peter Freythere907cb22010-01-12 21:15:08 +0100327{
Holger Hans Peter Freytherfd2c7572010-06-15 18:46:36 +0800328 struct bsc_connection *bsc = NULL;
Holger Hans Peter Freytherf75a6802010-06-15 18:45:38 +0800329 struct bsc_nat_parsed *parsed;
Holger Hans Peter Freyther4a629602010-01-13 09:28:12 +0100330
Holger Hans Peter Freythere907cb22010-01-12 21:15:08 +0100331 /* filter, drop, patch the message? */
Holger Hans Peter Freytherf75a6802010-06-15 18:45:38 +0800332 parsed = bsc_nat_parse(msg);
333 if (!parsed) {
334 LOGP(DNAT, LOGL_ERROR, "Can not parse msg from BSC.\n");
Holger Hans Peter Freythere83917d2010-01-31 09:46:21 +0100335 return -1;
Holger Hans Peter Freytherf75a6802010-06-15 18:45:38 +0800336 }
337
Holger Hans Peter Freytherbbf6b652010-01-30 11:53:30 +0100338 if (bsc_nat_filter_ipa(DIR_BSC, msg, parsed))
Holger Hans Peter Freytherf75a6802010-06-15 18:45:38 +0800339 goto exit;
Holger Hans Peter Freyther57adba52010-06-15 18:45:26 +0800340
Holger Hans Peter Freythere83917d2010-01-31 09:46:21 +0100341 /* Route and modify the SCCP packet */
342 if (parsed->ipa_proto == IPAC_PROTO_SCCP) {
343 switch (parsed->sccp_type) {
344 case SCCP_MSG_TYPE_UDT:
345 /* forward UDT messages to every BSC */
346 goto send_to_all;
347 break;
348 case SCCP_MSG_TYPE_RLSD:
349 case SCCP_MSG_TYPE_CREF:
350 case SCCP_MSG_TYPE_DT1:
351 case SCCP_MSG_TYPE_CC:
352 bsc = patch_sccp_src_ref_to_bsc(msg, parsed);
353 break;
354 case SCCP_MSG_TYPE_CR:
355 case SCCP_MSG_TYPE_RLC:
356 /* MSC never opens a SCCP connection, fall through */
357 default:
358 goto exit;
359 }
360 }
361
362 talloc_free(parsed);
363 if (!bsc)
364 return -1;
Holger Hans Peter Freytherfb5a4872010-02-08 23:24:32 +0100365 if (!bsc->authenticated) {
Holger Hans Peter Freyther3b960892010-06-15 19:06:18 +0800366 LOGP(DNAT, LOGL_ERROR, "Selected BSC not authenticated.\n");
Holger Hans Peter Freytherfb5a4872010-02-08 23:24:32 +0100367 return -1;
368 }
369
Holger Hans Peter Freyther2ec55172010-03-26 09:18:02 +0100370 bsc_write(bsc, msg->data, msg->len);
371 return 0;
Holger Hans Peter Freythere83917d2010-01-31 09:46:21 +0100372
373send_to_all:
Holger Hans Peter Freytherfd2c7572010-06-15 18:46:36 +0800374 /*
375 * Filter Paging from the network. We do not want to send a PAGING
376 * Command to every BSC in our network. We will analys the PAGING
377 * message and then send it to the authenticated messages...
378 */
379 if (parsed->ipa_proto == IPAC_PROTO_SCCP && parsed->gsm_type == BSS_MAP_MSG_PAGING) {
380 int data_length;
381 const u_int8_t *data;
382 struct tlv_parsed tp;
383 int i = 0;
384
385 tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l3h + 3, msgb_l3len(msg) - 3, 0, 0);
386 if (!TLVP_PRESENT(&tp, GSM0808_IE_CELL_IDENTIFIER_LIST)) {
387 LOGP(DNAT, LOGL_ERROR, "No CellIdentifier List inside paging msg.\n");
388 goto exit;
389 }
390
391 data_length = TLVP_LEN(&tp, GSM0808_IE_CELL_IDENTIFIER_LIST);
392 data = TLVP_VAL(&tp, GSM0808_IE_CELL_IDENTIFIER_LIST);
393 if (data[0] != CELL_IDENT_LAC) {
394 LOGP(DNAT, LOGL_ERROR, "Unhandled cell ident discrminator: %c\n", data[0]);
395 goto exit;
396 }
397
398 /* go through each LAC and forward the message */
399 for (i = 1; i < data_length - 1; i += 2) {
400 unsigned int _lac = ntohs(*(unsigned int *) &data[i]);
401 llist_for_each_entry(bsc, &nat->bsc_connections, list_entry) {
402 if (!bsc->authenticated || _lac != bsc->lac)
403 continue;
404
Holger Hans Peter Freyther2ec55172010-03-26 09:18:02 +0100405 bsc_write(bsc, msg->data, msg->len);
Holger Hans Peter Freytherfd2c7572010-06-15 18:46:36 +0800406 }
407 }
408
409 goto exit;
410 }
Holger Hans Peter Freyther4a629602010-01-13 09:28:12 +0100411 /* currently send this to every BSC connected */
Holger Hans Peter Freyther5e547882010-06-15 18:46:11 +0800412 llist_for_each_entry(bsc, &nat->bsc_connections, list_entry) {
Holger Hans Peter Freytherfb5a4872010-02-08 23:24:32 +0100413 if (!bsc->authenticated)
414 continue;
415
Holger Hans Peter Freyther2ec55172010-03-26 09:18:02 +0100416 bsc_write(bsc, msg->data, msg->len);
Holger Hans Peter Freyther4a629602010-01-13 09:28:12 +0100417 }
Holger Hans Peter Freytherf75a6802010-06-15 18:45:38 +0800418
419exit:
420 talloc_free(parsed);
Holger Hans Peter Freythere83917d2010-01-31 09:46:21 +0100421 return 0;
Holger Hans Peter Freythere907cb22010-01-12 21:15:08 +0100422}
423
Holger Hans Peter Freyther4a860a02010-06-15 18:47:29 +0800424static void msc_connection_was_lost(struct bsc_msc_connection *con)
425{
Holger Hans Peter Freyther3399df32010-03-29 08:04:09 +0200426 struct bsc_connection *bsc, *tmp;
427
428 LOGP(DMSC, LOGL_ERROR, "Closing all connections downstream.\n");
429 llist_for_each_entry_safe(bsc, tmp, &nat->bsc_connections, list_entry)
430 remove_bsc_connection(bsc);
431
432 bsc_msc_schedule_connect(con);
Holger Hans Peter Freyther4a860a02010-06-15 18:47:29 +0800433}
434
Holger Hans Peter Freyther257a8cc2010-06-15 18:47:02 +0800435static int ipaccess_msc_read_cb(struct bsc_fd *bfd)
Holger Hans Peter Freythere907cb22010-01-12 21:15:08 +0100436{
437 int error;
438 struct msgb *msg = ipaccess_read_msg(bfd, &error);
439 struct ipaccess_head *hh;
440
441 if (!msg) {
442 if (error == 0) {
Holger Hans Peter Freyther8f99b822010-01-29 05:58:43 +0100443 LOGP(DNAT, LOGL_FATAL, "The connection the MSC was lost, exiting\n");
Holger Hans Peter Freyther4a860a02010-06-15 18:47:29 +0800444 bsc_msc_lost(msc_con);
445 return -1;
Holger Hans Peter Freythere907cb22010-01-12 21:15:08 +0100446 }
447
Holger Hans Peter Freyther8f99b822010-01-29 05:58:43 +0100448 LOGP(DNAT, LOGL_ERROR, "Failed to parse ip access message: %d\n", error);
Holger Hans Peter Freythere907cb22010-01-12 21:15:08 +0100449 return -1;
450 }
451
Holger Hans Peter Freyther8f99b822010-01-29 05:58:43 +0100452 LOGP(DNAT, LOGL_DEBUG, "MSG from MSC: %s proto: %d\n", hexdump(msg->data, msg->len), msg->l2h[0]);
Holger Hans Peter Freythere907cb22010-01-12 21:15:08 +0100453
454 /* handle base message handling */
455 hh = (struct ipaccess_head *) msg->data;
456 ipaccess_rcvmsg_base(msg, bfd);
457
458 /* initialize the networking. This includes sending a GSM08.08 message */
459 if (hh->proto == IPAC_PROTO_IPACCESS && msg->l2h[0] == IPAC_MSGT_ID_ACK)
460 initialize_msc_if_needed();
461 else if (hh->proto == IPAC_PROTO_SCCP)
462 forward_sccp_to_bts(msg);
463
Holger Hans Peter Freyther418fe112010-06-15 18:46:48 +0800464 msgb_free(msg);
Holger Hans Peter Freythere907cb22010-01-12 21:15:08 +0100465 return 0;
466}
Holger Hans Peter Freyther89d9fd92010-06-15 18:44:42 +0800467
Holger Hans Peter Freyther257a8cc2010-06-15 18:47:02 +0800468static int ipaccess_msc_write_cb(struct bsc_fd *bfd, struct msgb *msg)
469{
470 int rc;
471 rc = write(bfd->fd, msg->data, msg->len);
472
473 if (rc != msg->len) {
474 LOGP(DNAT, LOGL_ERROR, "Failed to write MSG to MSC.\n");
475 return -1;
476 }
477
478 return rc;
479}
480
Holger Hans Peter Freythere8fa0f12010-01-12 21:34:54 +0100481/*
482 * Below is the handling of messages coming
483 * from the BSC and need to be forwarded to
484 * a real BSC.
485 */
Holger Hans Peter Freyther4a629602010-01-13 09:28:12 +0100486
487/*
488 * Remove the connection from the connections list,
489 * remove it from the patching of SCCP header lists
490 * as well. Maybe in the future even close connection..
491 */
492static void remove_bsc_connection(struct bsc_connection *connection)
493{
Holger Hans Peter Freythere83917d2010-01-31 09:46:21 +0100494 struct sccp_connections *sccp_patch, *tmp;
Holger Hans Peter Freyther84010542010-06-15 18:47:10 +0800495 bsc_unregister_fd(&connection->write_queue.bfd);
496 close(connection->write_queue.bfd.fd);
Holger Hans Peter Freytherffcf79c2010-03-26 09:27:08 +0100497 write_queue_clear(&connection->write_queue);
Holger Hans Peter Freyther4a629602010-01-13 09:28:12 +0100498 llist_del(&connection->list_entry);
Holger Hans Peter Freythere83917d2010-01-31 09:46:21 +0100499
Holger Hans Peter Freytherde557662010-06-15 18:46:19 +0800500 /* stop the timeout timer */
501 bsc_del_timer(&connection->id_timeout);
502
Holger Hans Peter Freythere83917d2010-01-31 09:46:21 +0100503 /* remove all SCCP connections */
Holger Hans Peter Freyther5e547882010-06-15 18:46:11 +0800504 llist_for_each_entry_safe(sccp_patch, tmp, &nat->sccp_connections, list_entry) {
Holger Hans Peter Freythere83917d2010-01-31 09:46:21 +0100505 if (sccp_patch->bsc != connection)
506 continue;
507
Holger Hans Peter Freythera207db22010-03-26 09:28:40 +0100508#warning "TODO: Send a RLSD to the MSC. Or at least a clear command."
Holger Hans Peter Freythere83917d2010-01-31 09:46:21 +0100509 llist_del(&sccp_patch->list_entry);
510 talloc_free(sccp_patch);
511 }
512
Holger Hans Peter Freyther4a629602010-01-13 09:28:12 +0100513 talloc_free(connection);
514}
515
Holger Hans Peter Freytherde557662010-06-15 18:46:19 +0800516static void ipaccess_close_bsc(void *data)
517{
518 struct bsc_connection *conn = data;
519
520 LOGP(DNAT, LOGL_ERROR, "BSC didn't respond to identity request. Closing.\n");
521 remove_bsc_connection(conn);
522}
523
524static void ipaccess_auth_bsc(struct tlv_parsed *tvp, struct bsc_connection *bsc)
525{
526 struct bsc_config *conf;
527 const char* token = (const char *) TLVP_VAL(tvp, IPAC_IDTAG_UNITNAME);
528
529 llist_for_each_entry(conf, &bsc->nat->bsc_configs, entry) {
530 if (strcmp(conf->token, token) == 0) {
531 bsc->authenticated = 1;
532 bsc->lac = conf->lac;
533 bsc_del_timer(&bsc->id_timeout);
534 break;
535 }
536 }
537}
538
Holger Hans Peter Freyther4ce32702010-03-26 07:24:34 +0100539static int forward_sccp_to_msc(struct bsc_connection *bsc, struct msgb *msg)
Holger Hans Peter Freyther4a629602010-01-13 09:28:12 +0100540{
Holger Hans Peter Freyther87fcac22010-02-09 16:30:53 +0100541 struct bsc_connection *found_bsc = NULL;
Holger Hans Peter Freytherf75a6802010-06-15 18:45:38 +0800542 struct bsc_nat_parsed *parsed;
Holger Hans Peter Freyther4a629602010-01-13 09:28:12 +0100543
Holger Hans Peter Freytherf75a6802010-06-15 18:45:38 +0800544 /* Parse and filter messages */
545 parsed = bsc_nat_parse(msg);
546 if (!parsed) {
547 LOGP(DNAT, LOGL_ERROR, "Can not parse msg from BSC.\n");
548 return -1;
549 }
550
Holger Hans Peter Freytherbbf6b652010-01-30 11:53:30 +0100551 if (bsc_nat_filter_ipa(DIR_MSC, msg, parsed))
Holger Hans Peter Freytherf75a6802010-06-15 18:45:38 +0800552 goto exit;
Holger Hans Peter Freyther57adba52010-06-15 18:45:26 +0800553
Holger Hans Peter Freythere83917d2010-01-31 09:46:21 +0100554 /* modify the SCCP entries */
555 if (parsed->ipa_proto == IPAC_PROTO_SCCP) {
556 switch (parsed->sccp_type) {
557 case SCCP_MSG_TYPE_CR:
558 if (create_sccp_src_ref(bsc, msg, parsed) != 0)
559 goto exit2;
560 found_bsc = patch_sccp_src_ref_to_msc(msg, parsed);
561 break;
562 case SCCP_MSG_TYPE_RLSD:
563 case SCCP_MSG_TYPE_CREF:
564 case SCCP_MSG_TYPE_DT1:
565 case SCCP_MSG_TYPE_CC:
566 found_bsc = patch_sccp_src_ref_to_msc(msg, parsed);
567 break;
568 case SCCP_MSG_TYPE_RLC:
569 found_bsc = patch_sccp_src_ref_to_msc(msg, parsed);
570 remove_sccp_src_ref(bsc, msg, parsed);
571 break;
572 case SCCP_MSG_TYPE_UDT:
573 /* simply forward everything */
574 break;
575 default:
576 goto exit2;
577 break;
578 }
579 }
580
581 if (found_bsc != bsc) {
582 LOGP(DNAT, LOGL_ERROR, "Found the wrong entry.\n");
583 goto exit2;
584 }
585
Holger Hans Peter Freytherfb5a4872010-02-08 23:24:32 +0100586 if (!bsc->authenticated) {
587 LOGP(DNAT, LOGL_ERROR, "BSC is not authenticated.\n");
588 goto exit2;
589 }
590
Holger Hans Peter Freyther4a629602010-01-13 09:28:12 +0100591 /* send the non-filtered but maybe modified msg */
Holger Hans Peter Freyther4a860a02010-06-15 18:47:29 +0800592 if (write_queue_enqueue(&msc_con->write_queue, msg) != 0) {
Holger Hans Peter Freyther257a8cc2010-06-15 18:47:02 +0800593 LOGP(DNAT, LOGL_ERROR, "Can not queue message for the MSC.\n");
594 msgb_free(msg);
595 }
Holger Hans Peter Freyther722ead82010-01-30 12:45:10 +0100596 talloc_free(parsed);
Holger Hans Peter Freyther257a8cc2010-06-15 18:47:02 +0800597 return 0;
Holger Hans Peter Freytherf75a6802010-06-15 18:45:38 +0800598
599exit:
Holger Hans Peter Freyther722ead82010-01-30 12:45:10 +0100600 /* if we filter out the reset send an ack to the BSC */
601 if (parsed->bssap == 0 && parsed->gsm_type == BSS_MAP_MSG_RESET) {
Holger Hans Peter Freyther4ce32702010-03-26 07:24:34 +0100602 send_reset_ack(bsc);
603 send_reset_ack(bsc);
Holger Hans Peter Freytherde557662010-06-15 18:46:19 +0800604 } else if (parsed->ipa_proto == IPAC_PROTO_IPACCESS) {
605 /* do we know who is handling this? */
606 if (msg->l2h[0] == IPAC_MSGT_ID_RESP) {
607 struct tlv_parsed tvp;
608 ipaccess_idtag_parse(&tvp,
609 (unsigned char *) msg->l2h + 2,
610 msgb_l2len(msg) - 2);
611 if (TLVP_PRESENT(&tvp, IPAC_IDTAG_UNITNAME))
612 ipaccess_auth_bsc(&tvp, bsc);
613 }
614
615 goto exit2;
Holger Hans Peter Freyther722ead82010-01-30 12:45:10 +0100616 }
617
Holger Hans Peter Freythere83917d2010-01-31 09:46:21 +0100618exit2:
Holger Hans Peter Freytherf75a6802010-06-15 18:45:38 +0800619 talloc_free(parsed);
Holger Hans Peter Freyther257a8cc2010-06-15 18:47:02 +0800620 msgb_free(msg);
621 return -1;
Holger Hans Peter Freyther4a629602010-01-13 09:28:12 +0100622}
623
Holger Hans Peter Freyther84010542010-06-15 18:47:10 +0800624static int ipaccess_bsc_read_cb(struct bsc_fd *bfd)
Holger Hans Peter Freyther4a629602010-01-13 09:28:12 +0100625{
626 int error;
Holger Hans Peter Freyther4ce32702010-03-26 07:24:34 +0100627 struct bsc_connection *bsc = bfd->data;
Holger Hans Peter Freyther4a629602010-01-13 09:28:12 +0100628 struct msgb *msg = ipaccess_read_msg(bfd, &error);
Holger Hans Peter Freyther4a629602010-01-13 09:28:12 +0100629
630 if (!msg) {
631 if (error == 0) {
Holger Hans Peter Freyther8f99b822010-01-29 05:58:43 +0100632 LOGP(DNAT, LOGL_ERROR, "The connection to the BSC was lost. Cleaning it\n");
Holger Hans Peter Freyther4ce32702010-03-26 07:24:34 +0100633 remove_bsc_connection(bsc);
Holger Hans Peter Freyther8f99b822010-01-29 05:58:43 +0100634 } else {
635 LOGP(DNAT, LOGL_ERROR, "Failed to parse ip access message: %d\n", error);
Holger Hans Peter Freyther4a629602010-01-13 09:28:12 +0100636 }
Holger Hans Peter Freyther4a629602010-01-13 09:28:12 +0100637 return -1;
638 }
639
Holger Hans Peter Freyther4a629602010-01-13 09:28:12 +0100640
Holger Hans Peter Freyther8f99b822010-01-29 05:58:43 +0100641 LOGP(DNAT, LOGL_DEBUG, "MSG from BSC: %s proto: %d\n", hexdump(msg->data, msg->len), msg->l2h[0]);
Holger Hans Peter Freyther4a629602010-01-13 09:28:12 +0100642
643 /* Handle messages from the BSC */
644 /* FIXME: Currently no PONG is sent to the BSC */
645 /* FIXME: Currently no ID ACK is sent to the BSC */
Holger Hans Peter Freyther4ce32702010-03-26 07:24:34 +0100646 forward_sccp_to_msc(bsc, msg);
Holger Hans Peter Freyther4a629602010-01-13 09:28:12 +0100647
648 return 0;
649}
650
Holger Hans Peter Freyther2ec55172010-03-26 09:18:02 +0100651static int ipaccess_bsc_write_cb(struct bsc_fd *bfd, struct msgb *msg)
652{
653 int rc;
654
655 rc = write(bfd->fd, msg->data, msg->len);
656 if (rc != msg->len)
657 LOGP(DNAT, LOGL_ERROR, "Failed to write message to the BSC.\n");
658
659 return rc;
660}
661
Holger Hans Peter Freythere8fa0f12010-01-12 21:34:54 +0100662static int ipaccess_listen_bsc_cb(struct bsc_fd *bfd, unsigned int what)
663{
Holger Hans Peter Freyther4a629602010-01-13 09:28:12 +0100664 struct bsc_connection *bsc;
Holger Hans Peter Freythere8fa0f12010-01-12 21:34:54 +0100665 int ret;
666 struct sockaddr_in sa;
667 socklen_t sa_len = sizeof(sa);
668
669 if (!(what & BSC_FD_READ))
670 return 0;
671
672 ret = accept(bfd->fd, (struct sockaddr *) &sa, &sa_len);
673 if (ret < 0) {
674 perror("accept");
675 return ret;
676 }
677
Holger Hans Peter Freyther3399df32010-03-29 08:04:09 +0200678 /*
679 * if we are not connected to a msc... just close the socket
680 */
681 if (!msc_con->is_connected) {
682 LOGP(DNAT, LOGL_NOTICE, "Disconnecting BSC due lack of MSC connection.\n");
683 return 0;
684 }
685
Holger Hans Peter Freythere8fa0f12010-01-12 21:34:54 +0100686 /* todo... do something with the connection */
Holger Hans Peter Freyther738dbdf2010-01-12 21:35:32 +0100687 /* todo... use GNUtls to see if we want to trust this as a BTS */
Holger Hans Peter Freythere8fa0f12010-01-12 21:34:54 +0100688
Holger Hans Peter Freyther4a629602010-01-13 09:28:12 +0100689 /*
690 *
691 */
Holger Hans Peter Freyther5e547882010-06-15 18:46:11 +0800692 bsc = bsc_connection_alloc();
Holger Hans Peter Freyther4a629602010-01-13 09:28:12 +0100693 if (!bsc) {
Holger Hans Peter Freyther8f99b822010-01-29 05:58:43 +0100694 LOGP(DNAT, LOGL_ERROR, "Failed to allocate BSC struct.\n");
Holger Hans Peter Freyther4a629602010-01-13 09:28:12 +0100695 close(ret);
696 return -1;
697 }
698
Holger Hans Peter Freytherde557662010-06-15 18:46:19 +0800699 bsc->nat = nat;
Holger Hans Peter Freyther84010542010-06-15 18:47:10 +0800700 write_queue_init(&bsc->write_queue, 100);
701 bsc->write_queue.bfd.data = bsc;
702 bsc->write_queue.bfd.fd = ret;
703 bsc->write_queue.read_cb = ipaccess_bsc_read_cb;
Holger Hans Peter Freyther2ec55172010-03-26 09:18:02 +0100704 bsc->write_queue.write_cb = ipaccess_bsc_write_cb;
Holger Hans Peter Freyther84010542010-06-15 18:47:10 +0800705 bsc->write_queue.bfd.when = BSC_FD_READ;
706 if (bsc_register_fd(&bsc->write_queue.bfd) < 0) {
Holger Hans Peter Freyther8f99b822010-01-29 05:58:43 +0100707 LOGP(DNAT, LOGL_ERROR, "Failed to register BSC fd.\n");
Holger Hans Peter Freyther4a629602010-01-13 09:28:12 +0100708 close(ret);
709 talloc_free(bsc);
710 return -2;
711 }
712
Holger Hans Peter Freyther8f99b822010-01-29 05:58:43 +0100713 LOGP(DNAT, LOGL_INFO, "Registered new BSC\n");
Holger Hans Peter Freyther5e547882010-06-15 18:46:11 +0800714 llist_add(&bsc->list_entry, &nat->bsc_connections);
Holger Hans Peter Freyther809d6fa2010-03-26 07:41:54 +0100715 send_id_ack(bsc);
716 send_id_req(bsc);
Holger Hans Peter Freytherde557662010-06-15 18:46:19 +0800717
718 /*
719 * start the hangup timer
720 */
721 bsc->id_timeout.data = bsc;
722 bsc->id_timeout.cb = ipaccess_close_bsc;
723 bsc_schedule_timer(&bsc->id_timeout, 2, 0);
Holger Hans Peter Freythere8fa0f12010-01-12 21:34:54 +0100724 return 0;
725}
726
727static int listen_for_bsc(struct bsc_fd *bfd, struct in_addr *in_addr, int port)
728{
729 struct sockaddr_in addr;
730 int ret, on = 1;
731
732 bfd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
733 bfd->cb = ipaccess_listen_bsc_cb;
734 bfd->when = BSC_FD_READ;
735
736 memset(&addr, 0, sizeof(addr));
737 addr.sin_family = AF_INET;
738 addr.sin_port = htons(port);
739 addr.sin_addr.s_addr = in_addr->s_addr;
740
741 setsockopt(bfd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
742
743 ret = bind(bfd->fd, (struct sockaddr *) &addr, sizeof(addr));
744 if (ret < 0) {
745 fprintf(stderr, "Could not bind the BSC socket %s\n",
746 strerror(errno));
747 return -EIO;
748 }
749
750 ret = listen(bfd->fd, 1);
751 if (ret < 0) {
752 perror("listen");
753 return ret;
754 }
755
756 ret = bsc_register_fd(bfd);
757 if (ret < 0) {
758 perror("register_listen_fd");
759 return ret;
760 }
761 return 0;
762}
763
Holger Hans Peter Freyther89d9fd92010-06-15 18:44:42 +0800764static void print_usage()
765{
766 printf("Usage: bsc_nat\n");
767}
768
769static void print_help()
770{
771 printf(" Some useful help...\n");
772 printf(" -h --help this text\n");
773 printf(" -d option --debug=DRLL:DCC:DMM:DRR:DRSL:DNM enable debugging\n");
774 printf(" -s --disable-color\n");
775 printf(" -c --config-file filename The config file to use.\n");
776 printf(" -m --msc=IP. The address of the MSC.\n");
Holger Hans Peter Freythere8fa0f12010-01-12 21:34:54 +0100777 printf(" -l --local=IP. The local address of this BSC.\n");
Holger Hans Peter Freyther89d9fd92010-06-15 18:44:42 +0800778}
779
780static void handle_options(int argc, char** argv)
781{
782 while (1) {
783 int option_index = 0, c;
784 static struct option long_options[] = {
785 {"help", 0, 0, 'h'},
786 {"debug", 1, 0, 'd'},
787 {"config-file", 1, 0, 'c'},
788 {"disable-color", 0, 0, 's'},
789 {"timestamp", 0, 0, 'T'},
790 {"msc", 1, 0, 'm'},
791 {"local", 1, 0, 'l'},
792 {0, 0, 0, 0}
793 };
794
795 c = getopt_long(argc, argv, "hd:sTPc:m:l:",
796 long_options, &option_index);
797 if (c == -1)
798 break;
799
800 switch (c) {
801 case 'h':
802 print_usage();
803 print_help();
804 exit(0);
805 case 's':
Holger Hans Peter Freyther3b960892010-06-15 19:06:18 +0800806 debug_set_use_color(stderr_target, 0);
Holger Hans Peter Freyther89d9fd92010-06-15 18:44:42 +0800807 break;
808 case 'd':
Holger Hans Peter Freyther3b960892010-06-15 19:06:18 +0800809 debug_parse_category_mask(stderr_target, optarg);
Holger Hans Peter Freyther89d9fd92010-06-15 18:44:42 +0800810 break;
811 case 'c':
812 config_file = strdup(optarg);
813 break;
814 case 'T':
Holger Hans Peter Freyther3b960892010-06-15 19:06:18 +0800815 debug_set_print_timestamp(stderr_target, 1);
Holger Hans Peter Freyther89d9fd92010-06-15 18:44:42 +0800816 break;
817 case 'm':
818 msc_address = strdup(optarg);
819 break;
820 case 'l':
821 inet_aton(optarg, &local_addr);
822 break;
823 default:
824 /* ignore */
825 break;
826 }
827 }
828}
829
Holger Hans Peter Freythere907cb22010-01-12 21:15:08 +0100830static void signal_handler(int signal)
831{
Holger Hans Peter Freythere907cb22010-01-12 21:15:08 +0100832 switch (signal) {
833 case SIGABRT:
834 /* in case of abort, we want to obtain a talloc report
835 * and then return to the caller, who will abort the process */
836 case SIGUSR1:
837 talloc_report_full(tall_bsc_ctx, stderr);
838 break;
839 default:
840 break;
841 }
842}
843
Holger Hans Peter Freyther89d9fd92010-06-15 18:44:42 +0800844int main(int argc, char** argv)
845{
Holger Hans Peter Freythere907cb22010-01-12 21:15:08 +0100846
Holger Hans Peter Freyther3b960892010-06-15 19:06:18 +0800847 debug_init();
848 stderr_target = debug_target_create_stderr();
849 debug_add_target(stderr_target);
850 debug_set_all_filter(stderr_target, 1);
851
Holger Hans Peter Freyther89d9fd92010-06-15 18:44:42 +0800852 /* parse options */
Holger Hans Peter Freythere8fa0f12010-01-12 21:34:54 +0100853 local_addr.s_addr = INADDR_ANY;
Holger Hans Peter Freyther89d9fd92010-06-15 18:44:42 +0800854 handle_options(argc, argv);
855
Holger Hans Peter Freyther5e547882010-06-15 18:46:11 +0800856 nat = bsc_nat_alloc();
857 if (!nat) {
858 fprintf(stderr, "Failed to allocate the BSC nat.\n");
859 return -4;
860 }
861
862 /* init vty and parse */
863 bsc_nat_vty_init(nat);
864 telnet_init(NULL, 4244);
865 if (vty_read_config_file(config_file) < 0) {
866 fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
867 return -3;
868 }
869
Holger Hans Peter Freyther89d9fd92010-06-15 18:44:42 +0800870 /* seed the PRNG */
871 srand(time(NULL));
872
Holger Hans Peter Freythere8fa0f12010-01-12 21:34:54 +0100873 /* connect to the MSC */
Holger Hans Peter Freyther4a860a02010-06-15 18:47:29 +0800874 msc_con = bsc_msc_create(msc_address, 5000);
875 if (!msc_con) {
876 fprintf(stderr, "Creating a bsc_msc_connection failed.\n");
Holger Hans Peter Freythere907cb22010-01-12 21:15:08 +0100877 exit(1);
878 }
879
Holger Hans Peter Freyther4a860a02010-06-15 18:47:29 +0800880 msc_con->connection_loss = msc_connection_was_lost;
881 msc_con->write_queue.read_cb = ipaccess_msc_read_cb;
882 msc_con->write_queue.write_cb = ipaccess_msc_write_cb;;
883 bsc_msc_connect(msc_con);
884
Holger Hans Peter Freythere8fa0f12010-01-12 21:34:54 +0100885 /* wait for the BSC */
Holger Hans Peter Freytherbea0ac62010-03-26 06:51:04 +0100886 if (listen_for_bsc(&bsc_listen, &local_addr, 5000) < 0) {
Holger Hans Peter Freythere8fa0f12010-01-12 21:34:54 +0100887 fprintf(stderr, "Failed to listen for BSC.\n");
888 exit(1);
889 }
890
Holger Hans Peter Freythere907cb22010-01-12 21:15:08 +0100891 signal(SIGABRT, &signal_handler);
892 signal(SIGUSR1, &signal_handler);
893 signal(SIGPIPE, SIG_IGN);
894
895 while (1) {
896 bsc_select_main(0);
897 }
898
Holger Hans Peter Freyther89d9fd92010-06-15 18:44:42 +0800899 return 0;
900}