blob: e5023c6e58c4da89f02348f03d1e945772052986 [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 Freythere86c02e2011-02-10 15:32:14 +010024#include <bsc_sccp.h>
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080025#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 Freyther84ec8712011-02-15 20:01:47 +010030#include <osmocore/talloc.h>
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +080031#include <osmocore/tlv.h>
32#include <osmocore/utils.h>
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080033
34#include <arpa/inet.h>
35#include <sys/socket.h>
36#include <netinet/tcp.h>
37
38#include <fcntl.h>
39#include <unistd.h>
40#include <errno.h>
41#include <string.h>
42
43#define RECONNECT_TIME 10, 0
44#define NAT_MUX 0xfc
45
Holger Hans Peter Freyther84ec8712011-02-15 20:01:47 +010046static void msc_send_id_response(struct msc_connection *bsc);
47static void msc_send(struct msc_connection *bsc, struct msgb *msg, int proto);
48static void msc_schedule_reconnect(struct msc_connection *bsc);
Holger Hans Peter Freytherc5200fc2011-02-16 22:35:30 +010049static void mgcp_forward(struct msc_connection *fw, const uint8_t *data, unsigned int length);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080050
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +010051int send_or_queue_bsc_msg(struct mtp_link_set *link, int sls, struct msgb *msg)
Holger Hans Peter Freythera4ca6d32010-10-06 04:51:44 +080052{
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +010053 if (mtp_link_set_submit_sccp_data(link, sls, msg->l2h, msgb_l2len(msg)) != 0)
Holger Hans Peter Freythera4ca6d32010-10-06 04:51:44 +080054 LOGP(DMSC, LOGL_ERROR, "Could not forward SCCP message.\n");
55 return 0;
56}
57
Holger Hans Peter Freyther84ec8712011-02-15 20:01:47 +010058void msc_close_connection(struct msc_connection *fw)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080059{
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +010060 struct bsc_fd *bfd = &fw->msc_connection.bfd;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080061
62 close(bfd->fd);
63 bsc_unregister_fd(bfd);
64 bfd->fd = -1;
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +010065 fw->msc_link_down = 1;
66 release_bsc_resources(fw);
67 bsc_del_timer(&fw->ping_timeout);
68 bsc_del_timer(&fw->pong_timeout);
69 bsc_del_timer(&fw->msc_timeout);
70 msc_schedule_reconnect(fw);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080071}
72
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +010073static void msc_connect_timeout(void *_fw_data)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080074{
Holger Hans Peter Freyther84ec8712011-02-15 20:01:47 +010075 struct msc_connection *fw = _fw_data;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080076
77 LOGP(DMSC, LOGL_ERROR, "Timeout on the MSC connection.\n");
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +010078 msc_close_connection(fw);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080079}
80
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +010081static void msc_pong_timeout(void *_fw_data)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080082{
Holger Hans Peter Freyther84ec8712011-02-15 20:01:47 +010083 struct msc_connection *fw = _fw_data;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080084 LOGP(DMSC, LOGL_ERROR, "MSC didn't respond to ping. Closing.\n");
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +010085 msc_close_connection(fw);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080086}
87
Holger Hans Peter Freyther84ec8712011-02-15 20:01:47 +010088static void send_ping(struct msc_connection *fw)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080089{
90 struct msgb *msg;
91
92 msg = msgb_alloc_headroom(4096, 128, "ping");
93 if (!msg) {
94 LOGP(DMSC, LOGL_ERROR, "Failed to create PING.\n");
95 return;
96 }
97
98 msg->l2h = msgb_put(msg, 1);
99 msg->l2h[0] = IPAC_MSGT_PING;
100
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100101 msc_send(fw, msg, IPAC_PROTO_IPACCESS);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800102}
103
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100104static void msc_ping_timeout(void *_fw_data)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800105{
Holger Hans Peter Freyther84ec8712011-02-15 20:01:47 +0100106 struct msc_connection *fw = _fw_data;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800107
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100108 if (fw->ping_time < 0)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800109 return;
110
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100111 send_ping(fw);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800112
113 /* send another ping in 20 seconds */
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100114 bsc_schedule_timer(&fw->ping_timeout, fw->ping_time, 0);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800115
116 /* also start a pong timer */
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100117 bsc_schedule_timer(&fw->pong_timeout, fw->pong_time, 0);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800118}
119
120/*
121 * callback with IP access data
122 */
123static int ipaccess_a_fd_cb(struct bsc_fd *bfd)
124{
125 int error;
126 struct ipaccess_head *hh;
Holger Hans Peter Freyther84ec8712011-02-15 20:01:47 +0100127 struct msc_connection *fw;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800128 struct msgb *msg;
129
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100130 fw = bfd->data;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800131 msg = ipaccess_read_msg(bfd, &error);
132
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800133 if (!msg) {
134 if (error == 0)
135 fprintf(stderr, "The connection to the MSC was lost, exiting\n");
136 else
137 fprintf(stderr, "Error in the IPA stream.\n");
138
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100139 msc_close_connection(fw);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800140 return -1;
141 }
142
143 LOGP(DMSC, LOGL_DEBUG, "From MSC: %s proto: %d\n", hexdump(msg->data, msg->len), msg->l2h[0]);
144
145 /* handle base message handling */
146 hh = (struct ipaccess_head *) msg->data;
147 ipaccess_rcvmsg_base(msg, bfd);
148
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800149 /* initialize the networking. This includes sending a GSM08.08 message */
150 if (hh->proto == IPAC_PROTO_IPACCESS) {
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100151 if (fw->first_contact) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800152 LOGP(DMSC, LOGL_NOTICE, "Connected to MSC. Sending reset.\n");
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100153 bsc_del_timer(&fw->msc_timeout);
154 fw->first_contact = 0;
155 fw->msc_link_down = 0;
156 msc_send_reset(fw);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800157 }
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100158 if (msg->l2h[0] == IPAC_MSGT_ID_GET && fw->token) {
159 msc_send_id_response(fw);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800160 } else if (msg->l2h[0] == IPAC_MSGT_PONG) {
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100161 bsc_del_timer(&fw->pong_timeout);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800162 }
163 } else if (hh->proto == IPAC_PROTO_SCCP) {
Holger Hans Peter Freyther3d4d8c72011-02-15 21:14:09 +0100164 msc_dispatch_sccp(fw, msg);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800165 } else if (hh->proto == NAT_MUX) {
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100166 mgcp_forward(fw, msg->l2h, msgb_l2len(msg));
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800167 } else {
168 LOGP(DMSC, LOGL_ERROR, "Unknown IPA proto 0x%x\n", hh->proto);
169 }
170
171 msgb_free(msg);
172 return 0;
173}
174
175static int ipaccess_write_cb(struct bsc_fd *fd, struct msgb *msg)
176{
177 int rc;
178
179 LOGP(DMSC, LOGL_DEBUG, "Sending to MSC: %s\n", hexdump(msg->data, msg->len));
180 rc = write(fd->fd, msg->data, msg->len);
181 if (rc != msg->len)
182 LOGP(DMSC, LOGL_ERROR, "Could not write to MSC.\n");
183
184 return rc;
185}
186
187/* called in the case of a non blocking connect */
188static int msc_connection_connect(struct bsc_fd *fd, unsigned int what)
189{
190 int rc;
191 int val;
192 socklen_t len = sizeof(val);
Holger Hans Peter Freyther84ec8712011-02-15 20:01:47 +0100193 struct msc_connection *fw;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800194
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100195 fw = fd->data;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800196
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100197 if (fd != &fw->msc_connection.bfd) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800198 LOGP(DMSC, LOGL_ERROR, "This is only working with the MSC connection.\n");
199 return -1;
200 }
201
202 if ((what & BSC_FD_WRITE) == 0)
203 return -1;
204
205 /* check the socket state */
206 rc = getsockopt(fd->fd, SOL_SOCKET, SO_ERROR, &val, &len);
207 if (rc != 0) {
208 LOGP(DMSC, LOGL_ERROR, "getsockopt for the MSC socket failed.\n");
209 goto error;
210 }
211 if (val != 0) {
212 LOGP(DMSC, LOGL_ERROR, "Not connected to the MSC.\n");
213 goto error;
214 }
215
216
217 /* go to full operation */
218 fd->cb = write_queue_bfd_cb;
219 fd->when = BSC_FD_READ;
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100220 if (!llist_empty(&fw->msc_connection.msg_queue))
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800221 fd->when |= BSC_FD_WRITE;
222 return 0;
223
224error:
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100225 msc_close_connection(fw);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800226 return -1;
227}
228
Holger Hans Peter Freyther377ba422010-10-01 20:37:40 +0800229static int setnonblocking(struct bsc_fd *fd)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800230{
231 int flags;
232
233 flags = fcntl(fd->fd, F_GETFL);
234 if (flags < 0) {
235 perror("fcntl get failed");
236 close(fd->fd);
237 fd->fd = -1;
Holger Hans Peter Freyther377ba422010-10-01 20:37:40 +0800238 return -1;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800239 }
240
241 flags |= O_NONBLOCK;
242 flags = fcntl(fd->fd, F_SETFL, flags);
243 if (flags < 0) {
244 perror("fcntl get failed");
245 close(fd->fd);
246 fd->fd = -1;
Holger Hans Peter Freyther377ba422010-10-01 20:37:40 +0800247 return -1;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800248 }
Holger Hans Peter Freyther377ba422010-10-01 20:37:40 +0800249
250 return 0;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800251}
252
253static int connect_to_msc(struct bsc_fd *fd, const char *ip, int port, int tos)
254{
255 struct sockaddr_in sin;
256 int on = 1, ret;
257
258 LOGP(DMSC, LOGL_NOTICE, "Attempting to connect MSC at %s:%d\n", ip, port);
259
260 fd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
261
262 if (fd->fd < 0) {
263 perror("Creating TCP socket failed");
264 return fd->fd;
265 }
266
267 /* make it non blocking */
Holger Hans Peter Freyther377ba422010-10-01 20:37:40 +0800268 if (setnonblocking(fd) != 0)
269 return -1;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800270
271 memset(&sin, 0, sizeof(sin));
272 sin.sin_family = AF_INET;
273 sin.sin_port = htons(port);
274 inet_aton(ip, &sin.sin_addr);
275
276 setsockopt(fd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
277 ret = setsockopt(fd->fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
278 if (ret != 0)
279 LOGP(DMSC, LOGL_ERROR, "Failed to set TCP_NODELAY: %s\n", strerror(errno));
280 ret = setsockopt(fd->fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos));
281 if (ret != 0)
282 LOGP(DMSC, LOGL_ERROR, "Failed to set IP_TOS: %s\n", strerror(errno));
283
284 ret = connect(fd->fd, (struct sockaddr *) &sin, sizeof(sin));
285
286 if (ret == -1 && errno == EINPROGRESS) {
287 LOGP(DMSC, LOGL_ERROR, "MSC Connection in progress\n");
288 fd->when = BSC_FD_WRITE;
289 fd->cb = msc_connection_connect;
290 } else if (ret < 0) {
291 perror("Connection failed");
292 close(fd->fd);
293 fd->fd = -1;
294 return ret;
295 } else {
296 fd->when = BSC_FD_READ;
297 fd->cb = write_queue_bfd_cb;
298 }
299
300 ret = bsc_register_fd(fd);
301 if (ret < 0) {
302 perror("Registering the fd failed");
303 close(fd->fd);
304 fd->fd = -1;
305 return ret;
306 }
307
308 return ret;
309}
310
311static void msc_reconnect(void *_data)
312{
313 int rc;
Holger Hans Peter Freyther84ec8712011-02-15 20:01:47 +0100314 struct msc_connection *fw = _data;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800315
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100316 bsc_del_timer(&fw->reconnect_timer);
317 fw->first_contact = 1;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800318
Holger Hans Peter Freyther84ec8712011-02-15 20:01:47 +0100319 rc = connect_to_msc(&fw->msc_connection.bfd, fw->ip, 5000, fw->dscp);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800320 if (rc < 0) {
321 fprintf(stderr, "Opening the MSC connection failed. Trying again\n");
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100322 bsc_schedule_timer(&fw->reconnect_timer, RECONNECT_TIME);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800323 return;
324 }
325
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100326 fw->msc_timeout.cb = msc_connect_timeout;
327 fw->msc_timeout.data = fw;
328 bsc_schedule_timer(&fw->msc_timeout, fw->msc_time, 0);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800329}
330
Holger Hans Peter Freyther84ec8712011-02-15 20:01:47 +0100331static void msc_schedule_reconnect(struct msc_connection *fw)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800332{
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100333 bsc_schedule_timer(&fw->reconnect_timer, RECONNECT_TIME);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800334}
335
336/*
337 * mgcp forwarding is below
338 */
Holger Hans Peter Freytherc5200fc2011-02-16 22:35:30 +0100339/* send a RSIP to the MGCP GW */
340void msc_mgcp_reset(struct msc_connection *msc)
341{
342 static const char mgcp_reset[] = {
343 "RSIP 1 13@mgw MGCP 1.0\r\n"
344 };
345
346 mgcp_forward(msc, (const uint8_t *) mgcp_reset, strlen(mgcp_reset));
347}
348
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800349static int mgcp_do_write(struct bsc_fd *fd, struct msgb *msg)
350{
351 int ret;
352
353 LOGP(DMGCP, LOGL_DEBUG, "Sending msg to MGCP GW size: %u\n", msg->len);
354
355 ret = write(fd->fd, msg->data, msg->len);
356 if (ret != msg->len)
357 LOGP(DMGCP, LOGL_ERROR, "Failed to forward message to MGCP GW (%s).\n", strerror(errno));
358
359 return ret;
360}
361
362static int mgcp_do_read(struct bsc_fd *fd)
363{
364 struct msgb *mgcp;
365 int ret;
366
367 mgcp = msgb_alloc_headroom(4096, 128, "mgcp_from_gw");
368 if (!mgcp) {
369 LOGP(DMGCP, LOGL_ERROR, "Failed to allocate MGCP message.\n");
370 return -1;
371 }
372
373 ret = read(fd->fd, mgcp->data, 4096 - 128);
374 if (ret <= 0) {
375 LOGP(DMGCP, LOGL_ERROR, "Failed to read: %d/%s\n", errno, strerror(errno));
376 msgb_free(mgcp);
377 return -1;
378 } else if (ret > 4096 - 128) {
379 LOGP(DMGCP, LOGL_ERROR, "Too much data: %d\n", ret);
380 msgb_free(mgcp);
381 return -1;
382 }
383
384 mgcp->l2h = msgb_put(mgcp, ret);
385 msc_send(fd->data, mgcp, NAT_MUX);
386 return 0;
387}
388
Holger Hans Peter Freytherc5200fc2011-02-16 22:35:30 +0100389static void mgcp_forward(struct msc_connection *fw, const uint8_t *data, unsigned int length)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800390{
391 struct msgb *mgcp;
392
393 if (length > 4096) {
394 LOGP(DMGCP, LOGL_ERROR, "Can not forward too big message.\n");
395 return;
396 }
397
398 mgcp = msgb_alloc(4096, "mgcp_to_gw");
399 if (!mgcp) {
400 LOGP(DMGCP, LOGL_ERROR, "Failed to send message.\n");
401 return;
402 }
403
404 msgb_put(mgcp, length);
405 memcpy(mgcp->data, data, mgcp->len);
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100406 if (write_queue_enqueue(&fw->mgcp_agent, mgcp) != 0) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800407 LOGP(DMGCP, LOGL_FATAL, "Could not queue message to MGCP GW.\n");
408 msgb_free(mgcp);
409 }
410}
411
Holger Hans Peter Freyther84ec8712011-02-15 20:01:47 +0100412static int mgcp_create_port(struct msc_connection *fw)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800413{
414 int on;
415 struct sockaddr_in addr;
416
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100417 fw->mgcp_agent.bfd.fd = socket(AF_INET, SOCK_DGRAM, 0);
418 if (fw->mgcp_agent.bfd.fd < 0) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800419 LOGP(DMGCP, LOGL_FATAL, "Failed to create UDP socket errno: %d\n", errno);
420 return -1;
421 }
422
423 on = 1;
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100424 setsockopt(fw->mgcp_agent.bfd.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800425
426 /* try to bind the socket */
427 memset(&addr, 0, sizeof(addr));
428 addr.sin_family = AF_INET;
429 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
430 addr.sin_port = 0;
431
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100432 if (bind(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 bind to any port.\n");
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
439 /* connect to the remote */
440 addr.sin_port = htons(2427);
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100441 if (connect(fw->mgcp_agent.bfd.fd, (struct sockaddr *) & addr, sizeof(addr)) < 0) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800442 LOGP(DMGCP, LOGL_FATAL, "Failed to connect to local MGCP GW. %s\n", strerror(errno));
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100443 close(fw->mgcp_agent.bfd.fd);
444 fw->mgcp_agent.bfd.fd = -1;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800445 return -1;
446 }
447
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100448 write_queue_init(&fw->mgcp_agent, 10);
449 fw->mgcp_agent.bfd.data = fw;
450 fw->mgcp_agent.bfd.when = BSC_FD_READ;
451 fw->mgcp_agent.read_cb = mgcp_do_read;
452 fw->mgcp_agent.write_cb = mgcp_do_write;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800453
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100454 if (bsc_register_fd(&fw->mgcp_agent.bfd) != 0) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800455 LOGP(DMGCP, LOGL_FATAL, "Failed to register BFD\n");
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100456 close(fw->mgcp_agent.bfd.fd);
457 fw->mgcp_agent.bfd.fd = -1;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800458 return -1;
459 }
460
461 return 0;
462}
463
Holger Hans Peter Freyther84ec8712011-02-15 20:01:47 +0100464static void msc_send(struct msc_connection *fw, struct msgb *msg, int proto)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800465{
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100466 if (fw->msc_link_down) {
Holger Hans Peter Freyther7b7c2972010-08-07 05:41:06 +0800467 LOGP(DMSC, LOGL_NOTICE, "Dropping data due lack of MSC connection.\n");
468 msgb_free(msg);
469 return;
470 }
471
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800472 ipaccess_prepend_header(msg, proto);
473
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100474 if (write_queue_enqueue(&fw->msc_connection, msg) != 0) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800475 LOGP(DMSC, LOGL_FATAL, "Failed to queue MSG for the MSC.\n");
476 msgb_free(msg);
477 return;
478 }
479}
480
Holger Hans Peter Freyther84ec8712011-02-15 20:01:47 +0100481void msc_send_rlc(struct msc_connection *fw,
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800482 struct sccp_source_reference *src, struct sccp_source_reference *dst)
483{
484 struct msgb *msg;
485
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100486 if (fw->msc_link_down) {
Holger Hans Peter Freythere250ac32011-01-21 12:50:02 +0100487 LOGP(DMSC, LOGL_NOTICE, "Not releasing connection due lack of connection.\n");
488 return;
489 }
490
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800491 msg = create_sccp_rlc(src, dst);
492 if (!msg)
493 return;
494
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100495 msc_send(fw, msg, IPAC_PROTO_SCCP);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800496}
497
Holger Hans Peter Freyther84ec8712011-02-15 20:01:47 +0100498void msc_send_reset(struct msc_connection *fw)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800499{
500 struct msgb *msg;
501
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100502 if (fw->msc_link_down) {
Holger Hans Peter Freythere250ac32011-01-21 12:50:02 +0100503 LOGP(DMSC, LOGL_NOTICE, "Not sending reset due lack of connection.\n");
504 return;
505 }
506
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800507 msg = create_reset();
508 if (!msg)
509 return;
510
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100511 msc_send(fw, msg, IPAC_PROTO_SCCP);
512 msc_ping_timeout(fw);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800513}
514
Holger Hans Peter Freyther84ec8712011-02-15 20:01:47 +0100515static void msc_send_id_response(struct msc_connection *fw)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800516{
517 struct msgb *msg;
518
519 msg = msgb_alloc_headroom(4096, 128, "id resp");
520 msg->l2h = msgb_v_put(msg, IPAC_MSGT_ID_RESP);
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100521 msgb_l16tv_put(msg, strlen(fw->token) + 1,
522 IPAC_IDTAG_UNITNAME, (uint8_t *) fw->token);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800523
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100524 msc_send(fw, msg, IPAC_PROTO_IPACCESS);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800525}
526
Holger Hans Peter Freyther84ec8712011-02-15 20:01:47 +0100527void msc_send_direct(struct msc_connection *fw, struct msgb *msg)
Holger Hans Peter Freyther594ee9a2010-11-16 11:03:19 +0100528{
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100529 return msc_send(fw, msg, IPAC_PROTO_SCCP);
Holger Hans Peter Freyther594ee9a2010-11-16 11:03:19 +0100530}
531
Holger Hans Peter Freyther84ec8712011-02-15 20:01:47 +0100532struct msc_connection *msc_connection_create(struct bsc_data *bsc, int mgcp)
533{
534 struct msc_connection *msc;
535
536 msc = talloc_zero(NULL, struct msc_connection);
537 if (!msc) {
538 LOGP(DMSC, LOGL_ERROR, "Failed to allocate the MSC Connection.\n");
539 return NULL;
540 }
541
542 write_queue_init(&msc->msc_connection, 100);
543 msc->reconnect_timer.cb = msc_reconnect;
544 msc->reconnect_timer.data = msc;
545 msc->msc_connection.read_cb = ipaccess_a_fd_cb;
546 msc->msc_connection.write_cb = ipaccess_write_cb;
547 msc->msc_connection.bfd.data = msc;
548 msc->msc_link_down = 1;
549
550 /* handle the timeout */
551 msc->ping_timeout.cb = msc_ping_timeout;
552 msc->ping_timeout.data = msc;
553 msc->pong_timeout.cb = msc_pong_timeout;
554 msc->pong_timeout.data = msc;
555
556 /* create MGCP port */
557 if (mgcp && mgcp_create_port(msc) != 0) {
558 LOGP(DMSC, LOGL_ERROR, "Failed to bind for the MGCP port.\n");
559 talloc_free(msc);
560 return NULL;
561 }
562
Holger Hans Peter Freyther84ec8712011-02-15 20:01:47 +0100563 llist_add(&msc->entry, &bsc->mscs);
564 msc->nr = bsc->num_mscs++;
565
566 return msc;
567}
568
569struct msc_connection *msc_connection_num(struct bsc_data *bsc, int num)
570{
571 struct msc_connection *msc;
572
573 llist_for_each_entry(msc, &bsc->mscs, entry)
574 if (msc->nr == num)
575 return msc;
576 return NULL;
577}
578
579int msc_connection_start(struct msc_connection *msc)
580{
581 if (msc->msc_connection.bfd.fd > 0) {
582 LOGP(DMSC, LOGL_ERROR,
583 "Function should not be called with active connection.\n");
584 return -1;
585 }
586
587 msc_schedule_reconnect(msc);
588 return 0;
589}