blob: 66288a316359dbbb388fc049b4e862cb00930537 [file] [log] [blame]
Holger Hans Peter Freythereef86b52010-06-15 18:45:06 +08001/* Routines to talk to the MSC using the IPA Protocol */
2/*
3 * (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
Holger Hans Peter Freytherdf6143a2010-06-15 18:46:56 +08004 * (C) 2010 by On-Waves
Holger Hans Peter Freythereef86b52010-06-15 18:45:06 +08005 * All Rights Reserved
6 *
7 * This program is free software; you can redistribute it and/or modify
Harald Welte9af6ddf2011-01-01 15:25:50 +01008 * 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 Freythereef86b52010-06-15 18:45:06 +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
Harald Welte9af6ddf2011-01-01 15:25:50 +010015 * GNU Affero General Public License for more details.
Holger Hans Peter Freythereef86b52010-06-15 18:45:06 +080016 *
Harald Welte9af6ddf2011-01-01 15:25:50 +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 Freythereef86b52010-06-15 18:45:06 +080019 *
20 */
21
22#include <openbsc/bsc_msc.h>
Holger Hans Peter Freyther6c0a04e2010-03-26 10:41:20 +010023#include <openbsc/debug.h>
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +020024#include <osmocom/abis/ipaccess.h>
Holger Hans Peter Freyther6c0a04e2010-03-26 10:41:20 +010025
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010026#include <osmocom/core/write_queue.h>
27#include <osmocom/core/talloc.h>
Holger Hans Peter Freythereef86b52010-06-15 18:45:06 +080028
Pablo Neira Ayusoed5cacb2011-08-17 22:44:07 +020029#include <osmocom/gsm/tlv.h>
30
Holger Hans Peter Freythereef86b52010-06-15 18:45:06 +080031#include <arpa/inet.h>
32#include <sys/socket.h>
Holger Hans Peter Freyther6c0a04e2010-03-26 10:41:20 +010033#include <errno.h>
34#include <fcntl.h>
Holger Hans Peter Freythereef86b52010-06-15 18:45:06 +080035#include <stdio.h>
36#include <string.h>
37#include <unistd.h>
38
Holger Hans Peter Freytherbaf2abe2010-06-15 18:47:29 +080039static void connection_loss(struct bsc_msc_connection *con)
40{
Pablo Neira Ayuso4db92992011-05-06 12:11:23 +020041 struct osmo_fd *fd;
Holger Hans Peter Freytherbaf2abe2010-06-15 18:47:29 +080042
43 fd = &con->write_queue.bfd;
44
45 close(fd->fd);
46 fd->fd = -1;
Pablo Neira Ayusoe1273b12011-05-06 12:09:47 +020047 fd->cb = osmo_wqueue_bfd_cb;
Holger Hans Peter Freytherbaf2abe2010-06-15 18:47:29 +080048 fd->when = 0;
49
50 con->is_connected = 0;
Holger Hans Peter Freytherbec411b2010-07-05 14:14:18 +080051 con->first_contact = 0;
Holger Hans Peter Freytherbaf2abe2010-06-15 18:47:29 +080052 con->connection_loss(con);
53}
54
Holger Hans Peter Freythere47a91b2010-05-05 22:48:56 +080055static void msc_con_timeout(void *_con)
56{
57 struct bsc_msc_connection *con = _con;
58
59 LOGP(DMSC, LOGL_ERROR, "MSC Connection timeout.\n");
60 bsc_msc_lost(con);
61}
62
Holger Hans Peter Freyther6c0a04e2010-03-26 10:41:20 +010063/* called in the case of a non blocking connect */
Pablo Neira Ayuso4db92992011-05-06 12:11:23 +020064static int msc_connection_connect(struct osmo_fd *fd, unsigned int what)
Holger Hans Peter Freyther6c0a04e2010-03-26 10:41:20 +010065{
66 int rc;
67 int val;
Holger Hans Peter Freytherbaf2abe2010-06-15 18:47:29 +080068 struct bsc_msc_connection *con;
Pablo Neira Ayusoe1273b12011-05-06 12:09:47 +020069 struct osmo_wqueue *queue;
Holger Hans Peter Freyther6c0a04e2010-03-26 10:41:20 +010070
71 socklen_t len = sizeof(val);
72
73 if ((what & BSC_FD_WRITE) == 0) {
Holger Hans Peter Freyther62abade2010-08-04 02:27:34 +080074 LOGP(DMSC, LOGL_ERROR, "Callback but not writable.\n");
Holger Hans Peter Freyther6c0a04e2010-03-26 10:41:20 +010075 return -1;
76 }
77
Pablo Neira Ayusoe1273b12011-05-06 12:09:47 +020078 queue = container_of(fd, struct osmo_wqueue, bfd);
Holger Hans Peter Freytherbaf2abe2010-06-15 18:47:29 +080079 con = container_of(queue, struct bsc_msc_connection, write_queue);
80
Holger Hans Peter Freytherd4eed522010-10-07 04:42:03 +080081 /* From here on we will either be connected or reconnect */
Pablo Neira Ayusobf540cb2011-05-06 12:11:06 +020082 osmo_timer_del(&con->timeout_timer);
Holger Hans Peter Freytherd4eed522010-10-07 04:42:03 +080083
Holger Hans Peter Freyther6c0a04e2010-03-26 10:41:20 +010084 /* check the socket state */
85 rc = getsockopt(fd->fd, SOL_SOCKET, SO_ERROR, &val, &len);
86 if (rc != 0) {
87 LOGP(DMSC, LOGL_ERROR, "getsockopt for the MSC socket failed.\n");
88 goto error;
89 }
90 if (val != 0) {
Holger Hans Peter Freyther9d90da92010-04-06 10:25:00 +020091 LOGP(DMSC, LOGL_ERROR, "Not connected to the MSC: %d\n", val);
Holger Hans Peter Freyther6c0a04e2010-03-26 10:41:20 +010092 goto error;
93 }
94
95
96 /* go to full operation */
Pablo Neira Ayusoe1273b12011-05-06 12:09:47 +020097 fd->cb = osmo_wqueue_bfd_cb;
Holger Hans Peter Freyther0176eb42010-04-08 11:12:32 +020098 fd->when = BSC_FD_READ | BSC_FD_EXCEPT;
Holger Hans Peter Freytherbaf2abe2010-06-15 18:47:29 +080099
100 con->is_connected = 1;
Holger Hans Peter Freytherb9ac37d2010-04-05 17:58:52 +0200101 LOGP(DMSC, LOGL_NOTICE, "(Re)Connected to the MSC.\n");
Holger Hans Peter Freytherbaf2abe2010-06-15 18:47:29 +0800102 if (con->connected)
103 con->connected(con);
Holger Hans Peter Freyther6c0a04e2010-03-26 10:41:20 +0100104 return 0;
105
106error:
Pablo Neira Ayuso4db92992011-05-06 12:11:23 +0200107 osmo_fd_unregister(fd);
Holger Hans Peter Freytherbaf2abe2010-06-15 18:47:29 +0800108 connection_loss(con);
Holger Hans Peter Freyther6c0a04e2010-03-26 10:41:20 +0100109 return -1;
110}
Pablo Neira Ayuso4db92992011-05-06 12:11:23 +0200111static void setnonblocking(struct osmo_fd *fd)
Holger Hans Peter Freyther6c0a04e2010-03-26 10:41:20 +0100112{
113 int flags;
114
115 flags = fcntl(fd->fd, F_GETFL);
116 if (flags < 0) {
117 perror("fcntl get failed");
118 close(fd->fd);
119 fd->fd = -1;
120 return;
121 }
122
123 flags |= O_NONBLOCK;
124 flags = fcntl(fd->fd, F_SETFL, flags);
125 if (flags < 0) {
126 perror("fcntl get failed");
127 close(fd->fd);
128 fd->fd = -1;
129 return;
130 }
131}
132
Holger Hans Peter Freytherbaf2abe2010-06-15 18:47:29 +0800133int bsc_msc_connect(struct bsc_msc_connection *con)
Holger Hans Peter Freythereef86b52010-06-15 18:45:06 +0800134{
Holger Hans Peter Freythere18801052011-04-23 23:31:31 +0200135 struct bsc_msc_dest *dest;
Pablo Neira Ayuso4db92992011-05-06 12:11:23 +0200136 struct osmo_fd *fd;
Holger Hans Peter Freythereef86b52010-06-15 18:45:06 +0800137 struct sockaddr_in sin;
138 int on = 1, ret;
139
Holger Hans Peter Freythere18801052011-04-23 23:31:31 +0200140 if (llist_empty(con->dests)) {
141 LOGP(DMSC, LOGL_ERROR, "No MSC connections configured.\n");
142 connection_loss(con);
143 return -1;
144 }
145
146 /* move to the next connection */
147 dest = (struct bsc_msc_dest *) con->dests->next;
148 llist_del(&dest->list);
149 llist_add_tail(&dest->list, con->dests);
150
151 LOGP(DMSC, LOGL_NOTICE, "Attempting to connect MSC at %s:%d\n",
152 dest->ip, dest->port);
Holger Hans Peter Freythereef86b52010-06-15 18:45:06 +0800153
Holger Hans Peter Freytherbaf2abe2010-06-15 18:47:29 +0800154 con->is_connected = 0;
155
156 fd = &con->write_queue.bfd;
Holger Hans Peter Freythereef86b52010-06-15 18:45:06 +0800157 fd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
Holger Hans Peter Freythereef86b52010-06-15 18:45:06 +0800158 fd->priv_nr = 1;
159
160 if (fd->fd < 0) {
161 perror("Creating TCP socket failed");
162 return fd->fd;
163 }
164
Holger Hans Peter Freyther6c0a04e2010-03-26 10:41:20 +0100165 /* make it non blocking */
166 setnonblocking(fd);
Holger Hans Peter Freythereef86b52010-06-15 18:45:06 +0800167
Holger Hans Peter Freytherca999a92010-06-15 18:52:38 +0800168 /* set the socket priority */
169 ret = setsockopt(fd->fd, IPPROTO_IP, IP_TOS,
Holger Hans Peter Freythere18801052011-04-23 23:31:31 +0200170 &dest->dscp, sizeof(dest->dscp));
Holger Hans Peter Freytherca999a92010-06-15 18:52:38 +0800171 if (ret != 0)
Holger Hans Peter Freythere18801052011-04-23 23:31:31 +0200172 LOGP(DMSC, LOGL_ERROR, "Failed to set DSCP to %d. %s\n",
173 dest->dscp, strerror(errno));
Holger Hans Peter Freytherca999a92010-06-15 18:52:38 +0800174
Holger Hans Peter Freythereef86b52010-06-15 18:45:06 +0800175 memset(&sin, 0, sizeof(sin));
176 sin.sin_family = AF_INET;
Holger Hans Peter Freythere18801052011-04-23 23:31:31 +0200177 sin.sin_port = htons(dest->port);
178 inet_aton(dest->ip, &sin.sin_addr);
Holger Hans Peter Freythereef86b52010-06-15 18:45:06 +0800179
180 setsockopt(fd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
181 ret = connect(fd->fd, (struct sockaddr *) &sin, sizeof(sin));
182
Holger Hans Peter Freyther6c0a04e2010-03-26 10:41:20 +0100183 if (ret == -1 && errno == EINPROGRESS) {
184 LOGP(DMSC, LOGL_ERROR, "MSC Connection in progress\n");
185 fd->when = BSC_FD_WRITE;
186 fd->cb = msc_connection_connect;
Holger Hans Peter Freythere47a91b2010-05-05 22:48:56 +0800187 con->timeout_timer.cb = msc_con_timeout;
188 con->timeout_timer.data = con;
Pablo Neira Ayusobf540cb2011-05-06 12:11:06 +0200189 osmo_timer_schedule(&con->timeout_timer, 20, 0);
Holger Hans Peter Freyther6c0a04e2010-03-26 10:41:20 +0100190 } else if (ret < 0) {
Holger Hans Peter Freythereef86b52010-06-15 18:45:06 +0800191 perror("Connection failed");
Holger Hans Peter Freytherbaf2abe2010-06-15 18:47:29 +0800192 connection_loss(con);
Holger Hans Peter Freythereef86b52010-06-15 18:45:06 +0800193 return ret;
Holger Hans Peter Freyther6c0a04e2010-03-26 10:41:20 +0100194 } else {
Holger Hans Peter Freyther0176eb42010-04-08 11:12:32 +0200195 fd->when = BSC_FD_READ | BSC_FD_EXCEPT;
Pablo Neira Ayusoe1273b12011-05-06 12:09:47 +0200196 fd->cb = osmo_wqueue_bfd_cb;
Holger Hans Peter Freytherbaf2abe2010-06-15 18:47:29 +0800197 con->is_connected = 1;
198 if (con->connected)
199 con->connected(con);
Holger Hans Peter Freythereef86b52010-06-15 18:45:06 +0800200 }
201
Pablo Neira Ayuso4db92992011-05-06 12:11:23 +0200202 ret = osmo_fd_register(fd);
Holger Hans Peter Freythereef86b52010-06-15 18:45:06 +0800203 if (ret < 0) {
204 perror("Registering the fd failed");
205 close(fd->fd);
206 return ret;
207 }
208
209 return ret;
210}
Holger Hans Peter Freytherbaf2abe2010-06-15 18:47:29 +0800211
Holger Hans Peter Freythere18801052011-04-23 23:31:31 +0200212struct bsc_msc_connection *bsc_msc_create(void *ctx, struct llist_head *dests)
Holger Hans Peter Freytherbaf2abe2010-06-15 18:47:29 +0800213{
214 struct bsc_msc_connection *con;
215
216 con = talloc_zero(NULL, struct bsc_msc_connection);
217 if (!con) {
218 LOGP(DMSC, LOGL_FATAL, "Failed to create the MSC connection.\n");
219 return NULL;
220 }
221
Holger Hans Peter Freythere18801052011-04-23 23:31:31 +0200222 con->dests = dests;
223 con->write_queue.bfd.fd = -1;
Pablo Neira Ayusoe1273b12011-05-06 12:09:47 +0200224 osmo_wqueue_init(&con->write_queue, 100);
Holger Hans Peter Freytherbaf2abe2010-06-15 18:47:29 +0800225 return con;
226}
227
228void bsc_msc_lost(struct bsc_msc_connection *con)
229{
Pablo Neira Ayusoe1273b12011-05-06 12:09:47 +0200230 osmo_wqueue_clear(&con->write_queue);
Pablo Neira Ayusobf540cb2011-05-06 12:11:06 +0200231 osmo_timer_del(&con->timeout_timer);
Holger Hans Peter Freytherfad07532010-10-07 06:07:57 +0800232
233 if (con->write_queue.bfd.fd >= 0)
Pablo Neira Ayuso4db92992011-05-06 12:11:23 +0200234 osmo_fd_unregister(&con->write_queue.bfd);
Holger Hans Peter Freytherbaf2abe2010-06-15 18:47:29 +0800235 connection_loss(con);
236}
237
238static void reconnect_msc(void *_msc)
239{
240 struct bsc_msc_connection *con = _msc;
241
242 LOGP(DMSC, LOGL_NOTICE, "Attempting to reconnect to the MSC.\n");
243 bsc_msc_connect(con);
244}
245
246void bsc_msc_schedule_connect(struct bsc_msc_connection *con)
247{
248 LOGP(DMSC, LOGL_NOTICE, "Attempting to reconnect to the MSC.\n");
249 con->reconnect_timer.cb = reconnect_msc;
250 con->reconnect_timer.data = con;
Pablo Neira Ayusobf540cb2011-05-06 12:11:06 +0200251 osmo_timer_schedule(&con->reconnect_timer, 5, 0);
Holger Hans Peter Freytherf76e7ef2010-06-15 18:52:05 +0800252}
253
254struct msgb *bsc_msc_id_get_resp(const char *token)
255{
256 struct msgb *msg;
257
258 if (!token) {
259 LOGP(DMSC, LOGL_ERROR, "No token specified.\n");
260 return NULL;
261 }
262
263 msg = msgb_alloc_headroom(4096, 128, "id resp");
264 if (!msg) {
265 LOGP(DMSC, LOGL_ERROR, "Failed to create the message.\n");
266 return NULL;
267 }
268
269 msg->l2h = msgb_v_put(msg, IPAC_MSGT_ID_RESP);
270 msgb_l16tv_put(msg, strlen(token) + 1,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200271 IPAC_IDTAG_UNITNAME, (uint8_t *) token);
Holger Hans Peter Freytherf76e7ef2010-06-15 18:52:05 +0800272 return msg;
Holger Hans Peter Freytherbec411b2010-07-05 14:14:18 +0800273}