blob: e373679c12f3b33fab3fc3f7239bafd722e7df98 [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
Jacob Erlbecke8278122014-03-31 13:42:11 +020045 if (con->pending_msg) {
46 LOGP(DMSC, LOGL_ERROR,
47 "MSC(%s) dropping incomplete message.\n", con->name);
48 msgb_free(con->pending_msg);
49 con->pending_msg = NULL;
50 }
51
Holger Hans Peter Freytherbaf2abe2010-06-15 18:47:29 +080052 close(fd->fd);
53 fd->fd = -1;
Pablo Neira Ayusoe1273b12011-05-06 12:09:47 +020054 fd->cb = osmo_wqueue_bfd_cb;
Holger Hans Peter Freytherbaf2abe2010-06-15 18:47:29 +080055 fd->when = 0;
56
57 con->is_connected = 0;
Holger Hans Peter Freytherbec411b2010-07-05 14:14:18 +080058 con->first_contact = 0;
Holger Hans Peter Freytherbaf2abe2010-06-15 18:47:29 +080059 con->connection_loss(con);
60}
61
Holger Hans Peter Freythere47a91b2010-05-05 22:48:56 +080062static void msc_con_timeout(void *_con)
63{
64 struct bsc_msc_connection *con = _con;
65
Holger Hans Peter Freytherc1a86872013-09-02 13:07:45 +020066 LOGP(DMSC, LOGL_ERROR,
67 "MSC(%s) Connection timeout.\n", con->name);
Holger Hans Peter Freythere47a91b2010-05-05 22:48:56 +080068 bsc_msc_lost(con);
69}
70
Holger Hans Peter Freyther6c0a04e2010-03-26 10:41:20 +010071/* called in the case of a non blocking connect */
Pablo Neira Ayuso4db92992011-05-06 12:11:23 +020072static int msc_connection_connect(struct osmo_fd *fd, unsigned int what)
Holger Hans Peter Freyther6c0a04e2010-03-26 10:41:20 +010073{
74 int rc;
75 int val;
Holger Hans Peter Freytherbaf2abe2010-06-15 18:47:29 +080076 struct bsc_msc_connection *con;
Pablo Neira Ayusoe1273b12011-05-06 12:09:47 +020077 struct osmo_wqueue *queue;
Holger Hans Peter Freyther6c0a04e2010-03-26 10:41:20 +010078
79 socklen_t len = sizeof(val);
80
Pablo Neira Ayusoe1273b12011-05-06 12:09:47 +020081 queue = container_of(fd, struct osmo_wqueue, bfd);
Holger Hans Peter Freytherbaf2abe2010-06-15 18:47:29 +080082 con = container_of(queue, struct bsc_msc_connection, write_queue);
83
Holger Hans Peter Freytherc1a86872013-09-02 13:07:45 +020084 if ((what & BSC_FD_WRITE) == 0) {
85 LOGP(DMSC, LOGL_ERROR,
86 "MSC(%s) Callback but not writable.\n", con->name);
87 return -1;
88 }
89
Holger Hans Peter Freytherd4eed522010-10-07 04:42:03 +080090 /* From here on we will either be connected or reconnect */
Pablo Neira Ayusobf540cb2011-05-06 12:11:06 +020091 osmo_timer_del(&con->timeout_timer);
Holger Hans Peter Freytherd4eed522010-10-07 04:42:03 +080092
Holger Hans Peter Freyther6c0a04e2010-03-26 10:41:20 +010093 /* check the socket state */
94 rc = getsockopt(fd->fd, SOL_SOCKET, SO_ERROR, &val, &len);
95 if (rc != 0) {
Holger Hans Peter Freytherc1a86872013-09-02 13:07:45 +020096 LOGP(DMSC, LOGL_ERROR,
97 "getsockopt for the MSC(%s) socket failed.\n", con->name);
Holger Hans Peter Freyther6c0a04e2010-03-26 10:41:20 +010098 goto error;
99 }
100 if (val != 0) {
Holger Hans Peter Freytherc1a86872013-09-02 13:07:45 +0200101 LOGP(DMSC, LOGL_ERROR,
102 "Not connected to the MSC(%s): %d\n",
103 con->name, val);
Holger Hans Peter Freyther6c0a04e2010-03-26 10:41:20 +0100104 goto error;
105 }
106
107
108 /* go to full operation */
Pablo Neira Ayusoe1273b12011-05-06 12:09:47 +0200109 fd->cb = osmo_wqueue_bfd_cb;
Holger Hans Peter Freyther0176eb42010-04-08 11:12:32 +0200110 fd->when = BSC_FD_READ | BSC_FD_EXCEPT;
Holger Hans Peter Freytherbaf2abe2010-06-15 18:47:29 +0800111
112 con->is_connected = 1;
Holger Hans Peter Freytherc1a86872013-09-02 13:07:45 +0200113 LOGP(DMSC, LOGL_NOTICE,
114 "(Re)Connected to the MSC(%s).\n", con->name);
Holger Hans Peter Freytherbaf2abe2010-06-15 18:47:29 +0800115 if (con->connected)
116 con->connected(con);
Holger Hans Peter Freyther6c0a04e2010-03-26 10:41:20 +0100117 return 0;
118
119error:
Pablo Neira Ayuso4db92992011-05-06 12:11:23 +0200120 osmo_fd_unregister(fd);
Holger Hans Peter Freytherbaf2abe2010-06-15 18:47:29 +0800121 connection_loss(con);
Holger Hans Peter Freyther6c0a04e2010-03-26 10:41:20 +0100122 return -1;
123}
Pablo Neira Ayuso4db92992011-05-06 12:11:23 +0200124static void setnonblocking(struct osmo_fd *fd)
Holger Hans Peter Freyther6c0a04e2010-03-26 10:41:20 +0100125{
126 int flags;
127
128 flags = fcntl(fd->fd, F_GETFL);
129 if (flags < 0) {
130 perror("fcntl get failed");
131 close(fd->fd);
132 fd->fd = -1;
133 return;
134 }
135
136 flags |= O_NONBLOCK;
137 flags = fcntl(fd->fd, F_SETFL, flags);
138 if (flags < 0) {
139 perror("fcntl get failed");
140 close(fd->fd);
141 fd->fd = -1;
142 return;
143 }
144}
145
Holger Hans Peter Freytherbaf2abe2010-06-15 18:47:29 +0800146int bsc_msc_connect(struct bsc_msc_connection *con)
Holger Hans Peter Freythereef86b52010-06-15 18:45:06 +0800147{
Holger Hans Peter Freythere18801052011-04-23 23:31:31 +0200148 struct bsc_msc_dest *dest;
Pablo Neira Ayuso4db92992011-05-06 12:11:23 +0200149 struct osmo_fd *fd;
Holger Hans Peter Freythereef86b52010-06-15 18:45:06 +0800150 struct sockaddr_in sin;
151 int on = 1, ret;
152
Holger Hans Peter Freythere18801052011-04-23 23:31:31 +0200153 if (llist_empty(con->dests)) {
Holger Hans Peter Freytherc1a86872013-09-02 13:07:45 +0200154 LOGP(DMSC, LOGL_ERROR,
155 "No MSC(%s) connections configured.\n",
156 con->name);
Holger Hans Peter Freythere18801052011-04-23 23:31:31 +0200157 connection_loss(con);
158 return -1;
159 }
160
Harald Welte48743612016-11-26 14:13:33 +0100161 /* TODO: Why are we not using the libosmocore soecket
162 * abstraction, or libosmo-netif? */
163
Holger Hans Peter Freythere18801052011-04-23 23:31:31 +0200164 /* move to the next connection */
165 dest = (struct bsc_msc_dest *) con->dests->next;
166 llist_del(&dest->list);
167 llist_add_tail(&dest->list, con->dests);
168
Holger Hans Peter Freytherc1a86872013-09-02 13:07:45 +0200169 LOGP(DMSC, LOGL_NOTICE,
170 "Attempting to connect MSC(%s) at %s:%d\n",
171 con->name, dest->ip, dest->port);
Holger Hans Peter Freythereef86b52010-06-15 18:45:06 +0800172
Holger Hans Peter Freytherbaf2abe2010-06-15 18:47:29 +0800173 con->is_connected = 0;
174
Jacob Erlbecke8278122014-03-31 13:42:11 +0200175 msgb_free(con->pending_msg);
176 con->pending_msg = NULL;
177
Holger Hans Peter Freytherbaf2abe2010-06-15 18:47:29 +0800178 fd = &con->write_queue.bfd;
Holger Hans Peter Freythereef86b52010-06-15 18:45:06 +0800179 fd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
Holger Hans Peter Freythereef86b52010-06-15 18:45:06 +0800180 fd->priv_nr = 1;
181
182 if (fd->fd < 0) {
183 perror("Creating TCP socket failed");
184 return fd->fd;
185 }
186
Holger Hans Peter Freyther6c0a04e2010-03-26 10:41:20 +0100187 /* make it non blocking */
188 setnonblocking(fd);
Holger Hans Peter Freythereef86b52010-06-15 18:45:06 +0800189
Holger Hans Peter Freytherca999a92010-06-15 18:52:38 +0800190 /* set the socket priority */
191 ret = setsockopt(fd->fd, IPPROTO_IP, IP_TOS,
Holger Hans Peter Freythere18801052011-04-23 23:31:31 +0200192 &dest->dscp, sizeof(dest->dscp));
Holger Hans Peter Freytherca999a92010-06-15 18:52:38 +0800193 if (ret != 0)
Holger Hans Peter Freytherc1a86872013-09-02 13:07:45 +0200194 LOGP(DMSC, LOGL_ERROR,
195 "Failed to set DSCP to %d on MSC(%s). %s\n",
196 dest->dscp, con->name, strerror(errno));
Holger Hans Peter Freytherca999a92010-06-15 18:52:38 +0800197
Holger Hans Peter Freythereef86b52010-06-15 18:45:06 +0800198 memset(&sin, 0, sizeof(sin));
199 sin.sin_family = AF_INET;
Holger Hans Peter Freythere18801052011-04-23 23:31:31 +0200200 sin.sin_port = htons(dest->port);
201 inet_aton(dest->ip, &sin.sin_addr);
Holger Hans Peter Freythereef86b52010-06-15 18:45:06 +0800202
Harald Welte48743612016-11-26 14:13:33 +0100203 ret = setsockopt(fd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
204 if (ret != 0)
205 LOGP(DMSC, LOGL_ERROR,
206 "Failed to set SO_REUSEADDR socket option\n");
Holger Hans Peter Freythereef86b52010-06-15 18:45:06 +0800207 ret = connect(fd->fd, (struct sockaddr *) &sin, sizeof(sin));
208
Holger Hans Peter Freyther6c0a04e2010-03-26 10:41:20 +0100209 if (ret == -1 && errno == EINPROGRESS) {
Holger Hans Peter Freytherc1a86872013-09-02 13:07:45 +0200210 LOGP(DMSC, LOGL_ERROR,
211 "MSC(%s) Connection in progress\n", con->name);
Holger Hans Peter Freyther6c0a04e2010-03-26 10:41:20 +0100212 fd->when = BSC_FD_WRITE;
213 fd->cb = msc_connection_connect;
Holger Hans Peter Freythere47a91b2010-05-05 22:48:56 +0800214 con->timeout_timer.cb = msc_con_timeout;
215 con->timeout_timer.data = con;
Pablo Neira Ayusobf540cb2011-05-06 12:11:06 +0200216 osmo_timer_schedule(&con->timeout_timer, 20, 0);
Holger Hans Peter Freyther6c0a04e2010-03-26 10:41:20 +0100217 } else if (ret < 0) {
Holger Hans Peter Freythereef86b52010-06-15 18:45:06 +0800218 perror("Connection failed");
Holger Hans Peter Freytherbaf2abe2010-06-15 18:47:29 +0800219 connection_loss(con);
Holger Hans Peter Freythereef86b52010-06-15 18:45:06 +0800220 return ret;
Holger Hans Peter Freyther6c0a04e2010-03-26 10:41:20 +0100221 } else {
Holger Hans Peter Freyther0176eb42010-04-08 11:12:32 +0200222 fd->when = BSC_FD_READ | BSC_FD_EXCEPT;
Pablo Neira Ayusoe1273b12011-05-06 12:09:47 +0200223 fd->cb = osmo_wqueue_bfd_cb;
Holger Hans Peter Freytherbaf2abe2010-06-15 18:47:29 +0800224 con->is_connected = 1;
225 if (con->connected)
226 con->connected(con);
Holger Hans Peter Freythereef86b52010-06-15 18:45:06 +0800227 }
228
Pablo Neira Ayuso4db92992011-05-06 12:11:23 +0200229 ret = osmo_fd_register(fd);
Holger Hans Peter Freythereef86b52010-06-15 18:45:06 +0800230 if (ret < 0) {
231 perror("Registering the fd failed");
232 close(fd->fd);
233 return ret;
234 }
235
236 return ret;
237}
Holger Hans Peter Freytherbaf2abe2010-06-15 18:47:29 +0800238
Holger Hans Peter Freythere18801052011-04-23 23:31:31 +0200239struct bsc_msc_connection *bsc_msc_create(void *ctx, struct llist_head *dests)
Holger Hans Peter Freytherbaf2abe2010-06-15 18:47:29 +0800240{
241 struct bsc_msc_connection *con;
242
243 con = talloc_zero(NULL, struct bsc_msc_connection);
244 if (!con) {
Holger Hans Peter Freyther3ffd9bc2013-09-04 08:45:48 +0200245 LOGP(DMSC, LOGL_FATAL, "Failed to create the MSC connection.\n");
Holger Hans Peter Freytherbaf2abe2010-06-15 18:47:29 +0800246 return NULL;
247 }
248
Holger Hans Peter Freythere18801052011-04-23 23:31:31 +0200249 con->dests = dests;
250 con->write_queue.bfd.fd = -1;
Holger Hans Peter Freytherc1a86872013-09-02 13:07:45 +0200251 con->name = "";
Pablo Neira Ayusoe1273b12011-05-06 12:09:47 +0200252 osmo_wqueue_init(&con->write_queue, 100);
Holger Hans Peter Freytherbaf2abe2010-06-15 18:47:29 +0800253 return con;
254}
255
256void bsc_msc_lost(struct bsc_msc_connection *con)
257{
Pablo Neira Ayusoe1273b12011-05-06 12:09:47 +0200258 osmo_wqueue_clear(&con->write_queue);
Pablo Neira Ayusobf540cb2011-05-06 12:11:06 +0200259 osmo_timer_del(&con->timeout_timer);
Holger Hans Peter Freyther33eb5872013-09-03 14:21:48 +0200260 osmo_timer_del(&con->reconnect_timer);
Holger Hans Peter Freytherfad07532010-10-07 06:07:57 +0800261
262 if (con->write_queue.bfd.fd >= 0)
Pablo Neira Ayuso4db92992011-05-06 12:11:23 +0200263 osmo_fd_unregister(&con->write_queue.bfd);
Holger Hans Peter Freytherbaf2abe2010-06-15 18:47:29 +0800264 connection_loss(con);
265}
266
267static void reconnect_msc(void *_msc)
268{
269 struct bsc_msc_connection *con = _msc;
270
Holger Hans Peter Freytherc1a86872013-09-02 13:07:45 +0200271 LOGP(DMSC, LOGL_NOTICE,
272 "Attempting to reconnect to the MSC(%s).\n", con->name);
Holger Hans Peter Freytherbaf2abe2010-06-15 18:47:29 +0800273 bsc_msc_connect(con);
274}
275
276void bsc_msc_schedule_connect(struct bsc_msc_connection *con)
277{
Holger Hans Peter Freytherc1a86872013-09-02 13:07:45 +0200278 LOGP(DMSC, LOGL_NOTICE,
279 "Attempting to reconnect to the MSC(%s)\n", con->name);
Holger Hans Peter Freytherbaf2abe2010-06-15 18:47:29 +0800280 con->reconnect_timer.cb = reconnect_msc;
281 con->reconnect_timer.data = con;
Pablo Neira Ayusobf540cb2011-05-06 12:11:06 +0200282 osmo_timer_schedule(&con->reconnect_timer, 5, 0);
Holger Hans Peter Freytherf76e7ef2010-06-15 18:52:05 +0800283}
284
Holger Hans Peter Freythere2ac6b72015-06-08 18:02:10 +0200285struct msgb *bsc_msc_id_get_resp(int fixed, const char *token, const uint8_t *res, int len)
Holger Hans Peter Freytherf76e7ef2010-06-15 18:52:05 +0800286{
287 struct msgb *msg;
288
289 if (!token) {
290 LOGP(DMSC, LOGL_ERROR, "No token specified.\n");
291 return NULL;
292 }
293
294 msg = msgb_alloc_headroom(4096, 128, "id resp");
295 if (!msg) {
296 LOGP(DMSC, LOGL_ERROR, "Failed to create the message.\n");
297 return NULL;
298 }
299
Holger Hans Peter Freyther8a8df802015-06-10 11:51:16 +0200300 /*
301 * The situation is bizarre. The encoding doesn't follow the
302 * TLV structure. It is more like a LV and old versions had
303 * it wrong but we want new versions to old servers so we
304 * introduce the quirk here.
305 */
Holger Hans Peter Freytherf76e7ef2010-06-15 18:52:05 +0800306 msg->l2h = msgb_v_put(msg, IPAC_MSGT_ID_RESP);
Holger Hans Peter Freyther8a8df802015-06-10 11:51:16 +0200307 if (fixed) {
308 msgb_put_u8(msg, 0);
309 msgb_put_u8(msg, strlen(token) + 2);
310 msgb_tv_fixed_put(msg, IPAC_IDTAG_UNITNAME, strlen(token) + 1, (uint8_t *) token);
Holger Hans Peter Freythere2ac6b72015-06-08 18:02:10 +0200311 if (len > 0) {
312 msgb_put_u8(msg, 0);
313 msgb_put_u8(msg, len + 1);
314 msgb_tv_fixed_put(msg, 0x24, len, res);
315 }
Holger Hans Peter Freyther8a8df802015-06-10 11:51:16 +0200316 } else {
317 msgb_l16tv_put(msg, strlen(token) + 1,
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200318 IPAC_IDTAG_UNITNAME, (uint8_t *) token);
Holger Hans Peter Freyther8a8df802015-06-10 11:51:16 +0200319 }
320
Holger Hans Peter Freytherf76e7ef2010-06-15 18:52:05 +0800321 return msg;
Holger Hans Peter Freytherbec411b2010-07-05 14:14:18 +0800322}