blob: 734606b76d9c41311a6c7f999183e8a2d79337c6 [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>
Holger Hans Peter Freytherdf6143a2010-06-15 18:46:56 +08005 * (C) 2010 by On-Waves
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/bsc_msc.h>
Holger Hans Peter Freyther6a97b8d2010-06-15 18:45:26 +080040#include <openbsc/bsc_nat.h>
Holger Hans Peter Freyther38a77d02010-01-30 12:45:10 +010041#include <openbsc/bssap.h>
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +010042#include <openbsc/ipaccess.h>
43#include <openbsc/abis_nm.h>
Holger Hans Peter Freyther9a85ef32010-06-15 18:46:11 +080044#include <openbsc/telnet_interface.h>
45
Holger Hans Peter Freyther6c45f2e2010-06-15 19:06:18 +080046#include <osmocore/talloc.h>
47
Holger Hans Peter Freyther9a85ef32010-06-15 18:46:11 +080048#include <vty/vty.h>
Holger Hans Peter Freyther9e2c5f52010-06-15 18:44:42 +080049
Holger Hans Peter Freyther6a97b8d2010-06-15 18:45:26 +080050#include <sccp/sccp.h>
51
Holger Hans Peter Freyther6c45f2e2010-06-15 19:06:18 +080052struct debug_target *stderr_target;
Holger Hans Peter Freyther9a85ef32010-06-15 18:46:11 +080053static const char *config_file = "bsc-nat.cfg";
Holger Hans Peter Freyther9e2c5f52010-06-15 18:44:42 +080054static char *msc_address = "127.0.0.1";
55static struct in_addr local_addr;
Holger Hans Peter Freytherbaf2abe2010-06-15 18:47:29 +080056static struct bsc_msc_connection *msc_con;
Holger Hans Peter Freyther2d677c62010-03-26 06:51:04 +010057static struct bsc_fd bsc_listen;
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +010058
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +010059
Holger Hans Peter Freyther9a85ef32010-06-15 18:46:11 +080060static struct bsc_nat *nat;
Holger Hans Peter Freyther3025e192010-03-26 09:18:02 +010061static void bsc_write(struct bsc_connection *bsc, const u_int8_t *data, unsigned int length);
Holger Hans Peter Freythercd895372010-03-29 08:04:09 +020062static void remove_bsc_connection(struct bsc_connection *connection);
Holger Hans Peter Freyther9a85ef32010-06-15 18:46:11 +080063
Holger Hans Peter Freyther9a85ef32010-06-15 18:46:11 +080064struct bsc_config *bsc_config_num(struct bsc_nat *nat, int num)
65{
66 struct bsc_config *conf;
67
68 llist_for_each_entry(conf, &nat->bsc_configs, entry)
69 if (conf->nr == num)
70 return conf;
71
72 return NULL;
73}
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +010074
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +010075/*
76 * below are stubs we need to link
77 */
78int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
79 struct gsm_nm_state *old_state, struct gsm_nm_state *new_state)
80{
81 return -1;
82}
83
84void input_event(int event, enum e1inp_sign_type type, struct gsm_bts_trx *trx)
85{}
86
87int gsm0408_rcvmsg(struct msgb *msg, u_int8_t link_id)
88{
89 return -1;
90}
91
Holger Hans Peter Freyther3025e192010-03-26 09:18:02 +010092static void send_reset_ack(struct bsc_connection *bsc)
Holger Hans Peter Freyther38a77d02010-01-30 12:45:10 +010093{
94 static const u_int8_t gsm_reset_ack[] = {
95 0x00, 0x13, 0xfd,
96 0x09, 0x00, 0x03, 0x07, 0x0b, 0x04, 0x43, 0x01,
97 0x00, 0xfe, 0x04, 0x43, 0x5c, 0x00, 0xfe, 0x03,
98 0x00, 0x01, 0x31,
99 };
100
Holger Hans Peter Freyther3025e192010-03-26 09:18:02 +0100101 bsc_write(bsc, gsm_reset_ack, sizeof(gsm_reset_ack));
Holger Hans Peter Freyther38a77d02010-01-30 12:45:10 +0100102}
103
Holger Hans Peter Freyther3025e192010-03-26 09:18:02 +0100104static void send_id_ack(struct bsc_connection *bsc)
Holger Hans Peter Freytherdb7ba7d2010-03-26 07:41:54 +0100105{
106 static const u_int8_t id_ack[] = {
107 0, 1, IPAC_PROTO_IPACCESS, IPAC_MSGT_ID_ACK
108 };
109
Holger Hans Peter Freyther3025e192010-03-26 09:18:02 +0100110 bsc_write(bsc, id_ack, sizeof(id_ack));
Holger Hans Peter Freytherdb7ba7d2010-03-26 07:41:54 +0100111}
112
Holger Hans Peter Freyther3025e192010-03-26 09:18:02 +0100113static void send_id_req(struct bsc_connection *bsc)
Holger Hans Peter Freytherdb7ba7d2010-03-26 07:41:54 +0100114{
115 static const u_int8_t id_req[] = {
116 0, 17, IPAC_PROTO_IPACCESS, IPAC_MSGT_ID_GET,
117 0x01, IPAC_IDTAG_UNIT,
118 0x01, IPAC_IDTAG_MACADDR,
119 0x01, IPAC_IDTAG_LOCATION1,
120 0x01, IPAC_IDTAG_LOCATION2,
121 0x01, IPAC_IDTAG_EQUIPVERS,
122 0x01, IPAC_IDTAG_SWVERSION,
123 0x01, IPAC_IDTAG_UNITNAME,
124 0x01, IPAC_IDTAG_SERNR,
125 };
126
Holger Hans Peter Freyther3025e192010-03-26 09:18:02 +0100127 bsc_write(bsc, id_req, sizeof(id_req));
Holger Hans Peter Freytherdb7ba7d2010-03-26 07:41:54 +0100128}
129
Holger Hans Peter Freytherd131b792010-03-31 07:30:58 +0200130static void send_mgcp_reset(struct bsc_connection *bsc)
131{
132 static const u_int8_t mgcp_reset[] = {
133 "RSIP 1 13@mgw MGCP 1.0\r\n"
134 };
135
136 bsc_write_mgcp(bsc, mgcp_reset, sizeof mgcp_reset - 1);
137}
138
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +0100139/*
140 * Below is the handling of messages coming
141 * from the MSC and need to be forwarded to
142 * a real BSC.
143 */
144static void initialize_msc_if_needed()
145{
146 static int init = 0;
147 init = 1;
148
149 /* do we need to send a GSM 08.08 message here? */
150}
151
Holger Hans Peter Freyther3025e192010-03-26 09:18:02 +0100152/*
153 * Currently we are lacking refcounting so we need to copy each message.
154 */
155static void bsc_write(struct bsc_connection *bsc, const u_int8_t *data, unsigned int length)
Holger Hans Peter Freytherf7cb33c2010-03-26 07:20:59 +0100156{
Holger Hans Peter Freyther3025e192010-03-26 09:18:02 +0100157 struct msgb *msg;
158
159 if (length > 4096) {
160 LOGP(DINP, LOGL_ERROR, "Can not send message of that size.\n");
161 return;
162 }
163
164 msg = msgb_alloc(4096, "to-bsc");
165 if (!msg) {
166 LOGP(DINP, LOGL_ERROR, "Failed to allocate memory for BSC msg.\n");
167 return;
168 }
169
170 msgb_put(msg, length);
171 memcpy(msg->data, data, length);
172 if (write_queue_enqueue(&bsc->write_queue, msg) != 0) {
173 LOGP(DINP, LOGL_ERROR, "Failed to enqueue the write.\n");
174 msgb_free(msg);
175 }
Holger Hans Peter Freytherf7cb33c2010-03-26 07:20:59 +0100176}
177
Holger Hans Peter Freyther058eeb72010-01-31 09:46:21 +0100178static int forward_sccp_to_bts(struct msgb *msg)
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +0100179{
Holger Hans Peter Freyther49c7fb52010-06-15 18:48:55 +0800180 struct sccp_connections *con;
181 struct bsc_connection *bsc;
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +0800182 struct bsc_nat_parsed *parsed;
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100183
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +0100184 /* filter, drop, patch the message? */
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +0800185 parsed = bsc_nat_parse(msg);
186 if (!parsed) {
187 LOGP(DNAT, LOGL_ERROR, "Can not parse msg from BSC.\n");
Holger Hans Peter Freyther058eeb72010-01-31 09:46:21 +0100188 return -1;
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +0800189 }
190
Holger Hans Peter Freyther1d6fb182010-01-30 11:53:30 +0100191 if (bsc_nat_filter_ipa(DIR_BSC, msg, parsed))
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +0800192 goto exit;
Holger Hans Peter Freyther6a97b8d2010-06-15 18:45:26 +0800193
Holger Hans Peter Freyther058eeb72010-01-31 09:46:21 +0100194 /* Route and modify the SCCP packet */
195 if (parsed->ipa_proto == IPAC_PROTO_SCCP) {
196 switch (parsed->sccp_type) {
197 case SCCP_MSG_TYPE_UDT:
198 /* forward UDT messages to every BSC */
199 goto send_to_all;
200 break;
201 case SCCP_MSG_TYPE_RLSD:
202 case SCCP_MSG_TYPE_CREF:
203 case SCCP_MSG_TYPE_DT1:
Holger Hans Peter Freytherf46ce532010-04-06 10:22:34 +0200204 case SCCP_MSG_TYPE_IT:
Holger Hans Peter Freyther49c7fb52010-06-15 18:48:55 +0800205 con = patch_sccp_src_ref_to_bsc(msg, parsed, nat);
Holger Hans Peter Freyther465313e2010-06-15 18:49:53 +0800206 if (parsed->gsm_type == BSS_MAP_MSG_ASSIGMENT_RQST) {
207 if (con) {
208 if (bsc_mgcp_assign(con, msg) != 0)
209 LOGP(DNAT, LOGL_ERROR, "Failed to assign...\n");
210 } else
211 LOGP(DNAT, LOGL_ERROR, "Assignment command but no BSC.\n");
212 }
Holger Hans Peter Freyther16a6f702010-03-29 17:18:42 +0200213 break;
Holger Hans Peter Freyther058eeb72010-01-31 09:46:21 +0100214 case SCCP_MSG_TYPE_CC:
Holger Hans Peter Freyther49c7fb52010-06-15 18:48:55 +0800215 con = patch_sccp_src_ref_to_bsc(msg, parsed, nat);
216 if (!con || update_sccp_src_ref(con, parsed) != 0)
Holger Hans Peter Freyther16a6f702010-03-29 17:18:42 +0200217 goto exit;
Holger Hans Peter Freyther0ab6bab2010-06-15 18:47:49 +0800218 break;
219 case SCCP_MSG_TYPE_RLC:
220 LOGP(DNAT, LOGL_ERROR, "Unexpected release complete from MSC.\n");
221 goto exit;
Holger Hans Peter Freyther058eeb72010-01-31 09:46:21 +0100222 break;
223 case SCCP_MSG_TYPE_CR:
Holger Hans Peter Freyther058eeb72010-01-31 09:46:21 +0100224 /* MSC never opens a SCCP connection, fall through */
225 default:
226 goto exit;
227 }
Holger Hans Peter Freytherf464ea52010-04-06 16:07:44 +0200228
229 if (!con)
230 LOGP(DNAT, LOGL_ERROR, "Unknown connection for msg type: 0x%x.\n", parsed->sccp_type);
Holger Hans Peter Freyther058eeb72010-01-31 09:46:21 +0100231 }
232
233 talloc_free(parsed);
Holger Hans Peter Freyther49c7fb52010-06-15 18:48:55 +0800234 if (!con)
Holger Hans Peter Freyther058eeb72010-01-31 09:46:21 +0100235 return -1;
Holger Hans Peter Freyther49c7fb52010-06-15 18:48:55 +0800236 if (!con->bsc->authenticated) {
Holger Hans Peter Freyther6c45f2e2010-06-15 19:06:18 +0800237 LOGP(DNAT, LOGL_ERROR, "Selected BSC not authenticated.\n");
Holger Hans Peter Freyther3f37b8f2010-02-08 23:24:32 +0100238 return -1;
239 }
240
Holger Hans Peter Freyther49c7fb52010-06-15 18:48:55 +0800241 bsc_write(con->bsc, msg->data, msg->len);
Holger Hans Peter Freyther3025e192010-03-26 09:18:02 +0100242 return 0;
Holger Hans Peter Freyther058eeb72010-01-31 09:46:21 +0100243
244send_to_all:
Holger Hans Peter Freyther45d11812010-06-15 18:46:36 +0800245 /*
246 * Filter Paging from the network. We do not want to send a PAGING
247 * Command to every BSC in our network. We will analys the PAGING
248 * message and then send it to the authenticated messages...
249 */
250 if (parsed->ipa_proto == IPAC_PROTO_SCCP && parsed->gsm_type == BSS_MAP_MSG_PAGING) {
Holger Hans Peter Freytherbae9da42010-03-30 05:57:42 +0200251 bsc = bsc_nat_find_bsc(nat, msg);
252 if (bsc)
253 bsc_write(bsc, msg->data, msg->len);
254 else
255 LOGP(DNAT, LOGL_ERROR, "Could not determine BSC for paging.\n");
Holger Hans Peter Freyther45d11812010-06-15 18:46:36 +0800256
257 goto exit;
258 }
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100259 /* currently send this to every BSC connected */
Holger Hans Peter Freyther9a85ef32010-06-15 18:46:11 +0800260 llist_for_each_entry(bsc, &nat->bsc_connections, list_entry) {
Holger Hans Peter Freyther3f37b8f2010-02-08 23:24:32 +0100261 if (!bsc->authenticated)
262 continue;
263
Holger Hans Peter Freyther3025e192010-03-26 09:18:02 +0100264 bsc_write(bsc, msg->data, msg->len);
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100265 }
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +0800266
267exit:
268 talloc_free(parsed);
Holger Hans Peter Freyther058eeb72010-01-31 09:46:21 +0100269 return 0;
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +0100270}
271
Holger Hans Peter Freytherbaf2abe2010-06-15 18:47:29 +0800272static void msc_connection_was_lost(struct bsc_msc_connection *con)
273{
Holger Hans Peter Freythercd895372010-03-29 08:04:09 +0200274 struct bsc_connection *bsc, *tmp;
275
276 LOGP(DMSC, LOGL_ERROR, "Closing all connections downstream.\n");
277 llist_for_each_entry_safe(bsc, tmp, &nat->bsc_connections, list_entry)
278 remove_bsc_connection(bsc);
279
Holger Hans Peter Freyther241e1302010-03-31 09:16:56 +0200280 bsc_mgcp_free_endpoints(nat);
Holger Hans Peter Freythercd895372010-03-29 08:04:09 +0200281 bsc_msc_schedule_connect(con);
Holger Hans Peter Freytherbaf2abe2010-06-15 18:47:29 +0800282}
283
Holger Hans Peter Freyther6f5fbfd2010-06-15 18:47:02 +0800284static int ipaccess_msc_read_cb(struct bsc_fd *bfd)
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +0100285{
286 int error;
287 struct msgb *msg = ipaccess_read_msg(bfd, &error);
288 struct ipaccess_head *hh;
289
290 if (!msg) {
291 if (error == 0) {
Holger Hans Peter Freyther418f3942010-01-29 05:58:43 +0100292 LOGP(DNAT, LOGL_FATAL, "The connection the MSC was lost, exiting\n");
Holger Hans Peter Freytherbaf2abe2010-06-15 18:47:29 +0800293 bsc_msc_lost(msc_con);
294 return -1;
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +0100295 }
296
Holger Hans Peter Freyther418f3942010-01-29 05:58:43 +0100297 LOGP(DNAT, LOGL_ERROR, "Failed to parse ip access message: %d\n", error);
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +0100298 return -1;
299 }
300
Holger Hans Peter Freyther418f3942010-01-29 05:58:43 +0100301 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 +0100302
303 /* handle base message handling */
304 hh = (struct ipaccess_head *) msg->data;
305 ipaccess_rcvmsg_base(msg, bfd);
306
307 /* initialize the networking. This includes sending a GSM08.08 message */
308 if (hh->proto == IPAC_PROTO_IPACCESS && msg->l2h[0] == IPAC_MSGT_ID_ACK)
309 initialize_msc_if_needed();
310 else if (hh->proto == IPAC_PROTO_SCCP)
311 forward_sccp_to_bts(msg);
312
Holger Hans Peter Freytheraad68b52010-06-15 18:46:48 +0800313 msgb_free(msg);
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +0100314 return 0;
315}
Holger Hans Peter Freyther9e2c5f52010-06-15 18:44:42 +0800316
Holger Hans Peter Freyther6f5fbfd2010-06-15 18:47:02 +0800317static int ipaccess_msc_write_cb(struct bsc_fd *bfd, struct msgb *msg)
318{
319 int rc;
320 rc = write(bfd->fd, msg->data, msg->len);
321
322 if (rc != msg->len) {
323 LOGP(DNAT, LOGL_ERROR, "Failed to write MSG to MSC.\n");
324 return -1;
325 }
326
327 return rc;
328}
329
Holger Hans Peter Freyther49d80682010-01-12 21:34:54 +0100330/*
331 * Below is the handling of messages coming
332 * from the BSC and need to be forwarded to
333 * a real BSC.
334 */
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100335
336/*
337 * Remove the connection from the connections list,
338 * remove it from the patching of SCCP header lists
339 * as well. Maybe in the future even close connection..
340 */
341static void remove_bsc_connection(struct bsc_connection *connection)
342{
Holger Hans Peter Freyther058eeb72010-01-31 09:46:21 +0100343 struct sccp_connections *sccp_patch, *tmp;
Holger Hans Peter Freythered07a3f2010-06-15 18:47:10 +0800344 bsc_unregister_fd(&connection->write_queue.bfd);
345 close(connection->write_queue.bfd.fd);
Holger Hans Peter Freytherf38e8792010-03-26 09:27:08 +0100346 write_queue_clear(&connection->write_queue);
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100347 llist_del(&connection->list_entry);
Holger Hans Peter Freyther058eeb72010-01-31 09:46:21 +0100348
Holger Hans Peter Freytheraa698242010-06-15 18:46:19 +0800349 /* stop the timeout timer */
350 bsc_del_timer(&connection->id_timeout);
351
Holger Hans Peter Freyther058eeb72010-01-31 09:46:21 +0100352 /* remove all SCCP connections */
Holger Hans Peter Freyther9a85ef32010-06-15 18:46:11 +0800353 llist_for_each_entry_safe(sccp_patch, tmp, &nat->sccp_connections, list_entry) {
Holger Hans Peter Freyther058eeb72010-01-31 09:46:21 +0100354 if (sccp_patch->bsc != connection)
355 continue;
356
Holger Hans Peter Freyther7c99d4f2010-03-26 09:28:40 +0100357#warning "TODO: Send a RLSD to the MSC. Or at least a clear command."
Holger Hans Peter Freyther23fe7be2010-03-30 10:45:48 +0200358 sccp_connection_destroy(sccp_patch);
Holger Hans Peter Freyther058eeb72010-01-31 09:46:21 +0100359 }
360
Holger Hans Peter Freyther26a43892010-04-05 23:09:27 +0200361 /* close endpoints allocated by this BSC */
362 bsc_mgcp_clear_endpoints_for(connection);
363
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100364 talloc_free(connection);
365}
366
Holger Hans Peter Freytheraa698242010-06-15 18:46:19 +0800367static void ipaccess_close_bsc(void *data)
368{
369 struct bsc_connection *conn = data;
370
371 LOGP(DNAT, LOGL_ERROR, "BSC didn't respond to identity request. Closing.\n");
372 remove_bsc_connection(conn);
373}
374
375static void ipaccess_auth_bsc(struct tlv_parsed *tvp, struct bsc_connection *bsc)
376{
377 struct bsc_config *conf;
378 const char* token = (const char *) TLVP_VAL(tvp, IPAC_IDTAG_UNITNAME);
379
380 llist_for_each_entry(conf, &bsc->nat->bsc_configs, entry) {
381 if (strcmp(conf->token, token) == 0) {
382 bsc->authenticated = 1;
Holger Hans Peter Freyther47dd4942010-04-06 15:11:34 +0200383 bsc->cfg = conf;
Holger Hans Peter Freytheraa698242010-06-15 18:46:19 +0800384 bsc_del_timer(&bsc->id_timeout);
Holger Hans Peter Freyther47dd4942010-04-06 15:11:34 +0200385 LOGP(DNAT, LOGL_NOTICE, "Authenticated bsc nr: %d lac: %d\n", conf->nr, conf->lac);
Holger Hans Peter Freytheraa698242010-06-15 18:46:19 +0800386 break;
387 }
388 }
389}
390
Holger Hans Peter Freyther747d6542010-03-26 07:24:34 +0100391static int forward_sccp_to_msc(struct bsc_connection *bsc, struct msgb *msg)
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100392{
Holger Hans Peter Freyther49c7fb52010-06-15 18:48:55 +0800393 struct sccp_connections *con;
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +0800394 struct bsc_nat_parsed *parsed;
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100395
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +0800396 /* Parse and filter messages */
397 parsed = bsc_nat_parse(msg);
398 if (!parsed) {
399 LOGP(DNAT, LOGL_ERROR, "Can not parse msg from BSC.\n");
Holger Hans Peter Freytherd7657ff2010-03-30 07:35:46 +0200400 msgb_free(msg);
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +0800401 return -1;
402 }
403
Holger Hans Peter Freyther1d6fb182010-01-30 11:53:30 +0100404 if (bsc_nat_filter_ipa(DIR_MSC, msg, parsed))
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +0800405 goto exit;
Holger Hans Peter Freyther6a97b8d2010-06-15 18:45:26 +0800406
Holger Hans Peter Freytherbbb9d392010-04-02 03:42:44 +0200407 /*
408 * check authentication after filtering to not reject auth
409 * responses coming from the BSC. We have to make sure that
410 * nothing from the exit path will forward things to the MSC
411 */
412 if (!bsc->authenticated) {
413 LOGP(DNAT, LOGL_ERROR, "BSC is not authenticated.\n");
414 msgb_free(msg);
415 return -1;
416 }
417
418
Holger Hans Peter Freyther058eeb72010-01-31 09:46:21 +0100419 /* modify the SCCP entries */
420 if (parsed->ipa_proto == IPAC_PROTO_SCCP) {
421 switch (parsed->sccp_type) {
422 case SCCP_MSG_TYPE_CR:
423 if (create_sccp_src_ref(bsc, msg, parsed) != 0)
424 goto exit2;
Holger Hans Peter Freyther49c7fb52010-06-15 18:48:55 +0800425 con = patch_sccp_src_ref_to_msc(msg, parsed, nat);
Holger Hans Peter Freyther058eeb72010-01-31 09:46:21 +0100426 break;
427 case SCCP_MSG_TYPE_RLSD:
428 case SCCP_MSG_TYPE_CREF:
429 case SCCP_MSG_TYPE_DT1:
430 case SCCP_MSG_TYPE_CC:
Holger Hans Peter Freytherf46ce532010-04-06 10:22:34 +0200431 case SCCP_MSG_TYPE_IT:
Holger Hans Peter Freyther49c7fb52010-06-15 18:48:55 +0800432 con = patch_sccp_src_ref_to_msc(msg, parsed, nat);
Holger Hans Peter Freyther058eeb72010-01-31 09:46:21 +0100433 break;
434 case SCCP_MSG_TYPE_RLC:
Holger Hans Peter Freyther49c7fb52010-06-15 18:48:55 +0800435 con = patch_sccp_src_ref_to_msc(msg, parsed, nat);
Holger Hans Peter Freytherf4cfc4f2010-03-31 09:15:05 +0200436 remove_sccp_src_ref(bsc, msg, parsed);
Holger Hans Peter Freyther058eeb72010-01-31 09:46:21 +0100437 break;
438 case SCCP_MSG_TYPE_UDT:
439 /* simply forward everything */
Holger Hans Peter Freyther49c7fb52010-06-15 18:48:55 +0800440 con = NULL;
Holger Hans Peter Freyther058eeb72010-01-31 09:46:21 +0100441 break;
442 default:
Holger Hans Peter Freyther0ab6bab2010-06-15 18:47:49 +0800443 LOGP(DNAT, LOGL_ERROR, "Not forwarding to msc sccp type: 0x%x\n", parsed->sccp_type);
Holger Hans Peter Freyther49c7fb52010-06-15 18:48:55 +0800444 con = NULL;
Holger Hans Peter Freyther058eeb72010-01-31 09:46:21 +0100445 goto exit2;
446 break;
447 }
Holger Hans Peter Freyther3c3bce12010-04-01 10:16:28 +0200448 } else if (parsed->ipa_proto == NAT_IPAC_PROTO_MGCP) {
449 bsc_mgcp_forward(bsc, msg);
450 goto exit2;
Holger Hans Peter Freyther49c7fb52010-06-15 18:48:55 +0800451 } else {
452 LOGP(DNAT, LOGL_ERROR, "Not forwarding unknown stream id: 0x%x\n", parsed->ipa_proto);
453 goto exit2;
Holger Hans Peter Freyther058eeb72010-01-31 09:46:21 +0100454 }
455
Holger Hans Peter Freyther49c7fb52010-06-15 18:48:55 +0800456 if (con && con->bsc != bsc) {
Holger Hans Peter Freyther058eeb72010-01-31 09:46:21 +0100457 LOGP(DNAT, LOGL_ERROR, "Found the wrong entry.\n");
458 goto exit2;
459 }
460
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100461 /* send the non-filtered but maybe modified msg */
Holger Hans Peter Freytherbaf2abe2010-06-15 18:47:29 +0800462 if (write_queue_enqueue(&msc_con->write_queue, msg) != 0) {
Holger Hans Peter Freyther6f5fbfd2010-06-15 18:47:02 +0800463 LOGP(DNAT, LOGL_ERROR, "Can not queue message for the MSC.\n");
464 msgb_free(msg);
465 }
Holger Hans Peter Freyther38a77d02010-01-30 12:45:10 +0100466 talloc_free(parsed);
Holger Hans Peter Freyther6f5fbfd2010-06-15 18:47:02 +0800467 return 0;
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +0800468
469exit:
Holger Hans Peter Freyther38a77d02010-01-30 12:45:10 +0100470 /* if we filter out the reset send an ack to the BSC */
471 if (parsed->bssap == 0 && parsed->gsm_type == BSS_MAP_MSG_RESET) {
Holger Hans Peter Freyther747d6542010-03-26 07:24:34 +0100472 send_reset_ack(bsc);
473 send_reset_ack(bsc);
Holger Hans Peter Freytheraa698242010-06-15 18:46:19 +0800474 } else if (parsed->ipa_proto == IPAC_PROTO_IPACCESS) {
475 /* do we know who is handling this? */
476 if (msg->l2h[0] == IPAC_MSGT_ID_RESP) {
477 struct tlv_parsed tvp;
478 ipaccess_idtag_parse(&tvp,
479 (unsigned char *) msg->l2h + 2,
480 msgb_l2len(msg) - 2);
481 if (TLVP_PRESENT(&tvp, IPAC_IDTAG_UNITNAME))
482 ipaccess_auth_bsc(&tvp, bsc);
483 }
484
485 goto exit2;
Holger Hans Peter Freyther38a77d02010-01-30 12:45:10 +0100486 }
487
Holger Hans Peter Freyther058eeb72010-01-31 09:46:21 +0100488exit2:
Holger Hans Peter Freyther0b8f69d2010-06-15 18:45:38 +0800489 talloc_free(parsed);
Holger Hans Peter Freyther6f5fbfd2010-06-15 18:47:02 +0800490 msgb_free(msg);
491 return -1;
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100492}
493
Holger Hans Peter Freythered07a3f2010-06-15 18:47:10 +0800494static int ipaccess_bsc_read_cb(struct bsc_fd *bfd)
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100495{
496 int error;
Holger Hans Peter Freyther747d6542010-03-26 07:24:34 +0100497 struct bsc_connection *bsc = bfd->data;
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100498 struct msgb *msg = ipaccess_read_msg(bfd, &error);
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100499
500 if (!msg) {
501 if (error == 0) {
Holger Hans Peter Freyther418f3942010-01-29 05:58:43 +0100502 LOGP(DNAT, LOGL_ERROR, "The connection to the BSC was lost. Cleaning it\n");
Holger Hans Peter Freyther747d6542010-03-26 07:24:34 +0100503 remove_bsc_connection(bsc);
Holger Hans Peter Freyther418f3942010-01-29 05:58:43 +0100504 } else {
505 LOGP(DNAT, LOGL_ERROR, "Failed to parse ip access message: %d\n", error);
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100506 }
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100507 return -1;
508 }
509
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100510
Holger Hans Peter Freyther418f3942010-01-29 05:58:43 +0100511 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 +0100512
513 /* Handle messages from the BSC */
514 /* FIXME: Currently no PONG is sent to the BSC */
515 /* FIXME: Currently no ID ACK is sent to the BSC */
Holger Hans Peter Freyther747d6542010-03-26 07:24:34 +0100516 forward_sccp_to_msc(bsc, msg);
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100517
518 return 0;
519}
520
Holger Hans Peter Freyther3025e192010-03-26 09:18:02 +0100521static int ipaccess_bsc_write_cb(struct bsc_fd *bfd, struct msgb *msg)
522{
523 int rc;
524
525 rc = write(bfd->fd, msg->data, msg->len);
526 if (rc != msg->len)
527 LOGP(DNAT, LOGL_ERROR, "Failed to write message to the BSC.\n");
528
529 return rc;
530}
531
Holger Hans Peter Freyther49d80682010-01-12 21:34:54 +0100532static int ipaccess_listen_bsc_cb(struct bsc_fd *bfd, unsigned int what)
533{
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100534 struct bsc_connection *bsc;
Holger Hans Peter Freyther49d80682010-01-12 21:34:54 +0100535 int ret;
536 struct sockaddr_in sa;
537 socklen_t sa_len = sizeof(sa);
538
539 if (!(what & BSC_FD_READ))
540 return 0;
541
542 ret = accept(bfd->fd, (struct sockaddr *) &sa, &sa_len);
543 if (ret < 0) {
544 perror("accept");
545 return ret;
546 }
547
Holger Hans Peter Freythercd895372010-03-29 08:04:09 +0200548 /*
549 * if we are not connected to a msc... just close the socket
550 */
551 if (!msc_con->is_connected) {
552 LOGP(DNAT, LOGL_NOTICE, "Disconnecting BSC due lack of MSC connection.\n");
Holger Hans Peter Freythera7c377d2010-04-06 12:42:35 +0200553 close(ret);
Holger Hans Peter Freythercd895372010-03-29 08:04:09 +0200554 return 0;
555 }
556
Holger Hans Peter Freyther49d80682010-01-12 21:34:54 +0100557 /* todo... do something with the connection */
Holger Hans Peter Freytherda86c0a2010-01-12 21:35:32 +0100558 /* todo... use GNUtls to see if we want to trust this as a BTS */
Holger Hans Peter Freyther49d80682010-01-12 21:34:54 +0100559
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100560 /*
561 *
562 */
Holger Hans Peter Freytherdcf8a7d2010-06-15 18:48:01 +0800563 bsc = bsc_connection_alloc(nat);
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100564 if (!bsc) {
Holger Hans Peter Freyther418f3942010-01-29 05:58:43 +0100565 LOGP(DNAT, LOGL_ERROR, "Failed to allocate BSC struct.\n");
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100566 close(ret);
567 return -1;
568 }
569
Holger Hans Peter Freythered07a3f2010-06-15 18:47:10 +0800570 write_queue_init(&bsc->write_queue, 100);
571 bsc->write_queue.bfd.data = bsc;
572 bsc->write_queue.bfd.fd = ret;
573 bsc->write_queue.read_cb = ipaccess_bsc_read_cb;
Holger Hans Peter Freyther3025e192010-03-26 09:18:02 +0100574 bsc->write_queue.write_cb = ipaccess_bsc_write_cb;
Holger Hans Peter Freythered07a3f2010-06-15 18:47:10 +0800575 bsc->write_queue.bfd.when = BSC_FD_READ;
576 if (bsc_register_fd(&bsc->write_queue.bfd) < 0) {
Holger Hans Peter Freyther418f3942010-01-29 05:58:43 +0100577 LOGP(DNAT, LOGL_ERROR, "Failed to register BSC fd.\n");
Holger Hans Peter Freyther24614ad2010-01-13 09:28:12 +0100578 close(ret);
579 talloc_free(bsc);
580 return -2;
581 }
582
Holger Hans Peter Freytherb9ac37d2010-04-05 17:58:52 +0200583 LOGP(DNAT, LOGL_NOTICE, "Registered new BSC\n");
Holger Hans Peter Freyther9a85ef32010-06-15 18:46:11 +0800584 llist_add(&bsc->list_entry, &nat->bsc_connections);
Holger Hans Peter Freytherdb7ba7d2010-03-26 07:41:54 +0100585 send_id_ack(bsc);
586 send_id_req(bsc);
Holger Hans Peter Freytherd131b792010-03-31 07:30:58 +0200587 send_mgcp_reset(bsc);
Holger Hans Peter Freytheraa698242010-06-15 18:46:19 +0800588
589 /*
590 * start the hangup timer
591 */
592 bsc->id_timeout.data = bsc;
593 bsc->id_timeout.cb = ipaccess_close_bsc;
594 bsc_schedule_timer(&bsc->id_timeout, 2, 0);
Holger Hans Peter Freyther49d80682010-01-12 21:34:54 +0100595 return 0;
596}
597
598static int listen_for_bsc(struct bsc_fd *bfd, struct in_addr *in_addr, int port)
599{
600 struct sockaddr_in addr;
601 int ret, on = 1;
602
603 bfd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
604 bfd->cb = ipaccess_listen_bsc_cb;
605 bfd->when = BSC_FD_READ;
606
607 memset(&addr, 0, sizeof(addr));
608 addr.sin_family = AF_INET;
609 addr.sin_port = htons(port);
610 addr.sin_addr.s_addr = in_addr->s_addr;
611
612 setsockopt(bfd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
613
614 ret = bind(bfd->fd, (struct sockaddr *) &addr, sizeof(addr));
615 if (ret < 0) {
616 fprintf(stderr, "Could not bind the BSC socket %s\n",
617 strerror(errno));
618 return -EIO;
619 }
620
621 ret = listen(bfd->fd, 1);
622 if (ret < 0) {
623 perror("listen");
624 return ret;
625 }
626
627 ret = bsc_register_fd(bfd);
628 if (ret < 0) {
629 perror("register_listen_fd");
630 return ret;
631 }
632 return 0;
633}
634
Holger Hans Peter Freyther9e2c5f52010-06-15 18:44:42 +0800635static void print_usage()
636{
637 printf("Usage: bsc_nat\n");
638}
639
640static void print_help()
641{
642 printf(" Some useful help...\n");
643 printf(" -h --help this text\n");
644 printf(" -d option --debug=DRLL:DCC:DMM:DRR:DRSL:DNM enable debugging\n");
645 printf(" -s --disable-color\n");
646 printf(" -c --config-file filename The config file to use.\n");
647 printf(" -m --msc=IP. The address of the MSC.\n");
Holger Hans Peter Freyther49d80682010-01-12 21:34:54 +0100648 printf(" -l --local=IP. The local address of this BSC.\n");
Holger Hans Peter Freyther9e2c5f52010-06-15 18:44:42 +0800649}
650
651static void handle_options(int argc, char** argv)
652{
653 while (1) {
654 int option_index = 0, c;
655 static struct option long_options[] = {
656 {"help", 0, 0, 'h'},
657 {"debug", 1, 0, 'd'},
658 {"config-file", 1, 0, 'c'},
659 {"disable-color", 0, 0, 's'},
660 {"timestamp", 0, 0, 'T'},
661 {"msc", 1, 0, 'm'},
662 {"local", 1, 0, 'l'},
663 {0, 0, 0, 0}
664 };
665
666 c = getopt_long(argc, argv, "hd:sTPc:m:l:",
667 long_options, &option_index);
668 if (c == -1)
669 break;
670
671 switch (c) {
672 case 'h':
673 print_usage();
674 print_help();
675 exit(0);
676 case 's':
Holger Hans Peter Freyther6c45f2e2010-06-15 19:06:18 +0800677 debug_set_use_color(stderr_target, 0);
Holger Hans Peter Freyther9e2c5f52010-06-15 18:44:42 +0800678 break;
679 case 'd':
Holger Hans Peter Freyther6c45f2e2010-06-15 19:06:18 +0800680 debug_parse_category_mask(stderr_target, optarg);
Holger Hans Peter Freyther9e2c5f52010-06-15 18:44:42 +0800681 break;
682 case 'c':
683 config_file = strdup(optarg);
684 break;
685 case 'T':
Holger Hans Peter Freyther6c45f2e2010-06-15 19:06:18 +0800686 debug_set_print_timestamp(stderr_target, 1);
Holger Hans Peter Freyther9e2c5f52010-06-15 18:44:42 +0800687 break;
688 case 'm':
689 msc_address = strdup(optarg);
690 break;
691 case 'l':
692 inet_aton(optarg, &local_addr);
693 break;
694 default:
695 /* ignore */
696 break;
697 }
698 }
699}
700
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +0100701static void signal_handler(int signal)
702{
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +0100703 switch (signal) {
704 case SIGABRT:
705 /* in case of abort, we want to obtain a talloc report
706 * and then return to the caller, who will abort the process */
707 case SIGUSR1:
708 talloc_report_full(tall_bsc_ctx, stderr);
709 break;
710 default:
711 break;
712 }
713}
714
Holger Hans Peter Freyther9e2c5f52010-06-15 18:44:42 +0800715int main(int argc, char** argv)
716{
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +0100717
Holger Hans Peter Freyther6c45f2e2010-06-15 19:06:18 +0800718 debug_init();
719 stderr_target = debug_target_create_stderr();
720 debug_add_target(stderr_target);
721 debug_set_all_filter(stderr_target, 1);
722
Holger Hans Peter Freyther9e2c5f52010-06-15 18:44:42 +0800723 /* parse options */
Holger Hans Peter Freyther49d80682010-01-12 21:34:54 +0100724 local_addr.s_addr = INADDR_ANY;
Holger Hans Peter Freyther9e2c5f52010-06-15 18:44:42 +0800725 handle_options(argc, argv);
726
Holger Hans Peter Freyther9a85ef32010-06-15 18:46:11 +0800727 nat = bsc_nat_alloc();
728 if (!nat) {
729 fprintf(stderr, "Failed to allocate the BSC nat.\n");
730 return -4;
731 }
732
Holger Hans Peter Freytherf7d33352010-06-15 18:50:26 +0800733 nat->mgcp_cfg = talloc_zero(nat, struct mgcp_config);
734
Holger Hans Peter Freyther9a85ef32010-06-15 18:46:11 +0800735 /* init vty and parse */
736 bsc_nat_vty_init(nat);
737 telnet_init(NULL, 4244);
Holger Hans Peter Freytherf7d33352010-06-15 18:50:26 +0800738 if (mgcp_parse_config(config_file, nat->mgcp_cfg) < 0) {
Holger Hans Peter Freyther9a85ef32010-06-15 18:46:11 +0800739 fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);
740 return -3;
741 }
742
Holger Hans Peter Freyther9e2c5f52010-06-15 18:44:42 +0800743 /* seed the PRNG */
744 srand(time(NULL));
745
Holger Hans Peter Freythera7f80182010-03-31 13:02:22 +0200746 /*
747 * Setup the MGCP code..
748 */
749 if (bsc_mgcp_init(nat) != 0)
750 return -4;
751
Holger Hans Peter Freyther49d80682010-01-12 21:34:54 +0100752 /* connect to the MSC */
Holger Hans Peter Freytherbaf2abe2010-06-15 18:47:29 +0800753 msc_con = bsc_msc_create(msc_address, 5000);
754 if (!msc_con) {
755 fprintf(stderr, "Creating a bsc_msc_connection failed.\n");
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +0100756 exit(1);
757 }
758
Holger Hans Peter Freytherbaf2abe2010-06-15 18:47:29 +0800759 msc_con->connection_loss = msc_connection_was_lost;
760 msc_con->write_queue.read_cb = ipaccess_msc_read_cb;
761 msc_con->write_queue.write_cb = ipaccess_msc_write_cb;;
762 bsc_msc_connect(msc_con);
763
Holger Hans Peter Freyther49d80682010-01-12 21:34:54 +0100764 /* wait for the BSC */
Holger Hans Peter Freyther2d677c62010-03-26 06:51:04 +0100765 if (listen_for_bsc(&bsc_listen, &local_addr, 5000) < 0) {
Holger Hans Peter Freyther49d80682010-01-12 21:34:54 +0100766 fprintf(stderr, "Failed to listen for BSC.\n");
767 exit(1);
768 }
769
Holger Hans Peter Freyther6ace5222010-01-12 21:15:08 +0100770 signal(SIGABRT, &signal_handler);
771 signal(SIGUSR1, &signal_handler);
772 signal(SIGPIPE, SIG_IGN);
773
774 while (1) {
775 bsc_select_main(0);
776 }
777
Holger Hans Peter Freyther9e2c5f52010-06-15 18:44:42 +0800778 return 0;
779}