blob: 069f9c6846cbc3bab8462679db96eea7c8a1e4ce [file] [log] [blame]
Alexander Couzensbeb10ef2016-11-01 22:05:13 +01001/* OpenBSC Abis receive lapd over a unix socket */
2
Harald Welte323d39d2017-11-13 01:09:21 +09003/* (C) 2016 by sysmocom - s.f.m.c. GmbH
Alexander Couzensbeb10ef2016-11-01 22:05:13 +01004 * Author: Alexander Couzens <lynxis@fe80.eu>
5 * Based on other e1_input drivers.
6 *
7 * All Rights Reserved
8 *
Harald Welte323d39d2017-11-13 01:09:21 +09009 * SPDX-License-Identifier: GPL-2.0+
10 *
Alexander Couzensbeb10ef2016-11-01 22:05:13 +010011 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
Alexander Couzensbeb10ef2016-11-01 22:05:13 +010021 */
22
23#include <errno.h>
24#include <stdio.h>
25#include <unistd.h>
26#include <sys/socket.h>
Stefan Sperlingb24efa52018-08-28 14:03:41 +020027#include <sys/un.h>
Alexander Couzensbeb10ef2016-11-01 22:05:13 +010028#include <limits.h>
29#include <string.h>
30
31#include <osmocom/core/talloc.h>
32#include <osmocom/core/logging.h>
33#include <osmocom/core/socket.h>
34
35#include <osmocom/abis/e1_input.h>
36#include <osmocom/abis/lapd.h>
37#include <osmocom/abis/e1_input.h>
38
39#include <osmocom/abis/unixsocket_proto.h>
40#include "internal.h"
41
42void *tall_unixsocket_ctx;
43#define UNIXSOCKET_ALLOC_SIZE 1600
44#define UNIXSOCKET_SOCK_PATH_DEFAULT "/tmp/osmo_abis_line_"
45
46struct unixsocket_line {
47 struct osmo_fd fd;
48};
49
50static int unixsocket_line_update(struct e1inp_line *line);
51static int ts_want_write(struct e1inp_ts *e1i_ts);
52
53static int unixsocket_exception_cb(struct osmo_fd *bfd)
54{
55 struct e1inp_line *line = bfd->data;
56
Harald Welteb5af0992020-01-12 12:59:52 +010057 LOGPIL(line, DLINP, LOGL_ERROR, "Socket connection failure, reconnecting... (line=%p, fd=%d)\n",
58 line, bfd->fd);
Alexander Couzensbeb10ef2016-11-01 22:05:13 +010059
60 /* Unregister faulty file descriptor from select loop */
61 if(osmo_fd_is_registered(bfd)) {
Harald Welteb5af0992020-01-12 12:59:52 +010062 LOGPIL(line, DLINP, LOGL_DEBUG, "removing inactive socket from select loop... (line=%p, fd=%d)\n",
63 line, bfd->fd);
Alexander Couzensbeb10ef2016-11-01 22:05:13 +010064 osmo_fd_unregister(bfd);
65 }
66
67 /* Close faulty file descriptor */
68 close(bfd->fd);
69
70 unixsocket_line_update(line);
71
72 return 0;
73}
74
75static int unixsocket_read_cb(struct osmo_fd *bfd)
76{
77 struct e1inp_line *line = bfd->data;
78 struct msgb *msg = msgb_alloc(UNIXSOCKET_ALLOC_SIZE, "UNIXSOCKET TS");
79 uint8_t version;
80 uint8_t controldata;
81 int ret;
82
83 if (!msg)
84 return -ENOMEM;
85
86 ret = read(bfd->fd, msg->data, UNIXSOCKET_ALLOC_SIZE - 16);
87 if (ret == 0) {
88 unixsocket_exception_cb(bfd);
89 goto fail;
90 } else if (ret < 0) {
91 perror("read ");
92 goto fail;
93 } else if (ret < 2) {
94 /* packet must be at least 2 byte long to hold version + control/data header */
Harald Welteb5af0992020-01-12 12:59:52 +010095 LOGPIL(line, DLMI, LOGL_ERROR, "received to small packet: %d < 2", ret);
Alexander Couzensbeb10ef2016-11-01 22:05:13 +010096 ret = -1;
97 goto fail;
98 }
99 msgb_put(msg, ret);
100
Harald Welteb5af0992020-01-12 12:59:52 +0100101 LOGPIL(line, DLMI, LOGL_DEBUG, "rx msg: %s (fd=%d)\n", osmo_hexdump_nospc(msg->data, msg->len), bfd->fd);
Alexander Couzensbeb10ef2016-11-01 22:05:13 +0100102
103 /* check version header */
104 version = msgb_pull_u8(msg);
105 controldata = msgb_pull_u8(msg);
106
107 if (version != UNIXSOCKET_PROTO_VERSION) {
Harald Welteb5af0992020-01-12 12:59:52 +0100108 LOGPIL(line, DLMI, LOGL_ERROR, "received message with invalid version %d. valid: %d",
109 ret, UNIXSOCKET_PROTO_VERSION);
Alexander Couzensbeb10ef2016-11-01 22:05:13 +0100110 ret = -1;
111 goto fail;
112 }
113
114 switch (controldata) {
115 case UNIXSOCKET_PROTO_DATA:
116 return e1inp_rx_ts_lapd(&line->ts[0], msg);
117 case UNIXSOCKET_PROTO_CONTROL:
Harald Welteb5af0992020-01-12 12:59:52 +0100118 LOGPIL(line, DLMI, LOGL_ERROR, "received (invalid) control message.");
Alexander Couzensbeb10ef2016-11-01 22:05:13 +0100119 ret = -1;
120 break;
121 default:
Harald Welteb5af0992020-01-12 12:59:52 +0100122 LOGPIL(line, DLMI, LOGL_ERROR, "received invalid message.");
Alexander Couzensbeb10ef2016-11-01 22:05:13 +0100123 ret = -1;
124 break;
125 }
126fail:
127 msgb_free(msg);
128 return ret;
129}
130
131static void timeout_ts1_write(void *data)
132{
133 struct e1inp_ts *e1i_ts = (struct e1inp_ts *)data;
134
135 /* trigger write of ts1, due to tx delay timer */
136 ts_want_write(e1i_ts);
137}
138
139static int unixsocket_write_cb(struct osmo_fd *bfd)
140{
141 struct e1inp_line *line = bfd->data;
142 struct e1inp_ts *e1i_ts = &line->ts[0];
143 struct msgb *msg;
144 struct e1inp_sign_link *sign_link;
145
Harald Welte949b8a22020-10-18 23:01:53 +0200146 osmo_fd_write_disable(bfd);
Alexander Couzensbeb10ef2016-11-01 22:05:13 +0100147
148 /* get the next msg for this timeslot */
149 msg = e1inp_tx_ts(e1i_ts, &sign_link);
150 if (!msg) {
151 /* no message after tx delay timer */
Harald Welteb5af0992020-01-12 12:59:52 +0100152 LOGPITS(e1i_ts, DLINP, LOGL_INFO, "no message available (line=%p)\n", line);
Alexander Couzensbeb10ef2016-11-01 22:05:13 +0100153 return 0;
154 }
155
156 /* set tx delay timer for next event */
Pablo Neira Ayusob26f2fd2017-06-07 18:32:13 +0200157 osmo_timer_setup(&e1i_ts->sign.tx_timer, timeout_ts1_write, e1i_ts);
Alexander Couzensbeb10ef2016-11-01 22:05:13 +0100158
159 osmo_timer_schedule(&e1i_ts->sign.tx_timer, 0, e1i_ts->sign.delay);
160
Harald Welteb5af0992020-01-12 12:59:52 +0100161 LOGPITS(e1i_ts, DLINP, LOGL_DEBUG, "sending: %s (line=%p)\n", msgb_hexdump(msg), line);
Alexander Couzensbeb10ef2016-11-01 22:05:13 +0100162 lapd_transmit(e1i_ts->lapd, sign_link->tei,
163 sign_link->sapi, msg);
164
165 return 0;
166}
167
168static int unixsocket_cb(struct osmo_fd *bfd, unsigned int what)
169{
170 int ret = 0;
171
Harald Weltede3959e2020-10-18 22:28:50 +0200172 if (what & OSMO_FD_READ)
Alexander Couzensbeb10ef2016-11-01 22:05:13 +0100173 ret = unixsocket_read_cb(bfd);
Harald Weltede3959e2020-10-18 22:28:50 +0200174 if (what & OSMO_FD_WRITE)
Alexander Couzensbeb10ef2016-11-01 22:05:13 +0100175 ret = unixsocket_write_cb(bfd);
176
177 return ret;
178}
179
180static int ts_want_write(struct e1inp_ts *e1i_ts)
181{
182 struct unixsocket_line *line = e1i_ts->line->driver_data;
183
Harald Welte949b8a22020-10-18 23:01:53 +0200184 osmo_fd_write_enable(&line->fd);
Alexander Couzensbeb10ef2016-11-01 22:05:13 +0100185
186 return 0;
187}
188
Harald Welteb5af0992020-01-12 12:59:52 +0100189static void unixsocket_write_msg(struct msgb *msg, struct osmo_fd *bfd)
190{
191 struct e1inp_line *line = bfd->data;
Alexander Couzensbeb10ef2016-11-01 22:05:13 +0100192 int ret;
193
Harald Welteb5af0992020-01-12 12:59:52 +0100194 LOGPIL(line, DLMI, LOGL_DEBUG, "tx msg: %s (fd=%d)\n",
195 osmo_hexdump_nospc(msg->data, msg->len), bfd->fd);
Alexander Couzensbeb10ef2016-11-01 22:05:13 +0100196
197 ret = write(bfd->fd, msg->data, msg->len);
198 msgb_free(msg);
199 if (ret == -1)
200 unixsocket_exception_cb(bfd);
201 else if (ret < 0)
Harald Welteb5af0992020-01-12 12:59:52 +0100202 LOGPIL(line, DLMI, LOGL_NOTICE, "%s write failed %d\n", __func__, ret);
Alexander Couzensbeb10ef2016-11-01 22:05:13 +0100203}
204
205/*!
206 * \brief unixsocket_write_msg lapd callback for data to unixsocket
207 * \param msg
208 * \param cbdata
209 */
210static void unixsocket_write_msg_lapd_cb(struct msgb *msg, void *cbdata)
211{
212 struct osmo_fd *bfd = cbdata;
213
214 /* data|control */
215 msgb_push_u8(msg, UNIXSOCKET_PROTO_DATA);
216 /* add version header */
217 msgb_push_u8(msg, UNIXSOCKET_PROTO_VERSION);
218
219 unixsocket_write_msg(msg, bfd);
220}
221
222static int unixsocket_line_update(struct e1inp_line *line)
223{
224 struct unixsocket_line *config;
Stefan Sperling0d7d0b02018-09-20 17:34:31 +0200225 struct sockaddr_un un;
Stefan Sperlingb24efa52018-08-28 14:03:41 +0200226 const char *sock_path;
Alexander Couzensbeb10ef2016-11-01 22:05:13 +0100227 int ret = 0;
228 int i;
229
Harald Welteb5af0992020-01-12 12:59:52 +0100230 LOGPIL(line, DLINP, LOGL_NOTICE, "line update (line=%p)\n", line);
Alexander Couzensbeb10ef2016-11-01 22:05:13 +0100231
232 if (!line->driver_data)
233 line->driver_data = talloc_zero(line, struct unixsocket_line);
234
235 if (!line->driver_data) {
Harald Welteb5af0992020-01-12 12:59:52 +0100236 LOGPIL(line, DLINP, LOGL_ERROR, "OOM in line update (line=%p)\n", line);
Alexander Couzensbeb10ef2016-11-01 22:05:13 +0100237 return -ENOMEM;
238 }
239
240 config = line->driver_data;
Alexander Couzensbeb10ef2016-11-01 22:05:13 +0100241
242 /* Open unix domain socket */
Stefan Sperlingb24efa52018-08-28 14:03:41 +0200243 if (line->sock_path == NULL) {
Stefan Sperling0d7d0b02018-09-20 17:34:31 +0200244 ret = snprintf(un.sun_path, sizeof(un.sun_path), "%s%d",
245 UNIXSOCKET_SOCK_PATH_DEFAULT, line->num);
246 if (ret == -1) {
Harald Welteb5af0992020-01-12 12:59:52 +0100247 LOGPIL(line, DLINP, LOGL_ERROR, "Cannot create default socket path: %s\n", strerror(errno));
Stefan Sperling0d7d0b02018-09-20 17:34:31 +0200248 return -errno;
249 } else if (ret >= sizeof(un.sun_path)) {
Harald Welteb5af0992020-01-12 12:59:52 +0100250 LOGPIL(line, DLINP, LOGL_ERROR, "Default socket path exceeds %zd bytes: %s%d\n",
Stefan Sperling0d7d0b02018-09-20 17:34:31 +0200251 sizeof(un.sun_path), UNIXSOCKET_SOCK_PATH_DEFAULT, line->num);
252 return -ENOSPC;
253 }
254 sock_path = un.sun_path;
Stefan Sperlingb24efa52018-08-28 14:03:41 +0200255 } else
256 sock_path = line->sock_path;
Alexander Couzensbeb10ef2016-11-01 22:05:13 +0100257 ret = osmo_sock_unix_init(SOCK_SEQPACKET, 0, sock_path,
258 OSMO_SOCK_F_CONNECT);
259 if (ret < 0) {
260 /* Note: We will not free the allocated driver_data memory if
261 * opening the socket fails. The caller may want to call this
262 * function multiple times using config->fd.data as line
263 * parameter. Freeing now would destroy that reference. */
Harald Welteb5af0992020-01-12 12:59:52 +0100264 LOGPIL(line, DLINP, LOGL_ERROR, "unable to open socket: %s (line=%p, fd=%d)\n", sock_path,
265 line, config->fd.fd);
Alexander Couzensbeb10ef2016-11-01 22:05:13 +0100266 return ret;
267 }
Harald Welteb5af0992020-01-12 12:59:52 +0100268 LOGPIL(line, DLINP, LOGL_DEBUG, "successfully opend (new) socket: %s (line=%p, fd=%d, ret=%d)\n",
269 sock_path, line, config->fd.fd, ret);
Harald Welte6e831b72020-10-18 22:59:58 +0200270 osmo_fd_setup(&config->fd, ret, OSMO_FD_READ, unixsocket_cb, line, 0);
Alexander Couzensbeb10ef2016-11-01 22:05:13 +0100271
272 /* Register socket in select loop */
273 if (osmo_fd_register(&config->fd) < 0) {
Harald Welteb5af0992020-01-12 12:59:52 +0100274 LOGPIL(line, DLINP, LOGL_ERROR, "error registering new socket (line=%p, fd=%d)\n",
275 line, config->fd.fd);
Alexander Couzensbeb10ef2016-11-01 22:05:13 +0100276 close(config->fd.fd);
277 return -EIO;
278 }
279
280 /* Set line parameter */
281 for (i = 0; i < ARRAY_SIZE(line->ts); i++) {
282 struct e1inp_ts *e1i_ts = &line->ts[i];
Harald Welteb9031882020-05-02 21:09:15 +0200283 char name[32];
Alexander Couzensbeb10ef2016-11-01 22:05:13 +0100284 if (!e1i_ts->lapd) {
Harald Welteb9031882020-05-02 21:09:15 +0200285 e1inp_ts_name(name, sizeof(name), e1i_ts);
286 e1i_ts->lapd = lapd_instance_alloc2(1,
Alexander Couzensbeb10ef2016-11-01 22:05:13 +0100287 unixsocket_write_msg_lapd_cb, &config->fd,
Harald Welteb9031882020-05-02 21:09:15 +0200288 e1inp_dlsap_up, e1i_ts, &lapd_profile_abis, name);
Alexander Couzensbeb10ef2016-11-01 22:05:13 +0100289 }
290 }
291
292 /* Ensure ericsson-superchannel is turned of when
293 * a new connection is made */
294 e1inp_ericsson_set_altc(line, 0);
295
296 return ret;
297}
298
299struct e1inp_driver unixsocket_driver = {
300 .name = "unixsocket",
301 .want_write = ts_want_write,
302 .line_update = unixsocket_line_update,
303 .default_delay = 0,
304};
305
306void e1inp_unixsocket_init(void)
307{
308 tall_unixsocket_ctx = talloc_named_const(libosmo_abis_ctx, 1, "unixsocket");
309 e1inp_driver_register(&unixsocket_driver);
310}
311
312void e1inp_ericsson_set_altc(struct e1inp_line *unixline, int superchannel)
313{
314 struct unixsocket_line *config;
315 struct msgb *msg;
316
317 if (!unixline)
318 return;
319
320 if (unixline->driver != &unixsocket_driver) {
Harald Welteb5af0992020-01-12 12:59:52 +0100321 LOGPIL(unixline, DLMI, LOGL_NOTICE, "altc is only supported by unixsocket\n");
Alexander Couzensbeb10ef2016-11-01 22:05:13 +0100322 return;
323 }
324
325 config = unixline->driver_data;
326 if (!config) {
Harald Welteb5af0992020-01-12 12:59:52 +0100327 LOGPIL(unixline, DLMI, LOGL_NOTICE, "e1inp driver not yet initialized.\n");
Alexander Couzensbeb10ef2016-11-01 22:05:13 +0100328 return;
329 }
330
331
332 msg = msgb_alloc_headroom(200, 100, "ALTC");
333
334 /* version header */
335 msgb_put_u8(msg, UNIXSOCKET_PROTO_VERSION);
336 /* data|control */
337 msgb_put_u8(msg, UNIXSOCKET_PROTO_CONTROL);
338
339 /* magic */
340 msgb_put_u32(msg, 0x23004200);
341 msgb_put_u8(msg, superchannel ? 1 : 0);
342
343 unixsocket_write_msg(msg, &config->fd);
344}
345