blob: ac160bb2cdc4521352c1472569be93f4b1d37c1f [file] [log] [blame]
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +08001/* MSC related stuff... */
2/*
3 * (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
4 * (C) 2010 by On-Waves
5 * All Rights Reserved
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 */
22
23#include <bsc_data.h>
24#include <bss_patch.h>
25#include <bssap_sccp.h>
26#include <ipaccess.h>
27#include <mtp_data.h>
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +080028#include <cellmgr_debug.h>
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080029
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +080030#include <osmocore/tlv.h>
31#include <osmocore/utils.h>
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080032
33#include <arpa/inet.h>
34#include <sys/socket.h>
35#include <netinet/tcp.h>
36
37#include <fcntl.h>
38#include <unistd.h>
39#include <errno.h>
40#include <string.h>
41
42#define RECONNECT_TIME 10, 0
43#define NAT_MUX 0xfc
44
45static void msc_send_id_response(struct bsc_data *bsc);
46static void msc_send(struct bsc_data *bsc, struct msgb *msg, int proto);
47
48void mtp_link_slta_recv(struct mtp_link *link)
49{
50 struct msgb *msg;
51 unsigned int sls;
52
53 while (!llist_empty(&link->pending_msgs)) {
54 msg = msgb_dequeue(&link->pending_msgs);
55 sls = (unsigned int) msg->l3h;
56
57 if (mtp_link_submit_sccp_data(link, sls, msg->l2h, msgb_l2len(msg)) != 0)
58 LOGP(DMSC, LOGL_ERROR, "Could not forward SCCP message.\n");
59
60 msgb_free(msg);
61 }
62}
63
64void msc_clear_queue(struct bsc_data *data)
65{
66 struct msgb *msg;
67
68 LOGP(DMSC, LOGL_NOTICE, "Clearing the MSC to BSC queue.\n");
69 while (!llist_empty(&data->link.the_link->pending_msgs)) {
70 msg = msgb_dequeue(&data->link.the_link->pending_msgs);
71 msgb_free(msg);
72 }
73}
74
Holger Hans Peter Freyther43d9eec2010-08-07 01:54:19 +080075void msc_close_connection(struct bsc_data *bsc)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080076{
77 struct bsc_fd *bfd = &bsc->msc_connection.bfd;
78
79 close(bfd->fd);
80 bsc_unregister_fd(bfd);
81 bfd->fd = -1;
82 release_bsc_resources(bsc);
83 bsc_del_timer(&bsc->ping_timeout);
84 bsc_del_timer(&bsc->pong_timeout);
85}
86
87static void msc_connect_timeout(void *_bsc_data)
88{
89 struct bsc_data *bsc_data = _bsc_data;
90
91 LOGP(DMSC, LOGL_ERROR, "Timeout on the MSC connection.\n");
Holger Hans Peter Freyther43d9eec2010-08-07 01:54:19 +080092 msc_close_connection(bsc_data);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080093}
94
95static void msc_pong_timeout(void *_bsc_data)
96{
97 struct bsc_data *bsc_data = _bsc_data;
98 LOGP(DMSC, LOGL_ERROR, "MSC didn't respond to ping. Closing.\n");
Holger Hans Peter Freyther43d9eec2010-08-07 01:54:19 +080099 msc_close_connection(bsc_data);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800100}
101
102static void send_ping(struct bsc_data *bsc)
103{
104 struct msgb *msg;
105
106 msg = msgb_alloc_headroom(4096, 128, "ping");
107 if (!msg) {
108 LOGP(DMSC, LOGL_ERROR, "Failed to create PING.\n");
109 return;
110 }
111
112 msg->l2h = msgb_put(msg, 1);
113 msg->l2h[0] = IPAC_MSGT_PING;
114
115 msc_send(bsc, msg, IPAC_PROTO_IPACCESS);
116}
117
118static void msc_ping_timeout(void *_bsc_data)
119{
120 struct bsc_data *bsc_data = _bsc_data;
121
122 if (bsc_data->ping_time < 0)
123 return;
124
125 send_ping(bsc_data);
126
127 /* send another ping in 20 seconds */
128 bsc_schedule_timer(&bsc_data->ping_timeout, bsc_data->ping_time, 0);
129
130 /* also start a pong timer */
131 bsc_schedule_timer(&bsc_data->pong_timeout, bsc_data->pong_time, 0);
132}
133
134/*
135 * callback with IP access data
136 */
137static int ipaccess_a_fd_cb(struct bsc_fd *bfd)
138{
139 int error;
140 struct ipaccess_head *hh;
141 struct mtp_link *link;
142 struct bsc_data *bsc;
143 struct msgb *msg;
144
145 msg = ipaccess_read_msg(bfd, &error);
146
147 bsc = (struct bsc_data *) bfd->data;
148
149 if (!msg) {
150 if (error == 0)
151 fprintf(stderr, "The connection to the MSC was lost, exiting\n");
152 else
153 fprintf(stderr, "Error in the IPA stream.\n");
154
Holger Hans Peter Freyther43d9eec2010-08-07 01:54:19 +0800155 msc_close_connection(bsc);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800156 return -1;
157 }
158
159 LOGP(DMSC, LOGL_DEBUG, "From MSC: %s proto: %d\n", hexdump(msg->data, msg->len), msg->l2h[0]);
160
161 /* handle base message handling */
162 hh = (struct ipaccess_head *) msg->data;
163 ipaccess_rcvmsg_base(msg, bfd);
164
165 link = bsc->link.the_link;
166
167 /* initialize the networking. This includes sending a GSM08.08 message */
168 if (hh->proto == IPAC_PROTO_IPACCESS) {
169 if (bsc->first_contact) {
170 LOGP(DMSC, LOGL_NOTICE, "Connected to MSC. Sending reset.\n");
171 bsc_del_timer(&bsc->msc_timeout);
172 bsc->first_contact = 0;
Holger Hans Peter Freyther0c95c6a2010-08-07 02:37:43 +0800173 bsc->msc_link_down = 0;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800174 msc_send_reset(bsc);
175 }
176 if (msg->l2h[0] == IPAC_MSGT_ID_GET && bsc->token) {
177 msc_send_id_response(bsc);
178 } else if (msg->l2h[0] == IPAC_MSGT_PONG) {
179 bsc_del_timer(&bsc->pong_timeout);
180 }
181 } else if (hh->proto == IPAC_PROTO_SCCP) {
182 struct sccp_parse_result result;
183 int rc;
184 rc = bss_patch_filter_msg(msg, &result);
185
186 if (rc == BSS_FILTER_RESET_ACK) {
187 LOGP(DMSC, LOGL_NOTICE, "Filtering reset ack from the MSC\n");
188 } else if (rc == BSS_FILTER_RLSD) {
189 LOGP(DMSC, LOGL_DEBUG, "Filtering RLSD from the MSC\n");
190 update_con_state(rc, &result, msg, 1, 0);
191 } else if (rc == BSS_FILTER_RLC) {
192 /* if we receive this we have forwarded a RLSD to the network */
193 LOGP(DMSC, LOGL_ERROR, "RLC from the network. BAD!\n");
194 } else if (rc == BSS_FILTER_CLEAR_COMPL) {
195 LOGP(DMSC, LOGL_ERROR, "Clear Complete from the network.\n");
196 } else if (link->sccp_up) {
197 unsigned int sls;
198
199 update_con_state(rc, &result, msg, 1, 0);
200 sls = sls_for_src_ref(result.destination_local_reference);
201
202 /* patch a possible PC */
203 bss_rewrite_header_to_bsc(msg, link->opc, link->dpc);
204
205 /* we can not forward it right now */
206 if (link->sltm_pending) {
207 LOGP(DMSC, LOGL_NOTICE, "Queueing msg for pending SLTM.\n");
Holger Hans Peter Freyther5aa17012010-07-31 04:37:26 +0800208 msg->l3h = (uint8_t *) sls;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800209 msgb_enqueue(&link->pending_msgs, msg);
210 return 0;
211 }
212
213 if (mtp_link_submit_sccp_data(link, sls, msg->l2h, msgb_l2len(msg)) != 0)
214 LOGP(DMSC, LOGL_ERROR, "Could not forward SCCP message.\n");
215 }
216 } else if (hh->proto == NAT_MUX) {
217 mgcp_forward(bsc, msg->l2h, msgb_l2len(msg));
218 } else {
219 LOGP(DMSC, LOGL_ERROR, "Unknown IPA proto 0x%x\n", hh->proto);
220 }
221
222 msgb_free(msg);
223 return 0;
224}
225
226static int ipaccess_write_cb(struct bsc_fd *fd, struct msgb *msg)
227{
228 int rc;
229
230 LOGP(DMSC, LOGL_DEBUG, "Sending to MSC: %s\n", hexdump(msg->data, msg->len));
231 rc = write(fd->fd, msg->data, msg->len);
232 if (rc != msg->len)
233 LOGP(DMSC, LOGL_ERROR, "Could not write to MSC.\n");
234
235 return rc;
236}
237
238/* called in the case of a non blocking connect */
239static int msc_connection_connect(struct bsc_fd *fd, unsigned int what)
240{
241 int rc;
242 int val;
243 socklen_t len = sizeof(val);
244 struct bsc_data *bsc;
245
246 bsc = (struct bsc_data *) fd->data;
247
248 if (fd != &bsc->msc_connection.bfd) {
249 LOGP(DMSC, LOGL_ERROR, "This is only working with the MSC connection.\n");
250 return -1;
251 }
252
253 if ((what & BSC_FD_WRITE) == 0)
254 return -1;
255
256 /* check the socket state */
257 rc = getsockopt(fd->fd, SOL_SOCKET, SO_ERROR, &val, &len);
258 if (rc != 0) {
259 LOGP(DMSC, LOGL_ERROR, "getsockopt for the MSC socket failed.\n");
260 goto error;
261 }
262 if (val != 0) {
263 LOGP(DMSC, LOGL_ERROR, "Not connected to the MSC.\n");
264 goto error;
265 }
266
267
268 /* go to full operation */
269 fd->cb = write_queue_bfd_cb;
270 fd->when = BSC_FD_READ;
271 if (!llist_empty(&bsc->msc_connection.msg_queue))
272 fd->when |= BSC_FD_WRITE;
273 return 0;
274
275error:
Holger Hans Peter Freyther62585392010-08-07 02:26:47 +0800276 msc_close_connection(bsc);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800277 return -1;
278}
279
280static void setnonblocking(struct bsc_fd *fd)
281{
282 int flags;
283
284 flags = fcntl(fd->fd, F_GETFL);
285 if (flags < 0) {
286 perror("fcntl get failed");
287 close(fd->fd);
288 fd->fd = -1;
289 return;
290 }
291
292 flags |= O_NONBLOCK;
293 flags = fcntl(fd->fd, F_SETFL, flags);
294 if (flags < 0) {
295 perror("fcntl get failed");
296 close(fd->fd);
297 fd->fd = -1;
298 return;
299 }
300}
301
302static int connect_to_msc(struct bsc_fd *fd, const char *ip, int port, int tos)
303{
304 struct sockaddr_in sin;
305 int on = 1, ret;
306
307 LOGP(DMSC, LOGL_NOTICE, "Attempting to connect MSC at %s:%d\n", ip, port);
308
309 fd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
310
311 if (fd->fd < 0) {
312 perror("Creating TCP socket failed");
313 return fd->fd;
314 }
315
316 /* make it non blocking */
317 setnonblocking(fd);
318
319 memset(&sin, 0, sizeof(sin));
320 sin.sin_family = AF_INET;
321 sin.sin_port = htons(port);
322 inet_aton(ip, &sin.sin_addr);
323
324 setsockopt(fd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
325 ret = setsockopt(fd->fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
326 if (ret != 0)
327 LOGP(DMSC, LOGL_ERROR, "Failed to set TCP_NODELAY: %s\n", strerror(errno));
328 ret = setsockopt(fd->fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos));
329 if (ret != 0)
330 LOGP(DMSC, LOGL_ERROR, "Failed to set IP_TOS: %s\n", strerror(errno));
331
332 ret = connect(fd->fd, (struct sockaddr *) &sin, sizeof(sin));
333
334 if (ret == -1 && errno == EINPROGRESS) {
335 LOGP(DMSC, LOGL_ERROR, "MSC Connection in progress\n");
336 fd->when = BSC_FD_WRITE;
337 fd->cb = msc_connection_connect;
338 } else if (ret < 0) {
339 perror("Connection failed");
340 close(fd->fd);
341 fd->fd = -1;
342 return ret;
343 } else {
344 fd->when = BSC_FD_READ;
345 fd->cb = write_queue_bfd_cb;
346 }
347
348 ret = bsc_register_fd(fd);
349 if (ret < 0) {
350 perror("Registering the fd failed");
351 close(fd->fd);
352 fd->fd = -1;
353 return ret;
354 }
355
356 return ret;
357}
358
359static void msc_reconnect(void *_data)
360{
361 int rc;
362 struct bsc_data *bsc = (struct bsc_data *) _data;
363
364 bsc_del_timer(&bsc->reconnect_timer);
365 bsc->first_contact = 1;
366
367 rc = connect_to_msc(&bsc->msc_connection.bfd, bsc->msc_address, 5000, bsc->msc_ip_dscp);
368 if (rc < 0) {
369 fprintf(stderr, "Opening the MSC connection failed. Trying again\n");
370 bsc_schedule_timer(&bsc->reconnect_timer, RECONNECT_TIME);
371 return;
372 }
373
374 bsc->msc_timeout.cb = msc_connect_timeout;
375 bsc->msc_timeout.data = bsc;
376 bsc_schedule_timer(&bsc->msc_timeout, bsc->msc_time, 0);
377}
378
379void msc_schedule_reconnect(struct bsc_data *bsc)
380{
381 bsc_schedule_timer(&bsc->reconnect_timer, RECONNECT_TIME);
382}
383
384/*
385 * mgcp forwarding is below
386 */
387static int mgcp_do_write(struct bsc_fd *fd, struct msgb *msg)
388{
389 int ret;
390
391 LOGP(DMGCP, LOGL_DEBUG, "Sending msg to MGCP GW size: %u\n", msg->len);
392
393 ret = write(fd->fd, msg->data, msg->len);
394 if (ret != msg->len)
395 LOGP(DMGCP, LOGL_ERROR, "Failed to forward message to MGCP GW (%s).\n", strerror(errno));
396
397 return ret;
398}
399
400static int mgcp_do_read(struct bsc_fd *fd)
401{
402 struct msgb *mgcp;
403 int ret;
404
405 mgcp = msgb_alloc_headroom(4096, 128, "mgcp_from_gw");
406 if (!mgcp) {
407 LOGP(DMGCP, LOGL_ERROR, "Failed to allocate MGCP message.\n");
408 return -1;
409 }
410
411 ret = read(fd->fd, mgcp->data, 4096 - 128);
412 if (ret <= 0) {
413 LOGP(DMGCP, LOGL_ERROR, "Failed to read: %d/%s\n", errno, strerror(errno));
414 msgb_free(mgcp);
415 return -1;
416 } else if (ret > 4096 - 128) {
417 LOGP(DMGCP, LOGL_ERROR, "Too much data: %d\n", ret);
418 msgb_free(mgcp);
419 return -1;
420 }
421
422 mgcp->l2h = msgb_put(mgcp, ret);
423 msc_send(fd->data, mgcp, NAT_MUX);
424 return 0;
425}
426
Holger Hans Peter Freyther5aa17012010-07-31 04:37:26 +0800427void mgcp_forward(struct bsc_data *bsc, const uint8_t *data, unsigned int length)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800428{
429 struct msgb *mgcp;
430
431 if (length > 4096) {
432 LOGP(DMGCP, LOGL_ERROR, "Can not forward too big message.\n");
433 return;
434 }
435
436 mgcp = msgb_alloc(4096, "mgcp_to_gw");
437 if (!mgcp) {
438 LOGP(DMGCP, LOGL_ERROR, "Failed to send message.\n");
439 return;
440 }
441
442 msgb_put(mgcp, length);
443 memcpy(mgcp->data, data, mgcp->len);
444 if (write_queue_enqueue(&bsc->mgcp_agent, mgcp) != 0) {
445 LOGP(DMGCP, LOGL_FATAL, "Could not queue message to MGCP GW.\n");
446 msgb_free(mgcp);
447 }
448}
449
450static int mgcp_create_port(struct bsc_data *bsc)
451{
452 int on;
453 struct sockaddr_in addr;
454
455 bsc->mgcp_agent.bfd.fd = socket(AF_INET, SOCK_DGRAM, 0);
456 if (bsc->mgcp_agent.bfd.fd < 0) {
457 LOGP(DMGCP, LOGL_FATAL, "Failed to create UDP socket errno: %d\n", errno);
458 return -1;
459 }
460
461 on = 1;
462 setsockopt(bsc->mgcp_agent.bfd.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
463
464 /* try to bind the socket */
465 memset(&addr, 0, sizeof(addr));
466 addr.sin_family = AF_INET;
467 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
468 addr.sin_port = 0;
469
470 if (bind(bsc->mgcp_agent.bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
471 LOGP(DMGCP, LOGL_FATAL, "Failed to bind to any port.\n");
472 close(bsc->mgcp_agent.bfd.fd);
473 bsc->mgcp_agent.bfd.fd = -1;
474 return -1;
475 }
476
477 /* connect to the remote */
478 addr.sin_port = htons(2427);
479 if (connect(bsc->mgcp_agent.bfd.fd, (struct sockaddr *) & addr, sizeof(addr)) < 0) {
480 LOGP(DMGCP, LOGL_FATAL, "Failed to connect to local MGCP GW. %s\n", strerror(errno));
481 close(bsc->mgcp_agent.bfd.fd);
482 bsc->mgcp_agent.bfd.fd = -1;
483 return -1;
484 }
485
486 write_queue_init(&bsc->mgcp_agent, 10);
487 bsc->mgcp_agent.bfd.data = bsc;
488 bsc->mgcp_agent.bfd.when = BSC_FD_READ;
489 bsc->mgcp_agent.read_cb = mgcp_do_read;
490 bsc->mgcp_agent.write_cb = mgcp_do_write;
491
492 if (bsc_register_fd(&bsc->mgcp_agent.bfd) != 0) {
493 LOGP(DMGCP, LOGL_FATAL, "Failed to register BFD\n");
494 close(bsc->mgcp_agent.bfd.fd);
495 bsc->mgcp_agent.bfd.fd = -1;
496 return -1;
497 }
498
499 return 0;
500}
501
502int msc_init(struct bsc_data *bsc)
503{
504 write_queue_init(&bsc->msc_connection, 100);
505 bsc->reconnect_timer.cb = msc_reconnect;
506 bsc->reconnect_timer.data = bsc;
507 bsc->msc_connection.read_cb = ipaccess_a_fd_cb;
508 bsc->msc_connection.write_cb = ipaccess_write_cb;
509 bsc->msc_connection.bfd.data = bsc;
Holger Hans Peter Freyther0c95c6a2010-08-07 02:37:43 +0800510 bsc->msc_link_down = 1;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800511
512 /* handle the timeout */
513 bsc->ping_timeout.cb = msc_ping_timeout;
514 bsc->ping_timeout.data = bsc;
515 bsc->pong_timeout.cb = msc_pong_timeout;
516 bsc->pong_timeout.data = bsc;
517
518 /* create MGCP port */
519 if (mgcp_create_port(bsc) != 0)
520 return -1;
521 return 0;
522}
523
524static void msc_send(struct bsc_data *bsc, struct msgb *msg, int proto)
525{
526 ipaccess_prepend_header(msg, proto);
527
528 if (write_queue_enqueue(&bsc->msc_connection, msg) != 0) {
529 LOGP(DMSC, LOGL_FATAL, "Failed to queue MSG for the MSC.\n");
530 msgb_free(msg);
531 return;
532 }
533}
534
535void msc_send_rlc(struct bsc_data *bsc,
536 struct sccp_source_reference *src, struct sccp_source_reference *dst)
537{
538 struct msgb *msg;
539
540 msg = create_sccp_rlc(src, dst);
541 if (!msg)
542 return;
543
544 msc_send(bsc, msg, IPAC_PROTO_SCCP);
545}
546
547void msc_send_reset(struct bsc_data *bsc)
548{
549 struct msgb *msg;
550
551 msg = create_reset();
552 if (!msg)
553 return;
554
555 msc_send(bsc, msg, IPAC_PROTO_SCCP);
556 msc_ping_timeout(bsc);
557}
558
559static void msc_send_id_response(struct bsc_data *bsc)
560{
561 struct msgb *msg;
562
563 msg = msgb_alloc_headroom(4096, 128, "id resp");
564 msg->l2h = msgb_v_put(msg, IPAC_MSGT_ID_RESP);
565 msgb_l16tv_put(msg, strlen(bsc->token) + 1,
Holger Hans Peter Freyther5aa17012010-07-31 04:37:26 +0800566 IPAC_IDTAG_UNITNAME, (uint8_t *) bsc->token);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800567
568 msc_send(bsc, msg, IPAC_PROTO_IPACCESS);
569}
570
571void msc_send_msg(struct bsc_data *bsc, int rc, struct sccp_parse_result *result, struct msgb *_msg)
572{
573 struct msgb *msg;
574
575 if (bsc->msc_connection.bfd.fd < 0) {
576 LOGP(DMSC, LOGL_ERROR, "No connection to the MSC. dropping\n");
577 return;
578 }
579
580 msg = msgb_alloc_headroom(4096, 128, "SCCP to MSC");
581 if (!msg) {
582 LOGP(DMSC, LOGL_ERROR, "Failed to alloc MSC msg.\n");
583 return;
584 }
585
586 bss_rewrite_header_for_msc(rc, msg, _msg, result);
587 msc_send(bsc, msg, IPAC_PROTO_SCCP);
588}