blob: e43a304d05cd1a5a8e6b0bd56e63384a134f73e1 [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
22#include <bsc_data.h>
Holger Hans Peter Freyther0f349f22010-10-06 04:39:08 +080023#include <bsc_ussd.h>
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080024#include <bss_patch.h>
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +010025#include <bsc_sccp.h>
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080026#include <bssap_sccp.h>
27#include <ipaccess.h>
28#include <mtp_data.h>
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +080029#include <cellmgr_debug.h>
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080030
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 Freythere86c02e2011-02-10 15:32:14 +010046static void msc_send_id_response(struct bsc_msc_forward *bsc);
47static void msc_send(struct bsc_msc_forward *bsc, struct msgb *msg, int proto);
48static void msc_schedule_reconnect(struct bsc_msc_forward *bsc);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080049
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +010050int send_or_queue_bsc_msg(struct mtp_link_set *link, int sls, struct msgb *msg)
Holger Hans Peter Freythera4ca6d32010-10-06 04:51:44 +080051{
Holger Hans Peter Freyther569f1e12011-01-02 18:47:49 +010052 if (mtp_link_set_submit_sccp_data(link, sls, msg->l2h, msgb_l2len(msg)) != 0)
Holger Hans Peter Freythera4ca6d32010-10-06 04:51:44 +080053 LOGP(DMSC, LOGL_ERROR, "Could not forward SCCP message.\n");
54 return 0;
55}
56
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +010057void msc_close_connection(struct bsc_msc_forward *fw)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080058{
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +010059 struct bsc_fd *bfd = &fw->msc_connection.bfd;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080060
61 close(bfd->fd);
62 bsc_unregister_fd(bfd);
63 bfd->fd = -1;
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +010064 fw->msc_link_down = 1;
65 release_bsc_resources(fw);
66 bsc_del_timer(&fw->ping_timeout);
67 bsc_del_timer(&fw->pong_timeout);
68 bsc_del_timer(&fw->msc_timeout);
69 msc_schedule_reconnect(fw);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080070}
71
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +010072static void msc_connect_timeout(void *_fw_data)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080073{
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +010074 struct bsc_msc_forward *fw = _fw_data;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080075
76 LOGP(DMSC, LOGL_ERROR, "Timeout on the MSC connection.\n");
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +010077 msc_close_connection(fw);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080078}
79
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +010080static void msc_pong_timeout(void *_fw_data)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080081{
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +010082 struct bsc_msc_forward *fw = _fw_data;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080083 LOGP(DMSC, LOGL_ERROR, "MSC didn't respond to ping. Closing.\n");
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +010084 msc_close_connection(fw);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080085}
86
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +010087static void send_ping(struct bsc_msc_forward *fw)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080088{
89 struct msgb *msg;
90
91 msg = msgb_alloc_headroom(4096, 128, "ping");
92 if (!msg) {
93 LOGP(DMSC, LOGL_ERROR, "Failed to create PING.\n");
94 return;
95 }
96
97 msg->l2h = msgb_put(msg, 1);
98 msg->l2h[0] = IPAC_MSGT_PING;
99
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100100 msc_send(fw, msg, IPAC_PROTO_IPACCESS);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800101}
102
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100103static void msc_ping_timeout(void *_fw_data)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800104{
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100105 struct bsc_msc_forward *fw = _fw_data;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800106
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100107 if (fw->ping_time < 0)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800108 return;
109
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100110 send_ping(fw);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800111
112 /* send another ping in 20 seconds */
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100113 bsc_schedule_timer(&fw->ping_timeout, fw->ping_time, 0);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800114
115 /* also start a pong timer */
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100116 bsc_schedule_timer(&fw->pong_timeout, fw->pong_time, 0);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800117}
118
119/*
120 * callback with IP access data
121 */
122static int ipaccess_a_fd_cb(struct bsc_fd *bfd)
123{
124 int error;
125 struct ipaccess_head *hh;
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100126 struct bsc_msc_forward *fw;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800127 struct msgb *msg;
128
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100129 fw = bfd->data;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800130 msg = ipaccess_read_msg(bfd, &error);
131
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800132 if (!msg) {
133 if (error == 0)
134 fprintf(stderr, "The connection to the MSC was lost, exiting\n");
135 else
136 fprintf(stderr, "Error in the IPA stream.\n");
137
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100138 msc_close_connection(fw);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800139 return -1;
140 }
141
142 LOGP(DMSC, LOGL_DEBUG, "From MSC: %s proto: %d\n", hexdump(msg->data, msg->len), msg->l2h[0]);
143
144 /* handle base message handling */
145 hh = (struct ipaccess_head *) msg->data;
146 ipaccess_rcvmsg_base(msg, bfd);
147
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800148 /* initialize the networking. This includes sending a GSM08.08 message */
149 if (hh->proto == IPAC_PROTO_IPACCESS) {
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100150 if (fw->first_contact) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800151 LOGP(DMSC, LOGL_NOTICE, "Connected to MSC. Sending reset.\n");
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100152 bsc_del_timer(&fw->msc_timeout);
153 fw->first_contact = 0;
154 fw->msc_link_down = 0;
155 msc_send_reset(fw);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800156 }
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100157 if (msg->l2h[0] == IPAC_MSGT_ID_GET && fw->token) {
158 msc_send_id_response(fw);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800159 } else if (msg->l2h[0] == IPAC_MSGT_PONG) {
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100160 bsc_del_timer(&fw->pong_timeout);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800161 }
162 } else if (hh->proto == IPAC_PROTO_SCCP) {
163 struct sccp_parse_result result;
164 int rc;
Holger Hans Peter Freyther76943812010-11-16 11:14:34 +0100165
166 /* we can not forward it right now */
Holger Hans Peter Freythercea45182011-02-10 20:03:52 +0100167 if (fw->forward_only) {
168 if (fw->bsc->sccp_up && send_or_queue_bsc_msg(fw->bsc, -1, msg) == 1)
169 return 0;
170
171 msgb_free(msg);
Holger Hans Peter Freyther76943812010-11-16 11:14:34 +0100172 return 0;
173 }
174
175
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800176 rc = bss_patch_filter_msg(msg, &result);
177
178 if (rc == BSS_FILTER_RESET_ACK) {
179 LOGP(DMSC, LOGL_NOTICE, "Filtering reset ack from the MSC\n");
180 } else if (rc == BSS_FILTER_RLSD) {
181 LOGP(DMSC, LOGL_DEBUG, "Filtering RLSD from the MSC\n");
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100182 update_con_state(fw, rc, &result, msg, 1, 0);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800183 } else if (rc == BSS_FILTER_RLC) {
184 /* if we receive this we have forwarded a RLSD to the network */
185 LOGP(DMSC, LOGL_ERROR, "RLC from the network. BAD!\n");
186 } else if (rc == BSS_FILTER_CLEAR_COMPL) {
187 LOGP(DMSC, LOGL_ERROR, "Clear Complete from the network.\n");
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100188 } else if (fw->bsc->sccp_up) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800189 unsigned int sls;
190
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100191 update_con_state(fw, rc, &result, msg, 1, 0);
192 sls = sls_for_src_ref(fw, result.destination_local_reference);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800193
Holger Hans Peter Freyther0f349f22010-10-06 04:39:08 +0800194 /* Check for Location Update Accept */
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100195 bsc_ussd_handle_in_msg(fw, &result, msg);
Holger Hans Peter Freyther0f349f22010-10-06 04:39:08 +0800196
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800197 /* patch a possible PC */
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100198 bss_rewrite_header_to_bsc(msg, fw->bsc->opc, fw->bsc->dpc);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800199
200 /* we can not forward it right now */
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100201 if (send_or_queue_bsc_msg(fw->bsc, sls, msg) == 1)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800202 return 0;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800203
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800204 }
205 } else if (hh->proto == NAT_MUX) {
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100206 mgcp_forward(fw, msg->l2h, msgb_l2len(msg));
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800207 } else {
208 LOGP(DMSC, LOGL_ERROR, "Unknown IPA proto 0x%x\n", hh->proto);
209 }
210
211 msgb_free(msg);
212 return 0;
213}
214
215static int ipaccess_write_cb(struct bsc_fd *fd, struct msgb *msg)
216{
217 int rc;
218
219 LOGP(DMSC, LOGL_DEBUG, "Sending to MSC: %s\n", hexdump(msg->data, msg->len));
220 rc = write(fd->fd, msg->data, msg->len);
221 if (rc != msg->len)
222 LOGP(DMSC, LOGL_ERROR, "Could not write to MSC.\n");
223
224 return rc;
225}
226
227/* called in the case of a non blocking connect */
228static int msc_connection_connect(struct bsc_fd *fd, unsigned int what)
229{
230 int rc;
231 int val;
232 socklen_t len = sizeof(val);
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100233 struct bsc_msc_forward *fw;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800234
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100235 fw = fd->data;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800236
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100237 if (fd != &fw->msc_connection.bfd) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800238 LOGP(DMSC, LOGL_ERROR, "This is only working with the MSC connection.\n");
239 return -1;
240 }
241
242 if ((what & BSC_FD_WRITE) == 0)
243 return -1;
244
245 /* check the socket state */
246 rc = getsockopt(fd->fd, SOL_SOCKET, SO_ERROR, &val, &len);
247 if (rc != 0) {
248 LOGP(DMSC, LOGL_ERROR, "getsockopt for the MSC socket failed.\n");
249 goto error;
250 }
251 if (val != 0) {
252 LOGP(DMSC, LOGL_ERROR, "Not connected to the MSC.\n");
253 goto error;
254 }
255
256
257 /* go to full operation */
258 fd->cb = write_queue_bfd_cb;
259 fd->when = BSC_FD_READ;
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100260 if (!llist_empty(&fw->msc_connection.msg_queue))
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800261 fd->when |= BSC_FD_WRITE;
262 return 0;
263
264error:
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100265 msc_close_connection(fw);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800266 return -1;
267}
268
Holger Hans Peter Freyther377ba422010-10-01 20:37:40 +0800269static int setnonblocking(struct bsc_fd *fd)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800270{
271 int flags;
272
273 flags = fcntl(fd->fd, F_GETFL);
274 if (flags < 0) {
275 perror("fcntl get failed");
276 close(fd->fd);
277 fd->fd = -1;
Holger Hans Peter Freyther377ba422010-10-01 20:37:40 +0800278 return -1;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800279 }
280
281 flags |= O_NONBLOCK;
282 flags = fcntl(fd->fd, F_SETFL, flags);
283 if (flags < 0) {
284 perror("fcntl get failed");
285 close(fd->fd);
286 fd->fd = -1;
Holger Hans Peter Freyther377ba422010-10-01 20:37:40 +0800287 return -1;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800288 }
Holger Hans Peter Freyther377ba422010-10-01 20:37:40 +0800289
290 return 0;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800291}
292
293static int connect_to_msc(struct bsc_fd *fd, const char *ip, int port, int tos)
294{
295 struct sockaddr_in sin;
296 int on = 1, ret;
297
298 LOGP(DMSC, LOGL_NOTICE, "Attempting to connect MSC at %s:%d\n", ip, port);
299
300 fd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
301
302 if (fd->fd < 0) {
303 perror("Creating TCP socket failed");
304 return fd->fd;
305 }
306
307 /* make it non blocking */
Holger Hans Peter Freyther377ba422010-10-01 20:37:40 +0800308 if (setnonblocking(fd) != 0)
309 return -1;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800310
311 memset(&sin, 0, sizeof(sin));
312 sin.sin_family = AF_INET;
313 sin.sin_port = htons(port);
314 inet_aton(ip, &sin.sin_addr);
315
316 setsockopt(fd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
317 ret = setsockopt(fd->fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
318 if (ret != 0)
319 LOGP(DMSC, LOGL_ERROR, "Failed to set TCP_NODELAY: %s\n", strerror(errno));
320 ret = setsockopt(fd->fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos));
321 if (ret != 0)
322 LOGP(DMSC, LOGL_ERROR, "Failed to set IP_TOS: %s\n", strerror(errno));
323
324 ret = connect(fd->fd, (struct sockaddr *) &sin, sizeof(sin));
325
326 if (ret == -1 && errno == EINPROGRESS) {
327 LOGP(DMSC, LOGL_ERROR, "MSC Connection in progress\n");
328 fd->when = BSC_FD_WRITE;
329 fd->cb = msc_connection_connect;
330 } else if (ret < 0) {
331 perror("Connection failed");
332 close(fd->fd);
333 fd->fd = -1;
334 return ret;
335 } else {
336 fd->when = BSC_FD_READ;
337 fd->cb = write_queue_bfd_cb;
338 }
339
340 ret = bsc_register_fd(fd);
341 if (ret < 0) {
342 perror("Registering the fd failed");
343 close(fd->fd);
344 fd->fd = -1;
345 return ret;
346 }
347
348 return ret;
349}
350
351static void msc_reconnect(void *_data)
352{
353 int rc;
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100354 struct bsc_msc_forward *fw = _data;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800355
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100356 bsc_del_timer(&fw->reconnect_timer);
357 fw->first_contact = 1;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800358
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100359 rc = connect_to_msc(&fw->msc_connection.bfd, fw->msc_address, 5000, fw->msc_ip_dscp);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800360 if (rc < 0) {
361 fprintf(stderr, "Opening the MSC connection failed. Trying again\n");
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100362 bsc_schedule_timer(&fw->reconnect_timer, RECONNECT_TIME);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800363 return;
364 }
365
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100366 fw->msc_timeout.cb = msc_connect_timeout;
367 fw->msc_timeout.data = fw;
368 bsc_schedule_timer(&fw->msc_timeout, fw->msc_time, 0);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800369}
370
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100371static void msc_schedule_reconnect(struct bsc_msc_forward *fw)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800372{
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100373 bsc_schedule_timer(&fw->reconnect_timer, RECONNECT_TIME);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800374}
375
376/*
377 * mgcp forwarding is below
378 */
379static int mgcp_do_write(struct bsc_fd *fd, struct msgb *msg)
380{
381 int ret;
382
383 LOGP(DMGCP, LOGL_DEBUG, "Sending msg to MGCP GW size: %u\n", msg->len);
384
385 ret = write(fd->fd, msg->data, msg->len);
386 if (ret != msg->len)
387 LOGP(DMGCP, LOGL_ERROR, "Failed to forward message to MGCP GW (%s).\n", strerror(errno));
388
389 return ret;
390}
391
392static int mgcp_do_read(struct bsc_fd *fd)
393{
394 struct msgb *mgcp;
395 int ret;
396
397 mgcp = msgb_alloc_headroom(4096, 128, "mgcp_from_gw");
398 if (!mgcp) {
399 LOGP(DMGCP, LOGL_ERROR, "Failed to allocate MGCP message.\n");
400 return -1;
401 }
402
403 ret = read(fd->fd, mgcp->data, 4096 - 128);
404 if (ret <= 0) {
405 LOGP(DMGCP, LOGL_ERROR, "Failed to read: %d/%s\n", errno, strerror(errno));
406 msgb_free(mgcp);
407 return -1;
408 } else if (ret > 4096 - 128) {
409 LOGP(DMGCP, LOGL_ERROR, "Too much data: %d\n", ret);
410 msgb_free(mgcp);
411 return -1;
412 }
413
414 mgcp->l2h = msgb_put(mgcp, ret);
415 msc_send(fd->data, mgcp, NAT_MUX);
416 return 0;
417}
418
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100419void mgcp_forward(struct bsc_msc_forward *fw, const uint8_t *data, unsigned int length)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800420{
421 struct msgb *mgcp;
422
423 if (length > 4096) {
424 LOGP(DMGCP, LOGL_ERROR, "Can not forward too big message.\n");
425 return;
426 }
427
428 mgcp = msgb_alloc(4096, "mgcp_to_gw");
429 if (!mgcp) {
430 LOGP(DMGCP, LOGL_ERROR, "Failed to send message.\n");
431 return;
432 }
433
434 msgb_put(mgcp, length);
435 memcpy(mgcp->data, data, mgcp->len);
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100436 if (write_queue_enqueue(&fw->mgcp_agent, mgcp) != 0) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800437 LOGP(DMGCP, LOGL_FATAL, "Could not queue message to MGCP GW.\n");
438 msgb_free(mgcp);
439 }
440}
441
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100442static int mgcp_create_port(struct bsc_msc_forward *fw)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800443{
444 int on;
445 struct sockaddr_in addr;
446
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100447 fw->mgcp_agent.bfd.fd = socket(AF_INET, SOCK_DGRAM, 0);
448 if (fw->mgcp_agent.bfd.fd < 0) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800449 LOGP(DMGCP, LOGL_FATAL, "Failed to create UDP socket errno: %d\n", errno);
450 return -1;
451 }
452
453 on = 1;
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100454 setsockopt(fw->mgcp_agent.bfd.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800455
456 /* try to bind the socket */
457 memset(&addr, 0, sizeof(addr));
458 addr.sin_family = AF_INET;
459 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
460 addr.sin_port = 0;
461
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100462 if (bind(fw->mgcp_agent.bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800463 LOGP(DMGCP, LOGL_FATAL, "Failed to bind to any port.\n");
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100464 close(fw->mgcp_agent.bfd.fd);
465 fw->mgcp_agent.bfd.fd = -1;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800466 return -1;
467 }
468
469 /* connect to the remote */
470 addr.sin_port = htons(2427);
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100471 if (connect(fw->mgcp_agent.bfd.fd, (struct sockaddr *) & addr, sizeof(addr)) < 0) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800472 LOGP(DMGCP, LOGL_FATAL, "Failed to connect to local MGCP GW. %s\n", strerror(errno));
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100473 close(fw->mgcp_agent.bfd.fd);
474 fw->mgcp_agent.bfd.fd = -1;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800475 return -1;
476 }
477
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100478 write_queue_init(&fw->mgcp_agent, 10);
479 fw->mgcp_agent.bfd.data = fw;
480 fw->mgcp_agent.bfd.when = BSC_FD_READ;
481 fw->mgcp_agent.read_cb = mgcp_do_read;
482 fw->mgcp_agent.write_cb = mgcp_do_write;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800483
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100484 if (bsc_register_fd(&fw->mgcp_agent.bfd) != 0) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800485 LOGP(DMGCP, LOGL_FATAL, "Failed to register BFD\n");
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100486 close(fw->mgcp_agent.bfd.fd);
487 fw->mgcp_agent.bfd.fd = -1;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800488 return -1;
489 }
490
491 return 0;
492}
493
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100494int msc_init(struct bsc_msc_forward *fw, int mgcp)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800495{
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100496 write_queue_init(&fw->msc_connection, 100);
497 fw->reconnect_timer.cb = msc_reconnect;
498 fw->reconnect_timer.data = fw;
499 fw->msc_connection.read_cb = ipaccess_a_fd_cb;
500 fw->msc_connection.write_cb = ipaccess_write_cb;
501 fw->msc_connection.bfd.data = fw;
502 fw->msc_link_down = 1;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800503
504 /* handle the timeout */
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100505 fw->ping_timeout.cb = msc_ping_timeout;
506 fw->ping_timeout.data = fw;
507 fw->pong_timeout.cb = msc_pong_timeout;
508 fw->pong_timeout.data = fw;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800509
510 /* create MGCP port */
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100511 if (mgcp && mgcp_create_port(fw) != 0)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800512 return -1;
Holger Hans Peter Freyther7b7c2972010-08-07 05:41:06 +0800513
514 /* now connect to the BSC */
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100515 msc_schedule_reconnect(fw);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800516 return 0;
517}
518
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100519static void msc_send(struct bsc_msc_forward *fw, struct msgb *msg, int proto)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800520{
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100521 if (fw->msc_link_down) {
Holger Hans Peter Freyther7b7c2972010-08-07 05:41:06 +0800522 LOGP(DMSC, LOGL_NOTICE, "Dropping data due lack of MSC connection.\n");
523 msgb_free(msg);
524 return;
525 }
526
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800527 ipaccess_prepend_header(msg, proto);
528
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100529 if (write_queue_enqueue(&fw->msc_connection, msg) != 0) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800530 LOGP(DMSC, LOGL_FATAL, "Failed to queue MSG for the MSC.\n");
531 msgb_free(msg);
532 return;
533 }
534}
535
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100536void msc_send_rlc(struct bsc_msc_forward *fw,
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800537 struct sccp_source_reference *src, struct sccp_source_reference *dst)
538{
539 struct msgb *msg;
540
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100541 if (fw->msc_link_down) {
Holger Hans Peter Freythere250ac32011-01-21 12:50:02 +0100542 LOGP(DMSC, LOGL_NOTICE, "Not releasing connection due lack of connection.\n");
543 return;
544 }
545
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800546 msg = create_sccp_rlc(src, dst);
547 if (!msg)
548 return;
549
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100550 msc_send(fw, msg, IPAC_PROTO_SCCP);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800551}
552
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100553void msc_send_reset(struct bsc_msc_forward *fw)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800554{
555 struct msgb *msg;
556
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100557 if (fw->msc_link_down) {
Holger Hans Peter Freythere250ac32011-01-21 12:50:02 +0100558 LOGP(DMSC, LOGL_NOTICE, "Not sending reset due lack of connection.\n");
559 return;
560 }
561
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800562 msg = create_reset();
563 if (!msg)
564 return;
565
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100566 msc_send(fw, msg, IPAC_PROTO_SCCP);
567 msc_ping_timeout(fw);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800568}
569
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100570static void msc_send_id_response(struct bsc_msc_forward *fw)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800571{
572 struct msgb *msg;
573
574 msg = msgb_alloc_headroom(4096, 128, "id resp");
575 msg->l2h = msgb_v_put(msg, IPAC_MSGT_ID_RESP);
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100576 msgb_l16tv_put(msg, strlen(fw->token) + 1,
577 IPAC_IDTAG_UNITNAME, (uint8_t *) fw->token);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800578
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100579 msc_send(fw, msg, IPAC_PROTO_IPACCESS);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800580}
581
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100582void msc_send_direct(struct bsc_msc_forward *fw, struct msgb *msg)
Holger Hans Peter Freyther594ee9a2010-11-16 11:03:19 +0100583{
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100584 return msc_send(fw, msg, IPAC_PROTO_SCCP);
Holger Hans Peter Freyther594ee9a2010-11-16 11:03:19 +0100585}
586
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100587void msc_send_msg(struct bsc_msc_forward *fw, int rc, struct sccp_parse_result *result, struct msgb *_msg)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800588{
589 struct msgb *msg;
590
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100591 if (fw->msc_connection.bfd.fd < 0) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800592 LOGP(DMSC, LOGL_ERROR, "No connection to the MSC. dropping\n");
593 return;
594 }
595
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100596 bsc_ussd_handle_out_msg(fw, result, _msg);
Holger Hans Peter Freyther0f349f22010-10-06 04:39:08 +0800597
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800598 msg = msgb_alloc_headroom(4096, 128, "SCCP to MSC");
599 if (!msg) {
600 LOGP(DMSC, LOGL_ERROR, "Failed to alloc MSC msg.\n");
601 return;
602 }
603
604 bss_rewrite_header_for_msc(rc, msg, _msg, result);
Holger Hans Peter Freythere86c02e2011-02-10 15:32:14 +0100605 msc_send(fw, msg, IPAC_PROTO_SCCP);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800606}