blob: a384290078d0257547cba28aa56409b2b8c12696 [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 *
Holger Hans Peter Freytherde56c222011-01-16 17:45:14 +01007 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080010 * (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
Holger Hans Peter Freytherde56c222011-01-16 17:45:14 +010015 * GNU Affero General Public License for more details.
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080016 *
Holger Hans Peter Freytherde56c222011-01-16 17:45:14 +010017 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080019 *
20 */
21
Holger Hans Peter Freyther84ec8712011-02-15 20:01:47 +010022#include <msc_connection.h>
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080023#include <bsc_data.h>
Holger Hans Peter Freyther0f349f22010-10-06 04:39:08 +080024#include <bsc_ussd.h>
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080025#include <bss_patch.h>
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +010026#include <bsc_sccp.h>
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080027#include <bssap_sccp.h>
28#include <ipaccess.h>
29#include <mtp_data.h>
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +080030#include <cellmgr_debug.h>
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080031
Holger Hans Peter Freyther84ec8712011-02-15 20:01:47 +010032#include <osmocore/talloc.h>
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +080033#include <osmocore/tlv.h>
34#include <osmocore/utils.h>
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080035
36#include <arpa/inet.h>
37#include <sys/socket.h>
38#include <netinet/tcp.h>
39
40#include <fcntl.h>
41#include <unistd.h>
42#include <errno.h>
43#include <string.h>
44
45#define RECONNECT_TIME 10, 0
46#define NAT_MUX 0xfc
47
Holger Hans Peter Freyther84ec8712011-02-15 20:01:47 +010048static void msc_send_id_response(struct msc_connection *bsc);
49static void msc_send(struct msc_connection *bsc, struct msgb *msg, int proto);
50static void msc_schedule_reconnect(struct msc_connection *bsc);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080051
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +010052int send_or_queue_bsc_msg(struct mtp_link_set *link, int sls, struct msgb *msg)
Holger Hans Peter Freythera4ca6d32010-10-06 04:51:44 +080053{
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +010054 if (mtp_link_set_submit_sccp_data(link, sls, msg->l2h, msgb_l2len(msg)) != 0)
Holger Hans Peter Freythera4ca6d32010-10-06 04:51:44 +080055 LOGP(DMSC, LOGL_ERROR, "Could not forward SCCP message.\n");
56 return 0;
57}
58
Holger Hans Peter Freyther84ec8712011-02-15 20:01:47 +010059void msc_close_connection(struct msc_connection *fw)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080060{
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +010061 struct bsc_fd *bfd = &fw->msc_connection.bfd;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080062
63 close(bfd->fd);
64 bsc_unregister_fd(bfd);
65 bfd->fd = -1;
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +010066 fw->msc_link_down = 1;
67 release_bsc_resources(fw);
68 bsc_del_timer(&fw->ping_timeout);
69 bsc_del_timer(&fw->pong_timeout);
70 bsc_del_timer(&fw->msc_timeout);
71 msc_schedule_reconnect(fw);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080072}
73
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +010074static void msc_connect_timeout(void *_fw_data)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080075{
Holger Hans Peter Freyther84ec8712011-02-15 20:01:47 +010076 struct msc_connection *fw = _fw_data;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080077
78 LOGP(DMSC, LOGL_ERROR, "Timeout on the MSC connection.\n");
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +010079 msc_close_connection(fw);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080080}
81
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +010082static void msc_pong_timeout(void *_fw_data)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080083{
Holger Hans Peter Freyther84ec8712011-02-15 20:01:47 +010084 struct msc_connection *fw = _fw_data;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080085 LOGP(DMSC, LOGL_ERROR, "MSC didn't respond to ping. Closing.\n");
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +010086 msc_close_connection(fw);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080087}
88
Holger Hans Peter Freyther84ec8712011-02-15 20:01:47 +010089static void send_ping(struct msc_connection *fw)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080090{
91 struct msgb *msg;
92
93 msg = msgb_alloc_headroom(4096, 128, "ping");
94 if (!msg) {
95 LOGP(DMSC, LOGL_ERROR, "Failed to create PING.\n");
96 return;
97 }
98
99 msg->l2h = msgb_put(msg, 1);
100 msg->l2h[0] = IPAC_MSGT_PING;
101
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100102 msc_send(fw, msg, IPAC_PROTO_IPACCESS);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800103}
104
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100105static void msc_ping_timeout(void *_fw_data)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800106{
Holger Hans Peter Freyther84ec8712011-02-15 20:01:47 +0100107 struct msc_connection *fw = _fw_data;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800108
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100109 if (fw->ping_time < 0)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800110 return;
111
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100112 send_ping(fw);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800113
114 /* send another ping in 20 seconds */
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100115 bsc_schedule_timer(&fw->ping_timeout, fw->ping_time, 0);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800116
117 /* also start a pong timer */
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100118 bsc_schedule_timer(&fw->pong_timeout, fw->pong_time, 0);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800119}
120
121/*
122 * callback with IP access data
123 */
124static int ipaccess_a_fd_cb(struct bsc_fd *bfd)
125{
126 int error;
127 struct ipaccess_head *hh;
Holger Hans Peter Freyther84ec8712011-02-15 20:01:47 +0100128 struct msc_connection *fw;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800129 struct msgb *msg;
130
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100131 fw = bfd->data;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800132 msg = ipaccess_read_msg(bfd, &error);
133
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800134 if (!msg) {
135 if (error == 0)
136 fprintf(stderr, "The connection to the MSC was lost, exiting\n");
137 else
138 fprintf(stderr, "Error in the IPA stream.\n");
139
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100140 msc_close_connection(fw);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800141 return -1;
142 }
143
144 LOGP(DMSC, LOGL_DEBUG, "From MSC: %s proto: %d\n", hexdump(msg->data, msg->len), msg->l2h[0]);
145
146 /* handle base message handling */
147 hh = (struct ipaccess_head *) msg->data;
148 ipaccess_rcvmsg_base(msg, bfd);
149
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800150 /* initialize the networking. This includes sending a GSM08.08 message */
151 if (hh->proto == IPAC_PROTO_IPACCESS) {
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100152 if (fw->first_contact) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800153 LOGP(DMSC, LOGL_NOTICE, "Connected to MSC. Sending reset.\n");
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100154 bsc_del_timer(&fw->msc_timeout);
155 fw->first_contact = 0;
156 fw->msc_link_down = 0;
157 msc_send_reset(fw);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800158 }
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100159 if (msg->l2h[0] == IPAC_MSGT_ID_GET && fw->token) {
160 msc_send_id_response(fw);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800161 } else if (msg->l2h[0] == IPAC_MSGT_PONG) {
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100162 bsc_del_timer(&fw->pong_timeout);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800163 }
164 } else if (hh->proto == IPAC_PROTO_SCCP) {
Holger Hans Peter Freyther3d4d8c72011-02-15 21:14:09 +0100165 msc_dispatch_sccp(fw, msg);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800166 } else if (hh->proto == NAT_MUX) {
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100167 mgcp_forward(fw, msg->l2h, msgb_l2len(msg));
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800168 } else {
169 LOGP(DMSC, LOGL_ERROR, "Unknown IPA proto 0x%x\n", hh->proto);
170 }
171
172 msgb_free(msg);
173 return 0;
174}
175
176static int ipaccess_write_cb(struct bsc_fd *fd, struct msgb *msg)
177{
178 int rc;
179
180 LOGP(DMSC, LOGL_DEBUG, "Sending to MSC: %s\n", hexdump(msg->data, msg->len));
181 rc = write(fd->fd, msg->data, msg->len);
182 if (rc != msg->len)
183 LOGP(DMSC, LOGL_ERROR, "Could not write to MSC.\n");
184
185 return rc;
186}
187
188/* called in the case of a non blocking connect */
189static int msc_connection_connect(struct bsc_fd *fd, unsigned int what)
190{
191 int rc;
192 int val;
193 socklen_t len = sizeof(val);
Holger Hans Peter Freyther84ec8712011-02-15 20:01:47 +0100194 struct msc_connection *fw;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800195
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100196 fw = fd->data;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800197
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100198 if (fd != &fw->msc_connection.bfd) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800199 LOGP(DMSC, LOGL_ERROR, "This is only working with the MSC connection.\n");
200 return -1;
201 }
202
203 if ((what & BSC_FD_WRITE) == 0)
204 return -1;
205
206 /* check the socket state */
207 rc = getsockopt(fd->fd, SOL_SOCKET, SO_ERROR, &val, &len);
208 if (rc != 0) {
209 LOGP(DMSC, LOGL_ERROR, "getsockopt for the MSC socket failed.\n");
210 goto error;
211 }
212 if (val != 0) {
213 LOGP(DMSC, LOGL_ERROR, "Not connected to the MSC.\n");
214 goto error;
215 }
216
217
218 /* go to full operation */
219 fd->cb = write_queue_bfd_cb;
220 fd->when = BSC_FD_READ;
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100221 if (!llist_empty(&fw->msc_connection.msg_queue))
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800222 fd->when |= BSC_FD_WRITE;
223 return 0;
224
225error:
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100226 msc_close_connection(fw);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800227 return -1;
228}
229
Holger Hans Peter Freyther377ba422010-10-01 20:37:40 +0800230static int setnonblocking(struct bsc_fd *fd)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800231{
232 int flags;
233
234 flags = fcntl(fd->fd, F_GETFL);
235 if (flags < 0) {
236 perror("fcntl get failed");
237 close(fd->fd);
238 fd->fd = -1;
Holger Hans Peter Freyther377ba422010-10-01 20:37:40 +0800239 return -1;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800240 }
241
242 flags |= O_NONBLOCK;
243 flags = fcntl(fd->fd, F_SETFL, flags);
244 if (flags < 0) {
245 perror("fcntl get failed");
246 close(fd->fd);
247 fd->fd = -1;
Holger Hans Peter Freyther377ba422010-10-01 20:37:40 +0800248 return -1;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800249 }
Holger Hans Peter Freyther377ba422010-10-01 20:37:40 +0800250
251 return 0;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800252}
253
254static int connect_to_msc(struct bsc_fd *fd, const char *ip, int port, int tos)
255{
256 struct sockaddr_in sin;
257 int on = 1, ret;
258
259 LOGP(DMSC, LOGL_NOTICE, "Attempting to connect MSC at %s:%d\n", ip, port);
260
261 fd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
262
263 if (fd->fd < 0) {
264 perror("Creating TCP socket failed");
265 return fd->fd;
266 }
267
268 /* make it non blocking */
Holger Hans Peter Freyther377ba422010-10-01 20:37:40 +0800269 if (setnonblocking(fd) != 0)
270 return -1;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800271
272 memset(&sin, 0, sizeof(sin));
273 sin.sin_family = AF_INET;
274 sin.sin_port = htons(port);
275 inet_aton(ip, &sin.sin_addr);
276
277 setsockopt(fd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
278 ret = setsockopt(fd->fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
279 if (ret != 0)
280 LOGP(DMSC, LOGL_ERROR, "Failed to set TCP_NODELAY: %s\n", strerror(errno));
281 ret = setsockopt(fd->fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos));
282 if (ret != 0)
283 LOGP(DMSC, LOGL_ERROR, "Failed to set IP_TOS: %s\n", strerror(errno));
284
285 ret = connect(fd->fd, (struct sockaddr *) &sin, sizeof(sin));
286
287 if (ret == -1 && errno == EINPROGRESS) {
288 LOGP(DMSC, LOGL_ERROR, "MSC Connection in progress\n");
289 fd->when = BSC_FD_WRITE;
290 fd->cb = msc_connection_connect;
291 } else if (ret < 0) {
292 perror("Connection failed");
293 close(fd->fd);
294 fd->fd = -1;
295 return ret;
296 } else {
297 fd->when = BSC_FD_READ;
298 fd->cb = write_queue_bfd_cb;
299 }
300
301 ret = bsc_register_fd(fd);
302 if (ret < 0) {
303 perror("Registering the fd failed");
304 close(fd->fd);
305 fd->fd = -1;
306 return ret;
307 }
308
309 return ret;
310}
311
312static void msc_reconnect(void *_data)
313{
314 int rc;
Holger Hans Peter Freyther84ec8712011-02-15 20:01:47 +0100315 struct msc_connection *fw = _data;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800316
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100317 bsc_del_timer(&fw->reconnect_timer);
318 fw->first_contact = 1;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800319
Holger Hans Peter Freyther84ec8712011-02-15 20:01:47 +0100320 rc = connect_to_msc(&fw->msc_connection.bfd, fw->ip, 5000, fw->dscp);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800321 if (rc < 0) {
322 fprintf(stderr, "Opening the MSC connection failed. Trying again\n");
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100323 bsc_schedule_timer(&fw->reconnect_timer, RECONNECT_TIME);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800324 return;
325 }
326
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100327 fw->msc_timeout.cb = msc_connect_timeout;
328 fw->msc_timeout.data = fw;
329 bsc_schedule_timer(&fw->msc_timeout, fw->msc_time, 0);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800330}
331
Holger Hans Peter Freyther84ec8712011-02-15 20:01:47 +0100332static void msc_schedule_reconnect(struct msc_connection *fw)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800333{
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100334 bsc_schedule_timer(&fw->reconnect_timer, RECONNECT_TIME);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800335}
336
337/*
338 * mgcp forwarding is below
339 */
340static int mgcp_do_write(struct bsc_fd *fd, struct msgb *msg)
341{
342 int ret;
343
344 LOGP(DMGCP, LOGL_DEBUG, "Sending msg to MGCP GW size: %u\n", msg->len);
345
346 ret = write(fd->fd, msg->data, msg->len);
347 if (ret != msg->len)
348 LOGP(DMGCP, LOGL_ERROR, "Failed to forward message to MGCP GW (%s).\n", strerror(errno));
349
350 return ret;
351}
352
353static int mgcp_do_read(struct bsc_fd *fd)
354{
355 struct msgb *mgcp;
356 int ret;
357
358 mgcp = msgb_alloc_headroom(4096, 128, "mgcp_from_gw");
359 if (!mgcp) {
360 LOGP(DMGCP, LOGL_ERROR, "Failed to allocate MGCP message.\n");
361 return -1;
362 }
363
364 ret = read(fd->fd, mgcp->data, 4096 - 128);
365 if (ret <= 0) {
366 LOGP(DMGCP, LOGL_ERROR, "Failed to read: %d/%s\n", errno, strerror(errno));
367 msgb_free(mgcp);
368 return -1;
369 } else if (ret > 4096 - 128) {
370 LOGP(DMGCP, LOGL_ERROR, "Too much data: %d\n", ret);
371 msgb_free(mgcp);
372 return -1;
373 }
374
375 mgcp->l2h = msgb_put(mgcp, ret);
376 msc_send(fd->data, mgcp, NAT_MUX);
377 return 0;
378}
379
Holger Hans Peter Freyther84ec8712011-02-15 20:01:47 +0100380void mgcp_forward(struct msc_connection *fw, const uint8_t *data, unsigned int length)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800381{
382 struct msgb *mgcp;
383
384 if (length > 4096) {
385 LOGP(DMGCP, LOGL_ERROR, "Can not forward too big message.\n");
386 return;
387 }
388
389 mgcp = msgb_alloc(4096, "mgcp_to_gw");
390 if (!mgcp) {
391 LOGP(DMGCP, LOGL_ERROR, "Failed to send message.\n");
392 return;
393 }
394
395 msgb_put(mgcp, length);
396 memcpy(mgcp->data, data, mgcp->len);
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100397 if (write_queue_enqueue(&fw->mgcp_agent, mgcp) != 0) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800398 LOGP(DMGCP, LOGL_FATAL, "Could not queue message to MGCP GW.\n");
399 msgb_free(mgcp);
400 }
401}
402
Holger Hans Peter Freyther84ec8712011-02-15 20:01:47 +0100403static int mgcp_create_port(struct msc_connection *fw)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800404{
405 int on;
406 struct sockaddr_in addr;
407
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100408 fw->mgcp_agent.bfd.fd = socket(AF_INET, SOCK_DGRAM, 0);
409 if (fw->mgcp_agent.bfd.fd < 0) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800410 LOGP(DMGCP, LOGL_FATAL, "Failed to create UDP socket errno: %d\n", errno);
411 return -1;
412 }
413
414 on = 1;
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100415 setsockopt(fw->mgcp_agent.bfd.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800416
417 /* try to bind the socket */
418 memset(&addr, 0, sizeof(addr));
419 addr.sin_family = AF_INET;
420 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
421 addr.sin_port = 0;
422
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100423 if (bind(fw->mgcp_agent.bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800424 LOGP(DMGCP, LOGL_FATAL, "Failed to bind to any port.\n");
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100425 close(fw->mgcp_agent.bfd.fd);
426 fw->mgcp_agent.bfd.fd = -1;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800427 return -1;
428 }
429
430 /* connect to the remote */
431 addr.sin_port = htons(2427);
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100432 if (connect(fw->mgcp_agent.bfd.fd, (struct sockaddr *) & addr, sizeof(addr)) < 0) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800433 LOGP(DMGCP, LOGL_FATAL, "Failed to connect to local MGCP GW. %s\n", strerror(errno));
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100434 close(fw->mgcp_agent.bfd.fd);
435 fw->mgcp_agent.bfd.fd = -1;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800436 return -1;
437 }
438
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100439 write_queue_init(&fw->mgcp_agent, 10);
440 fw->mgcp_agent.bfd.data = fw;
441 fw->mgcp_agent.bfd.when = BSC_FD_READ;
442 fw->mgcp_agent.read_cb = mgcp_do_read;
443 fw->mgcp_agent.write_cb = mgcp_do_write;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800444
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100445 if (bsc_register_fd(&fw->mgcp_agent.bfd) != 0) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800446 LOGP(DMGCP, LOGL_FATAL, "Failed to register BFD\n");
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100447 close(fw->mgcp_agent.bfd.fd);
448 fw->mgcp_agent.bfd.fd = -1;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800449 return -1;
450 }
451
452 return 0;
453}
454
Holger Hans Peter Freyther84ec8712011-02-15 20:01:47 +0100455static void msc_send(struct msc_connection *fw, struct msgb *msg, int proto)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800456{
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100457 if (fw->msc_link_down) {
Holger Hans Peter Freyther7b7c2972010-08-07 05:41:06 +0800458 LOGP(DMSC, LOGL_NOTICE, "Dropping data due lack of MSC connection.\n");
459 msgb_free(msg);
460 return;
461 }
462
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800463 ipaccess_prepend_header(msg, proto);
464
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100465 if (write_queue_enqueue(&fw->msc_connection, msg) != 0) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800466 LOGP(DMSC, LOGL_FATAL, "Failed to queue MSG for the MSC.\n");
467 msgb_free(msg);
468 return;
469 }
470}
471
Holger Hans Peter Freyther84ec8712011-02-15 20:01:47 +0100472void msc_send_rlc(struct msc_connection *fw,
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800473 struct sccp_source_reference *src, struct sccp_source_reference *dst)
474{
475 struct msgb *msg;
476
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100477 if (fw->msc_link_down) {
Holger Hans Peter Freythere250ac32011-01-21 12:50:02 +0100478 LOGP(DMSC, LOGL_NOTICE, "Not releasing connection due lack of connection.\n");
479 return;
480 }
481
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800482 msg = create_sccp_rlc(src, dst);
483 if (!msg)
484 return;
485
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100486 msc_send(fw, msg, IPAC_PROTO_SCCP);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800487}
488
Holger Hans Peter Freyther84ec8712011-02-15 20:01:47 +0100489void msc_send_reset(struct msc_connection *fw)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800490{
491 struct msgb *msg;
492
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100493 if (fw->msc_link_down) {
Holger Hans Peter Freythere250ac32011-01-21 12:50:02 +0100494 LOGP(DMSC, LOGL_NOTICE, "Not sending reset due lack of connection.\n");
495 return;
496 }
497
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800498 msg = create_reset();
499 if (!msg)
500 return;
501
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100502 msc_send(fw, msg, IPAC_PROTO_SCCP);
503 msc_ping_timeout(fw);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800504}
505
Holger Hans Peter Freyther84ec8712011-02-15 20:01:47 +0100506static void msc_send_id_response(struct msc_connection *fw)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800507{
508 struct msgb *msg;
509
510 msg = msgb_alloc_headroom(4096, 128, "id resp");
511 msg->l2h = msgb_v_put(msg, IPAC_MSGT_ID_RESP);
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100512 msgb_l16tv_put(msg, strlen(fw->token) + 1,
513 IPAC_IDTAG_UNITNAME, (uint8_t *) fw->token);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800514
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100515 msc_send(fw, msg, IPAC_PROTO_IPACCESS);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800516}
517
Holger Hans Peter Freyther84ec8712011-02-15 20:01:47 +0100518void msc_send_direct(struct msc_connection *fw, struct msgb *msg)
Holger Hans Peter Freyther594ee9a2010-11-16 11:03:19 +0100519{
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100520 return msc_send(fw, msg, IPAC_PROTO_SCCP);
Holger Hans Peter Freyther594ee9a2010-11-16 11:03:19 +0100521}
522
Holger Hans Peter Freyther84ec8712011-02-15 20:01:47 +0100523void msc_send_msg(struct msc_connection *fw, int rc, struct sccp_parse_result *result, struct msgb *_msg)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800524{
525 struct msgb *msg;
526
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100527 if (fw->msc_connection.bfd.fd < 0) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800528 LOGP(DMSC, LOGL_ERROR, "No connection to the MSC. dropping\n");
529 return;
530 }
531
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100532 bsc_ussd_handle_out_msg(fw, result, _msg);
Holger Hans Peter Freyther0f349f22010-10-06 04:39:08 +0800533
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800534 msg = msgb_alloc_headroom(4096, 128, "SCCP to MSC");
535 if (!msg) {
536 LOGP(DMSC, LOGL_ERROR, "Failed to alloc MSC msg.\n");
537 return;
538 }
539
540 bss_rewrite_header_for_msc(rc, msg, _msg, result);
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100541 msc_send(fw, msg, IPAC_PROTO_SCCP);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800542}
Holger Hans Peter Freyther84ec8712011-02-15 20:01:47 +0100543
544struct msc_connection *msc_connection_create(struct bsc_data *bsc, int mgcp)
545{
546 struct msc_connection *msc;
547
548 msc = talloc_zero(NULL, struct msc_connection);
549 if (!msc) {
550 LOGP(DMSC, LOGL_ERROR, "Failed to allocate the MSC Connection.\n");
551 return NULL;
552 }
553
554 write_queue_init(&msc->msc_connection, 100);
555 msc->reconnect_timer.cb = msc_reconnect;
556 msc->reconnect_timer.data = msc;
557 msc->msc_connection.read_cb = ipaccess_a_fd_cb;
558 msc->msc_connection.write_cb = ipaccess_write_cb;
559 msc->msc_connection.bfd.data = msc;
560 msc->msc_link_down = 1;
561
562 /* handle the timeout */
563 msc->ping_timeout.cb = msc_ping_timeout;
564 msc->ping_timeout.data = msc;
565 msc->pong_timeout.cb = msc_pong_timeout;
566 msc->pong_timeout.data = msc;
567
568 /* create MGCP port */
569 if (mgcp && mgcp_create_port(msc) != 0) {
570 LOGP(DMSC, LOGL_ERROR, "Failed to bind for the MGCP port.\n");
571 talloc_free(msc);
572 return NULL;
573 }
574
575 INIT_LLIST_HEAD(&msc->sccp_connections);
576 llist_add(&msc->entry, &bsc->mscs);
577 msc->nr = bsc->num_mscs++;
578
579 return msc;
580}
581
582struct msc_connection *msc_connection_num(struct bsc_data *bsc, int num)
583{
584 struct msc_connection *msc;
585
586 llist_for_each_entry(msc, &bsc->mscs, entry)
587 if (msc->nr == num)
588 return msc;
589 return NULL;
590}
591
592int msc_connection_start(struct msc_connection *msc)
593{
594 if (msc->msc_connection.bfd.fd > 0) {
595 LOGP(DMSC, LOGL_ERROR,
596 "Function should not be called with active connection.\n");
597 return -1;
598 }
599
600 msc_schedule_reconnect(msc);
601 return 0;
602}