diff --git a/configure.ac b/configure.ac index 5a83eb1..35b8328 100644 --- a/configure.ac +++ b/configure.ac @@ -75,6 +75,27 @@ else AC_MSG_WARN([DAHDI input driver will not be built]) fi +AC_ARG_ENABLE([e1d], + [AS_HELP_STRING( + [--enable-e1d], + [Enable osmo-e1d driver support] + )], + [ + ENABLE_E1D=$enableval + ], + [ + ENABLE_E1D="no" + ]) +AS_IF([test "x$ENABLE_E1D" = "xyes"], [ + PKG_CHECK_MODULES(LIBOSMOE1D, libosmo-e1d) +]) +AM_CONDITIONAL(ENABLE_E1D, test "x$ENABLE_E1D" = "xyes") +AC_SUBST(ENABLE_E1D) +if test x"$ENABLE_E1D" = x"yes" +then + AC_DEFINE([HAVE_E1D], [1], [Enable osmo-e1d driver support]) +fi + AC_ARG_ENABLE(sanitize, [AS_HELP_STRING( [--enable-sanitize], diff --git a/include/osmocom/abis/e1_input.h b/include/osmocom/abis/e1_input.h index de1c504..00b4aaa 100644 --- a/include/osmocom/abis/e1_input.h +++ b/include/osmocom/abis/e1_input.h @@ -128,6 +128,10 @@ struct e1inp_ts { /* DAHDI driver has one fd for each ts */ struct osmo_fd fd; } dahdi; + struct { + /* osmo-e1d driver has one fd for each ts */ + struct osmo_fd fd; + } e1d; struct { struct osmo_fd fd; } rs232; diff --git a/src/Makefile.am b/src/Makefile.am index 5ae94e4..3838a5a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -5,9 +5,9 @@ ABIS_LIBVERSION=8:0:2 TRAU_LIBVERSION=4:0:2 AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir) -AM_CFLAGS= -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(COVERAGE_CFLAGS) +AM_CFLAGS= -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(LIBOSMOE1D_CFLAGS) $(COVERAGE_CFLAGS) AM_LDFLAGS = $(COVERAGE_LDFLAGS) -COMMONLIBS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) +COMMONLIBS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOSMOE1D_LIBS) lib_LTLIBRARIES = libosmoabis.la libosmotrau.la @@ -19,6 +19,7 @@ libosmoabis_la_SOURCES = init.c \ ipa_proxy.c \ subchan_demux.c \ trau_frame.c \ + input/e1d.c \ input/ipa.c \ input/ipa_keepalive.c \ input/ipaccess.c \ diff --git a/src/e1_input.c b/src/e1_input.c index a707438..cb1612d 100644 --- a/src/e1_input.c +++ b/src/e1_input.c @@ -889,6 +889,9 @@ void e1inp_init(void) e1inp_misdn_init(); #ifdef HAVE_DAHDI_USER_H e1inp_dahdi_init(); +#endif +#ifdef ENABLE_E1D + e1inp_e1d_init(); #endif e1inp_ipaccess_init(); e1inp_rs232_init(); diff --git a/src/e1_input_vty.c b/src/e1_input_vty.c index d81c859..a1943e6 100644 --- a/src/e1_input_vty.c +++ b/src/e1_input_vty.c @@ -41,7 +41,7 @@ /* CONFIG */ -#define E1_DRIVER_NAMES "(misdn|misdn_lapd|dahdi|ipa|unixsocket)" +#define E1_DRIVER_NAMES "(misdn|misdn_lapd|dahdi|e1d|ipa|unixsocket)" #define E1_DRIVER_HELP "mISDN supported E1 Card (kernel LAPD)\n" \ "mISDN supported E1 Card (userspace LAPD)\n" \ "DAHDI supported E1/T1/J1 Card\n" \ diff --git a/src/input/e1d.c b/src/input/e1d.c new file mode 100644 index 0000000..ceeb0c2 --- /dev/null +++ b/src/input/e1d.c @@ -0,0 +1,280 @@ +/* OpenBSC Abis input driver for osmo-e1d */ + +/* (C) 2019 by Sylvain Munaut + * + * All Rights Reserved + * + * SPDX-License-Identifier: GPL-2.0+ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include "config.h" + +#ifdef HAVE_E1D + +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + +#include +#include + + +#define TS_SIGN_ALLOC_SIZE 300 + +struct osmo_e1dp_client *g_e1d; + +/* pre-declaration */ +extern struct e1inp_driver e1d_driver; +static int e1d_want_write(struct e1inp_ts *e1i_ts); + + +static int +handle_ts_sign_read(struct osmo_fd *bfd) +{ + struct e1inp_line *line = bfd->data; + unsigned int ts_nr = bfd->priv_nr; + struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1]; + struct msgb *msg = msgb_alloc(TS_SIGN_ALLOC_SIZE, "E1D Signaling TS"); + int ret; + + if (!msg) + return -ENOMEM; + + ret = read(bfd->fd, msg->data, TS_SIGN_ALLOC_SIZE - 16); + if (ret < 0) { + perror("read "); + return ret; + } + + msgb_put(msg, ret); + if (ret <= 1) { + perror("read "); + return ret; + } + + return e1inp_rx_ts_lapd(e1i_ts, msg); +} + +static void +timeout_ts_sign_write(void *data) +{ + struct e1inp_ts *e1i_ts = (struct e1inp_ts *)data; + + /* trigger write of ts1, due to tx delay timer */ + e1d_want_write(e1i_ts); +} + +static int +handle_ts_sign_write(struct osmo_fd *bfd) +{ + struct e1inp_line *line = bfd->data; + unsigned int ts_nr = bfd->priv_nr; + struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1]; + struct e1inp_sign_link *sign_link; + struct msgb *msg; + + bfd->when &= ~BSC_FD_WRITE; + + /* get the next msg for this timeslot */ + msg = e1inp_tx_ts(e1i_ts, &sign_link); + if (!msg) { + /* no message after tx delay timer */ + return 0; + } + + DEBUGP(DLMI, "TX: %s\n", osmo_hexdump(msg->data, msg->len)); + lapd_transmit(e1i_ts->lapd, sign_link->tei, + sign_link->sapi, msg); + + /* set tx delay timer for next event */ + osmo_timer_setup(&e1i_ts->sign.tx_timer, timeout_ts_sign_write, e1i_ts); + osmo_timer_schedule(&e1i_ts->sign.tx_timer, 0, 50000); + + return 0; +} + + +static void +e1d_write_msg(struct msgb *msg, void *cbdata) +{ + struct osmo_fd *bfd = cbdata; + struct e1inp_line *line = bfd->data; + unsigned int ts_nr = bfd->priv_nr; + struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1]; + int ret; + + ret = write(bfd->fd, msg->data, msg->len); + msgb_free(msg); + if (ret < 0) + LOGP(DLMI, LOGL_NOTICE, "%s write failed %d\n", __func__, ret); +} + +static int +e1d_fd_cb(struct osmo_fd *bfd, unsigned int what) +{ + struct e1inp_line *line = bfd->data; + unsigned int ts_nr = bfd->priv_nr; + unsigned int idx = ts_nr-1; + struct e1inp_ts *e1i_ts = &line->ts[idx]; + int ret = 0; + + switch (e1i_ts->type) { + case E1INP_TS_TYPE_SIGN: + //if (what & BSC_FD_EXCEPT) + //FIXME: what to do ?!?! + if (what & BSC_FD_READ) + ret = handle_ts_sign_read(bfd); + if (what & BSC_FD_WRITE) + ret = handle_ts_sign_write(bfd); + break; + default: + LOGP(DLINP, LOGL_NOTICE, + "unknown/unsupported E1 TS type %u\n", e1i_ts->type); + break; + } + + return ret; +} + + +static int +e1d_want_write(struct e1inp_ts *e1i_ts) +{ + /* We never include the DAHDI B-Channel FD into the writeset */ + if (e1i_ts->type == E1INP_TS_TYPE_TRAU) { + LOGP(DLINP, LOGL_DEBUG, "Trying to write TRAU ts\n"); + return 0; + } + + e1i_ts->driver.e1d.fd.when |= BSC_FD_WRITE; + + return 0; +} + +static int +e1d_line_update(struct e1inp_line *line) +{ + int ts; + int ret; + + if (line->driver != &e1d_driver) + return -EINVAL; + + + LOGP(DLINP, LOGL_ERROR, "Line update %d %d %d\n", line->num, line->port_nr, line->num_ts); + + for (ts=1; tsnum_ts; ts++) + { + unsigned int idx = ts-1; + struct e1inp_ts *e1i_ts = &line->ts[idx]; + struct osmo_fd *bfd = &e1i_ts->driver.e1d.fd; + + /* unregister FD if it was already registered */ + if (bfd->list.next && bfd->list.next != LLIST_POISON1) + osmo_fd_unregister(bfd); + + bfd->data = line; + bfd->priv_nr = ts; + bfd->cb = e1d_fd_cb; + + switch (e1i_ts->type) { + case E1INP_TS_TYPE_NONE: + /* close/release LAPD instance, if any */ + if (e1i_ts->lapd) { + lapd_instance_free(e1i_ts->lapd); + e1i_ts->lapd = NULL; + } + if (bfd->fd) { + close(bfd->fd); + bfd->fd = 0; + } + continue; + case E1INP_TS_TYPE_SIGN: + if (bfd->fd <= 0) + bfd->fd = osmo_e1dp_client_ts_open(g_e1d, 0, 0, ts, E1DP_TSMODE_HDLCFCS); + if (bfd->fd < 0) { + LOGP(DLINP, LOGL_ERROR, + "Could not open timeslot %d\n", ts); + return -EIO; + } + bfd->when = BSC_FD_READ | BSC_FD_EXCEPT; + + if (!e1i_ts->lapd) + e1i_ts->lapd = lapd_instance_alloc(1, + e1d_write_msg, bfd, e1inp_dlsap_up, + e1i_ts, &lapd_profile_abis); + break; + case E1INP_TS_TYPE_HDLC: + break; + case E1INP_TS_TYPE_TRAU: + break; + case E1INP_TS_TYPE_RAW: + break; + }; + + ret = osmo_fd_register(bfd); + if (ret < 0) { + LOGP(DLINP, LOGL_ERROR, + "could not register FD: %s\n", + strerror(ret)); + return ret; + } + } + + return 0; +} + +static void +e1d_vty_show(struct vty *vty, struct e1inp_line *line) +{ + /* FIXME */ + vty_out(vty, "Not supported yet%s", VTY_NEWLINE); +} + + +struct e1inp_driver e1d_driver = { + .name = "e1d", + .want_write = e1d_want_write, + .line_update = e1d_line_update, + .vty_show = e1d_vty_show, +}; + +int +e1inp_e1d_init(void) +{ + /* Connect to daemon */ + g_e1d = osmo_e1dp_client_create(NULL, "/tmp/osmo-e1d.ctl"); + if (!g_e1d) { + LOGP(DLINP, LOGL_ERROR, "Unable to connect to osmo-e1d daemon\n"); + return -EPIPE; + } + + /* register the driver with the core */ + return e1inp_driver_register(&e1d_driver); +} + +#endif /* HAVE_E1D */