laforge has submitted this change. ( 
https://gerrit.osmocom.org/c/osmo-e1d/+/30068 )

Change subject: DAHDI trunkdev support
......................................................................

DAHDI trunkdev support

DAHDI trunkdev is a newly-introduced 'virtual trunk' character device
which is used instead of a real hardware driver. This means that an
application (such as osmo-e1d) can implement a virtual E1 trunk and
receive and transmit E1 frame data which is exposed to DAHDI users
just like the data from a real physical E1 span.

In order to build DAHDI trunkdev support into osmo-e1d, you will need
a special fork of dahdi containing the required support, currently
the laforge/trunkdev branch of the following repository:
        https://gitea.osmocom.org/retronetworking/dahdi-linux

Change-Id: Ib15a7313fcd63e1ed9f2f5b349df967bc4335ec2
---
M configure.ac
M include/osmocom/octoi/octoi.h
M src/Makefile.am
A src/dahdi_trunkdev.c
M src/e1d.h
M src/e1oip.c
M src/intf_line.c
M src/log.c
M src/log.h
M src/octoi/octoi.c
M src/octoi/octoi_clnt_vty.c
M src/octoi/octoi_srv_fsm.c
M src/octoi/octoi_srv_vty.c
M src/octoi/octoi_vty.h
M src/vty.c
15 files changed, 490 insertions(+), 15 deletions(-)

Approvals:
  Jenkins Builder: Verified
  laforge: Looks good to me, approved



diff --git a/configure.ac b/configure.ac
index 2cf5a9f..456375c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -75,6 +75,21 @@
        CPPFLAGS="$CPPFLAGS $WERROR_FLAGS"
 fi

+AC_ARG_ENABLE(dahdi-trunkdev,
+       [AS_HELP_STRING(
+               [--enable-dahdi-trunkdev],
+               [Enable support for DAHDI trunkdev [default=no]],
+       )],
+       [ENABLE_DAHDI_TRUNKDEV=$enableval], [ENABLE_DAHDI_TRUNKDEV="no"])
+if test x"$ENABLE_DAHDI_TRUNKDEV" = x"yes"
+then
+       AC_CHECK_TYPE(struct dahdi_trunkdev_open,
+             [AC_DEFINE(HAVE_DAHDI_TRUNKDEV)],
+             [AC_MSG_ERROR("Cannot build requested trunkdev support without 
matching DAHDI headers")],
+             [[#include <dahdi/user.h>]])
+fi
+AM_CONDITIONAL(ENABLE_DAHDI_TRUNKDEV, test "x$ENABLE_DAHDI_TRUNKDEV" = "xyes")
+AC_SUBST(ENABLE_DAHDI_TRUNKDEV)

 # Generate manuals
 AC_ARG_ENABLE(manuals,
diff --git a/include/osmocom/octoi/octoi.h b/include/osmocom/octoi/octoi.h
index c9fa3d5..fddee41 100644
--- a/include/osmocom/octoi/octoi.h
+++ b/include/osmocom/octoi/octoi.h
@@ -11,7 +11,7 @@
        ACCOUNT_MODE_NONE,
        ACCOUNT_MODE_ICE1USB,
        ACCOUNT_MODE_REDIRECT,
-       ACCOUNT_MODE_DAHDI,
+       ACCOUNT_MODE_DAHDI_TRUNKDEV,
 };

 extern const struct value_string octoi_account_mode_name[];
@@ -32,8 +32,9 @@
                        struct osmo_sockaddr_str to;    /* remote IP/port to 
which to redirect */
                } redirect;
                struct {
-                                                       /* TBD */
-               } dahdi;
+                       char *name;                     /* DAHDI trunkdev name 
*/
+                       uint8_t line_nr;                /* line number inside 
icE1usb */
+               } dahdi_trunkdev;
        } u;
 };

@@ -71,6 +72,8 @@
                                   struct octoi_account *acc);
        /* OCTOI library notifies the application that a given peer has 
disconnected */
        void (*peer_disconnected)(struct octoi_peer *peer);
+       /* OCTOI library notifies the application that a given client has been 
updated */
+       void (*client_updated)(struct octoi_client *client);
 };

 struct octoi_daemon {
diff --git a/src/Makefile.am b/src/Makefile.am
index 2cc8a8f..e609a1f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -76,3 +76,8 @@
        usb.c \
        vty.c \
        $(NULL)
+
+if ENABLE_DAHDI_TRUNKDEV
+osmo_e1d_SOURCES += dahdi_trunkdev.c
+osmo_e1gen_SOURCES += dahdi_trunkdev.c
+endif
diff --git a/src/dahdi_trunkdev.c b/src/dahdi_trunkdev.c
new file mode 100644
index 0000000..11c5b9f
--- /dev/null
+++ b/src/dahdi_trunkdev.c
@@ -0,0 +1,233 @@
+/*
+ * trunkdev.c
+ *
+ * (C) 2022 by Harald Welte <[email protected]>
+ *
+ * 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.
+ */
+
+#include <errno.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <string.h>
+#include <talloc.h>
+#include <fcntl.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+#include <osmocom/core/utils.h>
+
+#include <dahdi/user.h>
+
+#include "e1d.h"
+#include "log.h"
+
+/***********************************************************************
+ * low-level trunkdev routines
+ ***********************************************************************/
+
+static int trunkdev_specify(int fd, const char *name)
+{
+       struct dahdi_trunkdev_open td_o = { 0 };
+
+       OSMO_STRLCPY_ARRAY(td_o.name, name);
+
+       return ioctl(fd, DAHDI_TRUNKDEV_OPEN, &td_o);
+}
+
+/***********************************************************************
+ * osmo-e1d interface
+ ***********************************************************************/
+
+/* default dahdi chunk size: 8 chunks (in this case E1 frames) per read/write 
*/
+#define DAHDI_CHUNKSIZE                8
+#define BYTES_PER_FRAME                32
+
+/* one E1 line (DAHDI span) inside the trunkdev */
+struct e1_trunkdev_line_data {
+       unsigned int basechan;          /* so far, only 0 supported */
+       unsigned int numchans;          /* so far, onlt 32 supported */
+};
+
+/* one DAHDI trunkdev */
+struct e1_trunkdev_intf_data {
+       /* file descriptor to the character device /dev/dahdi/trunkdev */
+       struct osmo_fd ofd;
+};
+
+/* file-descriptor call-back.  Triggered by DAHDI via poll(), whenever
+ * there is new E1 frame data available to read from trunkdev.  The flow
+ * control in transmit side is simple: We write as * many frames as we are 
reading */
+static int dahdi_trunkdev_fd_cb(struct osmo_fd *ofd, unsigned int what)
+{
+       struct e1_intf *e1i = ofd->data;
+       struct e1_line *e1l = e1_intf_find_line(e1i, 0);
+       uint8_t buf[DAHDI_CHUNKSIZE*BYTES_PER_FRAME];
+       int rc, len;
+
+       OSMO_ASSERT(what & OSMO_FD_READ);
+
+       len = read(ofd->fd, buf, sizeof(buf));
+       if (len <= 0) {
+               LOGPIF(e1i, DTRUNKDEV, LOGL_ERROR, "Error %d during trunkdev 
read: %s\n", len,
+                       strerror(errno));
+               return len;
+       } else if (len < (int) sizeof(buf)) {
+               /* for some not yet known reason this happens quite often, 
typically 244 of 256 bytes,
+                * followed by the remaining 32 bytes in the next read.  No 
data is lost, it just
+                * costs a lot of extra syscalls / context switches */
+               LOGPIF(e1i, DTRUNKDEV, LOGL_DEBUG, "Short read during trunkdev 
read: %d < %zu\n",
+                       len, sizeof(buf));
+       }
+       if (len % BYTES_PER_FRAME) {
+               LOGPIF(e1i, DTRUNKDEV, LOGL_ERROR, "Odd number of bytes during 
read: %d\n", len);
+               return -EIO;
+       }
+
+       if (!e1l) {
+               /* no line: discard input; transmit all-ff (BLUE) */
+               memset(buf, 0xff, len);
+       } else {
+               /* DAHDI trunkdev currently only supports one span/line per 
trunk */
+               rc = e1_line_demux_in(e1l, buf, len, -1);
+#if 0
+               if (rc < 0) {
+                       LOGPLI(e1l, DTRUNKDEV, LOGL_ERROR, "Error %d during 
e1_line_demux_in()\n", rc);
+                       return rc;
+               }
+#endif
+               /* only pull as many frames out of our muxer as we have just 
read from the trunk */
+               len = e1_line_mux_out(e1l, buf, len/BYTES_PER_FRAME);
+               if (len < 0) {
+                       LOGPLI(e1l, DTRUNKDEV, LOGL_ERROR, "Error %d during 
mux_out\n", len);
+                       return len;
+               }
+       }
+
+       rc = write(ofd->fd, buf, len);
+       if (rc <= 0) {
+               LOGPIF(e1i, DTRUNKDEV, LOGL_ERROR, "Error %d during trunkdev 
write: %s\n", rc,
+                       strerror(errno));
+               return rc;
+       } else if (rc < len) {
+               LOGPIF(e1i, DTRUNKDEV, LOGL_ERROR, "Short write during trunkdev 
write: %d < %d\n",
+                       rc, len);
+       }
+
+       return 0;
+}
+
+
+int
+e1_dahdi_trunkdev_open(struct e1_intf *e1i)
+{
+       struct dahdi_trunkdev_create _cr;
+       struct e1_trunkdev_intf_data *tid;
+       struct e1_line *e1l;
+       int rc, fd;
+
+       /* various sanity checks */
+
+       if (e1i->drv != E1_DRIVER_DAHDI_TRUNKDEV) {
+               LOGPIF(e1i, DTRUNKDEV, LOGL_ERROR, "Cannot open non-trunkdev 
trunk as trunkdev\n");
+               return -EINVAL;
+       }
+
+       if (!e1i->dahdi_trunkdev.name) {
+               LOGPIF(e1i, DTRUNKDEV, LOGL_ERROR, "Cannot open trunkdev 
without name\n");
+               return -EINVAL;
+       }
+
+       if (strlen(e1i->dahdi_trunkdev.name) > sizeof(_cr.name)-1) {
+               LOGPIF(e1i, DTRUNKDEV, LOGL_ERROR, "Cannot open trunkdev with 
excessively long name\n");
+               return -EINVAL;
+       }
+
+       if (e1i->drv_data) {
+               LOGPIF(e1i, DTRUNKDEV, LOGL_NOTICE, "Cannot open trunkdev 
that's already open\n");
+               return -EBUSY;
+       }
+
+       /* open the trunkdev */
+       fd = open("/dev/dahdi/trunkdev", O_RDWR);
+       if (fd < 0) {
+               LOGPIF(e1i, DTRUNKDEV, LOGL_ERROR, "Cannot open 
/dev/dahdi/trunkdev: %s\n",
+                       strerror(errno));
+               return -errno;
+       }
+
+       /* try to select the trunk by name */
+       rc = trunkdev_specify(fd, e1i->dahdi_trunkdev.name);
+       if (rc < 0) {
+               LOGPIF(e1i, DTRUNKDEV, LOGL_ERROR, "Unable to specify trunkdev 
'%s': %s\n",
+                       e1i->dahdi_trunkdev.name, strerror(errno));
+               /* TODO: auto- create on demand? */
+               close(fd);
+               return -errno;
+       }
+
+       LOGPIF(e1i, DTRUNKDEV, LOGL_NOTICE, "Successfully opened trunkdev 
'%s'\n", e1i->dahdi_trunkdev.name);
+       tid = talloc_zero(e1i->e1d->ctx, struct e1_trunkdev_intf_data);
+       OSMO_ASSERT(tid);
+       osmo_fd_setup(&tid->ofd, fd, OSMO_FD_READ, dahdi_trunkdev_fd_cb, e1i, 
e1i->id);
+       osmo_fd_register(&tid->ofd);
+       e1i->drv_data = tid;
+
+       /* ensure line0 exists */
+       if (!e1_intf_find_line(e1i, 0)) {
+               e1l = e1_line_new(e1i, 0, NULL);
+               e1l->mode = E1_LINE_MODE_E1OIP;
+       }
+
+       /* activate line */
+       llist_for_each_entry(e1l, &e1i->lines, list)
+               e1_line_active(e1l);
+
+       return 0;
+}
+
+int
+e1_dahdi_trunkdev_close(struct e1_intf *e1i)
+{
+       struct e1_trunkdev_intf_data *tid = e1i->drv_data;
+       int rc;
+
+       if (e1i->drv != E1_DRIVER_DAHDI_TRUNKDEV) {
+               LOGPIF(e1i, DTRUNKDEV, LOGL_ERROR, "Cannot close non-trunkdev 
trunk as trunkdev\n");
+               return -EINVAL;
+       }
+
+       if (!tid) {
+               LOGPIF(e1i, DTRUNKDEV, LOGL_DEBUG, "No need to close trunkdev; 
was not open\n");
+               return 0;
+       }
+
+       osmo_fd_unregister(&tid->ofd);
+
+       /* we're not deleting the dahdi trunkdev as that might upset the 
applications using
+        * the channel-side of it */
+       rc = close(tid->ofd.fd);
+       if (rc < 0)
+               LOGPIF(e1i, DTRUNKDEV, LOGL_ERROR, "Error closing trunkdev: 
%s\n", strerror(errno));
+
+       talloc_free(tid);
+       e1i->drv_data = tid = NULL;
+
+       LOGPIF(e1i, DTRUNKDEV, LOGL_NOTICE, "Closed trunkdev '%s'\n", 
e1i->dahdi_trunkdev.name);
+
+       return 0;
+}
diff --git a/src/e1d.h b/src/e1d.h
index 82c9bb6..1c7c4c4 100644
--- a/src/e1d.h
+++ b/src/e1d.h
@@ -161,6 +161,7 @@
 enum e1_driver {
        E1_DRIVER_USB,
        E1_DRIVER_VPAIR,
+       E1_DRIVER_DAHDI_TRUNKDEV,
 };

 extern const struct value_string e1_driver_names[];
@@ -180,6 +181,9 @@
                        uint16_t fine;
                } gpsdo;
        } usb;
+       struct {
+               char *name;
+       } dahdi_trunkdev;

        bool vty_created;
        enum e1_driver drv;
@@ -210,6 +214,9 @@
 struct e1_intf *
 e1d_find_intf_by_usb_serial(struct e1_daemon *e1d, const char *serial_str);

+struct e1_intf *
+e1d_find_intf_by_trunkdev_name(struct e1_daemon *e1d, const char *name);
+
 void
 e1_intf_destroy(struct e1_intf *intf);

@@ -244,6 +251,14 @@
 struct e1_intf *
 e1d_vpair_intf_peer(struct e1_intf *intf);

+#ifdef HAVE_DAHDI_TRUNKDEV
+int
+e1_dahdi_trunkdev_open(struct e1_intf *e1i);
+
+int
+e1_dahdi_trunkdev_close(struct e1_intf *e1i);
+#endif
+
 int
 e1oip_line_demux_in(struct e1_line *line, const uint8_t *buf, int ftr);

diff --git a/src/e1oip.c b/src/e1oip.c
index 384a91b..86172d0 100644
--- a/src/e1oip.c
+++ b/src/e1oip.c
@@ -48,6 +48,16 @@
        return e1_intf_find_line(e1i, id);
 }

+/* convenience helper function finding a e1_line for given name + id */
+static struct e1_line *
+find_line_by_trunkdev_name(struct e1_daemon *e1d, const char *name, uint8_t id)
+{
+       struct e1_intf *e1i = e1d_find_intf_by_trunkdev_name(e1d, name);
+       if (!e1i)
+               return NULL;
+       return e1_intf_find_line(e1i, id);
+}
+
 static struct e1_line *
 find_line_for_account(struct e1_daemon *e1d, const struct octoi_account *acc)
 {
@@ -55,8 +65,9 @@
        case ACCOUNT_MODE_ICE1USB:
                return find_line_by_usb_serial(e1d, acc->u.ice1usb.usb_serial,
                                                acc->u.ice1usb.line_nr);
-       case ACCOUNT_MODE_DAHDI:
-               OSMO_ASSERT(0);         /* TODO */
+       case ACCOUNT_MODE_DAHDI_TRUNKDEV:
+               return find_line_by_trunkdev_name(e1d, 
acc->u.dahdi_trunkdev.name,
+                                                 
acc->u.dahdi_trunkdev.line_nr);
                break;
        default:
                return NULL;
@@ -127,6 +138,35 @@
        return line;
 }

+static void
+_e1d_octoi_client_updated_cb(struct octoi_client *clnt)
+{
+       struct e1_daemon *e1d = g_octoi->priv;
+       struct e1_line *line;
+
+       /* find line for client */
+       line = find_line_for_account(e1d, clnt->cfg.account);
+       if (!line)
+               return;
+
+       if (line->mode != E1_LINE_MODE_E1OIP)
+               return;
+
+       /* check if line is active */
+       if (!osmo_timer_pending(&line->ts0.timer))
+               return;
+
+       /* TODO: kill old peer, if != current peer */
+       if (!line->octoi_peer)
+               line->octoi_peer = octoi_client_get_peer(clnt);
+       else
+               OSMO_ASSERT(line->octoi_peer == octoi_client_get_peer(clnt));
+
+       /* start client for peer (if not started) */
+       OSMO_ASSERT(line->octoi_peer);
+       octoi_clnt_start_for_peer(line->octoi_peer, clnt->cfg.account);
+}
+
 /* OCTOI has detected that a given peer has vanished; delete reference to it */
 static void
 _e1d_octoi_peer_disconnected_cb(struct octoi_peer *peer)
@@ -148,5 +188,6 @@

 const struct octoi_ops e1d_octoi_ops = {
        .client_connected = &_e1d_octoi_client_connected_cb,
+       .client_updated = &_e1d_octoi_client_updated_cb,
        .peer_disconnected = &_e1d_octoi_peer_disconnected_cb,
 };
diff --git a/src/intf_line.c b/src/intf_line.c
index 811b8fe..3895653 100644
--- a/src/intf_line.c
+++ b/src/intf_line.c
@@ -46,6 +46,7 @@
 const struct value_string e1_driver_names[] = {
        { E1_DRIVER_USB, "usb" },
        { E1_DRIVER_VPAIR, "vpair" },
+       { E1_DRIVER_DAHDI_TRUNKDEV, "dahdi-trunkdev" },
        { 0, NULL }
 };

@@ -133,6 +134,22 @@
        return NULL;
 }

+struct e1_intf *
+e1d_find_intf_by_trunkdev_name(struct e1_daemon *e1d, const char *name)
+{
+       struct e1_intf *intf;
+
+       if (!name)
+               return NULL;
+
+       llist_for_each_entry(intf, &e1d->interfaces, list) {
+               if (intf->dahdi_trunkdev.name && 
!strcmp(intf->dahdi_trunkdev.name, name))
+                       return intf;
+       }
+
+       return NULL;
+}
+
 struct e1_line *
 e1_intf_find_line(struct e1_intf *intf, uint8_t id)
 {
@@ -300,6 +317,11 @@
                            line->id == acc->u.ice1usb.line_nr)
                                return clnt;
                        break;
+               case ACCOUNT_MODE_DAHDI_TRUNKDEV:
+                       if (!strcmp(line->intf->dahdi_trunkdev.name, 
acc->u.dahdi_trunkdev.name) &&
+                           line->id == acc->u.dahdi_trunkdev.line_nr)
+                               return clnt;
+                       break;
                case ACCOUNT_MODE_NONE:
                case ACCOUNT_MODE_REDIRECT:
                        break;
diff --git a/src/log.c b/src/log.c
index e2b90dc..fd25616 100644
--- a/src/log.c
+++ b/src/log.c
@@ -38,6 +38,12 @@
                .loglevel = LOGL_NOTICE,
                .enabled = 1,
        },
+       [DTRUNKDEV] = {
+               .name = "DTRUNKDEV",
+               .description = "DAHDI trunkdev driver",
+               .loglevel = LOGL_NOTICE,
+               .enabled = 1,
+       },
 };

 const struct log_info log_info = {
diff --git a/src/log.h b/src/log.h
index d46a5a7..fe5c99b 100644
--- a/src/log.h
+++ b/src/log.h
@@ -29,6 +29,7 @@
 enum {
        DE1D,
        DXFR,
+       DTRUNKDEV,
 };
 
 #define LOGPIF(itf, ss, lvl, fmt, args...) \
diff --git a/src/octoi/octoi.c b/src/octoi/octoi.c
index 8d82092..6e4b8f9 100644
--- a/src/octoi/octoi.c
+++ b/src/octoi/octoi.c
@@ -43,6 +43,7 @@
 int octoi_vty_go_parent(struct vty *vty)
 {
        struct octoi_account *acc;
+       struct octoi_client *clnt;

        switch (vty->node) {
        case OCTOI_ACCOUNT_NODE:
@@ -54,6 +55,14 @@
                vty->node = OCTOI_CLNT_NODE;
                vty->index = client4account(acc);
                break;
+       case OCTOI_CLNT_NODE:
+               clnt = vty->index;
+               /* check if we have a (new?) line for this client */
+               if (g_octoi->ops->client_updated)
+                       g_octoi->ops->client_updated(clnt);
+               vty->node = CONFIG_NODE;
+               vty->index = NULL;
+               break;
        default:
                vty->node = CONFIG_NODE;
                vty->index = NULL;
diff --git a/src/octoi/octoi_clnt_vty.c b/src/octoi/octoi_clnt_vty.c
index ff50ddb..c7c2482 100644
--- a/src/octoi/octoi_clnt_vty.c
+++ b/src/octoi/octoi_clnt_vty.c
@@ -281,6 +281,10 @@
        install_element(OCTOI_CLNT_ACCOUNT_NODE, &cfg_account_mode_cmd);
        install_element(OCTOI_CLNT_ACCOUNT_NODE, 
&cfg_account_batching_factor_cmd);
        install_element(OCTOI_CLNT_ACCOUNT_NODE, 
&cfg_account_prefill_frame_count_cmd);
+#ifdef HAVE_DAHDI_TRUNKDEV
+       install_element(OCTOI_CLNT_ACCOUNT_NODE, 
&cfg_account_trunkdev_name_cmd);
+       install_element(OCTOI_CLNT_ACCOUNT_NODE, 
&cfg_account_trunkdev_line_cmd);
+#endif /* HAVE_DAHDI_TRUNKDEV */

        install_node(&clnt_node, config_write_octoi_clnt);
        install_element(CONFIG_NODE, &cfg_client_cmd);
diff --git a/src/octoi/octoi_srv_fsm.c b/src/octoi/octoi_srv_fsm.c
index cda0e52..ed9e8f9 100644
--- a/src/octoi/octoi_srv_fsm.c
+++ b/src/octoi/octoi_srv_fsm.c
@@ -109,7 +109,7 @@

                switch (acc->mode) {
                case ACCOUNT_MODE_ICE1USB:
-               case ACCOUNT_MODE_DAHDI:
+               case ACCOUNT_MODE_DAHDI_TRUNKDEV:
                        /* check if a matching device exists for that account */
                        st->app_priv = g_octoi->ops->client_connected(srv, 
st->peer, acc);
                        if (!st->app_priv) {
diff --git a/src/octoi/octoi_srv_vty.c b/src/octoi/octoi_srv_vty.c
index 58d18bc..67c4eb6 100644
--- a/src/octoi/octoi_srv_vty.c
+++ b/src/octoi/octoi_srv_vty.c
@@ -48,7 +48,7 @@
        { ACCOUNT_MODE_NONE,            "none" },
        { ACCOUNT_MODE_ICE1USB,         "ice1usb" },
        { ACCOUNT_MODE_REDIRECT,        "redirect" },
-       { ACCOUNT_MODE_DAHDI,           "dahdi" },
+       { ACCOUNT_MODE_DAHDI_TRUNKDEV,  "dahdi-trunkdev" },
        { 0, NULL }
 };

@@ -288,10 +288,11 @@
 #endif

 gDEFUN(cfg_account_mode, cfg_account_mode_cmd,
-       "mode (ice1usb|redirect)",
+       "mode (ice1usb|redirect|dahdi-trunkdev)",
        "Operational mode of account\n"
        "Connect to local icE1usb (identified by USB serial + line number)\n"
-       "Redirect to other IP/Port\n")
+       "Redirect to other IP/Port\n"
+       "Use DAHDI trunkdev virtual trunk\n")
 {
        struct octoi_account *acc = vty->index;

@@ -309,6 +310,14 @@
                acc->mode = ACCOUNT_MODE_ICE1USB;
        } else if (!strcmp(argv[0], "redirect")) {
                acc->mode = ACCOUNT_MODE_REDIRECT;
+       } else if (!strcmp(argv[0], "dahdi-trunkdev")) {
+#ifdef HAVE_DAHDI_TRUNKDEV
+               acc->mode = ACCOUNT_MODE_DAHDI_TRUNKDEV;
+#else
+               vty_out(vty, "%% This build wasn't compiled with dahdi-trunkdev 
support%s",
+                       VTY_NEWLINE);
+               return CMD_WARNING;
+#endif
        } else
                OSMO_ASSERT(0);

@@ -400,6 +409,42 @@
                acc->batching_factor, acc->prefill_frame_count, VTY_NEWLINE);
 }

+#ifdef HAVE_DAHDI_TRUNKDEV
+
+#define DAHDI_STR      "DAHDI trunkdev settings\n"
+
+gDEFUN(cfg_account_trunkdev_name, cfg_account_trunkdev_name_cmd,
+       "dahdi-trunkdev name NAME",
+       DAHDI_STR "Identify DAHDI trunkdev device by name\n"
+       "Name of the DAHDI trunkdev device\n")
+{
+       struct octoi_account *acc = vty->index;
+
+       if (acc->mode != ACCOUNT_MODE_DAHDI_TRUNKDEV) {
+               vty_out(vty, "%% Error: Not in dahdi-trunkdev mode!%s", 
VTY_NEWLINE);
+               return CMD_WARNING;
+       }
+
+       osmo_talloc_replace_string(acc, &acc->u.dahdi_trunkdev.name, argv[0]);
+       return CMD_SUCCESS;
+}
+
+gDEFUN(cfg_account_trunkdev_line, cfg_account_trunkdev_line_cmd,
+       "dahdi-trunkdev line-number <0-1>",
+       DAHDI_STR "E1 Line number\n" "E1 Line number\n")
+{
+       struct octoi_account *acc = vty->index;
+
+       if (acc->mode != ACCOUNT_MODE_DAHDI_TRUNKDEV) {
+               vty_out(vty, "%% Error: Not in dahdi-trunkdev mode!%s", 
VTY_NEWLINE);
+               return CMD_WARNING;
+       }
+
+       acc->u.dahdi_trunkdev.line_nr = atoi(argv[0]);
+       return CMD_SUCCESS;
+}
+#endif /* HAVE_DAHDI_TRUNKDEV */
+
 void octoi_vty_write_one_account(struct vty *vty, const struct octoi_account 
*acc)
 {
        if (!acc)
@@ -427,8 +472,13 @@
                vty_out(vty, "  redirect %s %u%s", acc->u.redirect.to.ip, 
acc->u.redirect.to.port,
                        VTY_NEWLINE);
                break;
-       case ACCOUNT_MODE_DAHDI:
-               OSMO_ASSERT(0);
+       case ACCOUNT_MODE_DAHDI_TRUNKDEV:
+#ifdef HAVE_DAHDI_TRUNKDEV
+               if (acc->u.dahdi_trunkdev.name)
+                       vty_out(vty, "  dahdi-trunkdev name %s%s", 
acc->u.dahdi_trunkdev.name, VTY_NEWLINE);
+
+               vty_out(vty, "  dahdi-trunkdev line-number %u%s", 
acc->u.dahdi_trunkdev.line_nr, VTY_NEWLINE);
+#endif
                break;
        }
 }
@@ -489,6 +539,10 @@
        install_element(OCTOI_ACCOUNT_NODE, &cfg_account_redir_cmd);
        install_element(OCTOI_ACCOUNT_NODE, &cfg_account_batching_factor_cmd);
        install_element(OCTOI_ACCOUNT_NODE, 
&cfg_account_prefill_frame_count_cmd);
+#ifdef HAVE_DAHDI_TRUNKDEV
+       install_element(OCTOI_ACCOUNT_NODE, &cfg_account_trunkdev_name_cmd);
+       install_element(OCTOI_ACCOUNT_NODE, &cfg_account_trunkdev_line_cmd);
+#endif /* HAVE_DAHDI_TRUNKDEV */

        install_node(&srv_node, config_write_octoi_srv);
        install_element(CONFIG_NODE, &cfg_server_cmd);
diff --git a/src/octoi/octoi_vty.h b/src/octoi/octoi_vty.h
index 16c5337..33188e4 100644
--- a/src/octoi/octoi_vty.h
+++ b/src/octoi/octoi_vty.h
@@ -9,6 +9,8 @@
 extern struct cmd_element cfg_account_ice1_line_cmd;
 extern struct cmd_element cfg_account_batching_factor_cmd;
 extern struct cmd_element cfg_account_prefill_frame_count_cmd;
+extern struct cmd_element cfg_account_trunkdev_name_cmd;
+extern struct cmd_element cfg_account_trunkdev_line_cmd;

 struct octoi_account *octoi_client_account_create(struct octoi_client *clnt, 
const char *user_id);

diff --git a/src/vty.c b/src/vty.c
index 6507937..5b4ca47 100644
--- a/src/vty.c
+++ b/src/vty.c
@@ -88,10 +88,19 @@

 static const char *intf_serno(const struct e1_intf *intf)
 {
-       if (intf->usb.serial_str)
-               return intf->usb.serial_str;
-       else
-               return "unnamed";
+       switch (intf->drv) {
+       case E1_DRIVER_USB:
+               if (intf->usb.serial_str)
+                       return intf->usb.serial_str;
+               break;
+       case E1_DRIVER_DAHDI_TRUNKDEV:
+               if (intf->dahdi_trunkdev.name)
+                       return intf->dahdi_trunkdev.name;
+               break;
+       default:
+               break;
+       }
+       return "unnamed";
 }

 static void vty_dump_intf(struct vty *vty, const struct e1_intf *intf)
@@ -288,6 +297,31 @@
        return CMD_SUCCESS;
 }

+#ifdef HAVE_DAHDI_TRUNKDEV
+DEFUN(cfg_e1d_if_trunkdev, cfg_e1d_if_trunkdev_cmd, "interface <0-255> 
dahdi-trunkdev",
+       "Configure a DAHDI trunkdev interface (virtual trunk)\n"
+       "E1 Interface Number\n"
+       "Use DAHDI trunkdev driver for this interface\n")
+{
+       struct e1_intf *intf;
+       int intf_nr = atoi(argv[0]);
+
+       intf = e1d_find_intf(vty_e1d, intf_nr);
+       if (!intf)
+               intf = e1_intf_new(vty_e1d, intf_nr, NULL);
+       if (!intf) {
+               vty_out(vty, "%% Could not create interface%s", VTY_NEWLINE);
+               return CMD_WARNING;
+       }
+       intf->drv = E1_DRIVER_DAHDI_TRUNKDEV;
+       intf->vty_created = true;
+
+       vty->index = intf;
+       vty->node = INTF_NODE;
+       return CMD_SUCCESS;
+}
+#endif /* HAVE_DAHDI_TRUNKDEV */
+
 DEFUN(cfg_e1d_if_usb_serial, cfg_e1d_if_usb_serial_cmd,
        "usb-serial SERNO",
        "Configure the USB serial number of an E1 interface device\n"
@@ -334,6 +368,26 @@
        return CMD_SUCCESS;
 }

+#ifdef HAVE_DAHDI_TRUNKDEV
+DEFUN(cfg_e1d_if_trunkdev_name, cfg_e1d_if_trunkdev_name_cmd,
+       "trunkdev-name SERNO",
+       "Configure the name of the DAHDI trunkdev device\n"
+       "DAHDI trunkdev name\n")
+{
+       struct e1_intf *intf = vty->index;
+
+       if (intf->drv != E1_DRIVER_DAHDI_TRUNKDEV)
+               return CMD_WARNING;
+
+       osmo_talloc_replace_string(intf, &intf->dahdi_trunkdev.name, argv[0]);
+
+       e1_dahdi_trunkdev_close(intf);
+       e1_dahdi_trunkdev_open(intf);
+
+       return CMD_SUCCESS;
+}
+#endif /* HAVE_DAHDI_TRUNKDEV */
+
 DEFUN(cfg_e1d_if_line, cfg_e1d_if_line_cmd, "line <0-255>",
        "Configure an E1 line\n"
        "E1 Interface Number\n")
@@ -425,6 +479,11 @@
                case E1_DRIVER_VPAIR:
                        vty_out(vty, " interface %u vpair%s", intf->id, 
VTY_NEWLINE);
                        break;
+               case E1_DRIVER_DAHDI_TRUNKDEV:
+                       vty_out(vty, " interface %u dahdi-trunkdev%s", 
intf->id, VTY_NEWLINE);
+                       if (intf->dahdi_trunkdev.name && 
strlen(intf->dahdi_trunkdev.name))
+                               vty_out(vty, "  trunkdev-name %s%s", 
intf->dahdi_trunkdev.name, VTY_NEWLINE);
+                       break;
                default:
                        break;
                }
@@ -449,10 +508,16 @@
        install_node(&intf_node, NULL);
        install_element(E1D_NODE, &cfg_e1d_if_icE1usb_cmd);
        install_element(E1D_NODE, &cfg_e1d_if_vpair_cmd);
+#ifdef HAVE_DAHDI_TRUNKDEV
+       install_element(E1D_NODE, &cfg_e1d_if_trunkdev_cmd);
+#endif /* HAVE_DAHDI_TRUNKDEV */
        install_element(INTF_NODE, &cfg_e1d_if_line_cmd);
        install_element(INTF_NODE, &cfg_e1d_if_usb_serial_cmd);
        install_element(INTF_NODE, &cfg_e1d_if_gpsdo_manual_cmd);
        install_element(INTF_NODE, &cfg_e1d_if_no_gpsdo_manual_cmd);
+#ifdef HAVE_DAHDI_TRUNKDEV
+       install_element(INTF_NODE, &cfg_e1d_if_trunkdev_name_cmd);
+#endif /* HAVE_DAHDI_TRUNKDEV */

        install_node(&line_node, NULL);
        install_element(LINE_NODE, &cfg_e1d_if_line_mode_cmd);

--
To view, visit https://gerrit.osmocom.org/c/osmo-e1d/+/30068
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings

Gerrit-Project: osmo-e1d
Gerrit-Branch: master
Gerrit-Change-Id: Ib15a7313fcd63e1ed9f2f5b349df967bc4335ec2
Gerrit-Change-Number: 30068
Gerrit-PatchSet: 7
Gerrit-Owner: laforge <[email protected]>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <[email protected]>
Gerrit-Reviewer: manawyrm <[email protected]>
Gerrit-Reviewer: pespin <[email protected]>
Gerrit-Reviewer: tnt <[email protected]>
Gerrit-MessageType: merged

Reply via email to