aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorHarald Welte <laforge@osmocom.org>2022-11-10 01:19:35 +0100
committerHarald Welte <laforge@osmocom.org>2023-02-01 11:24:49 +0100
commit8aba31092f75ff6d0012bd615c355bae7a8a5922 (patch)
tree6868ec9cc8ec05292edf1dd6c9e71a6445c5a9b6 /src
parent632517011d756da5b0e5ddb38348df0454254621 (diff)
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
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am5
-rw-r--r--src/dahdi_trunkdev.c233
-rw-r--r--src/e1d.h15
-rw-r--r--src/e1oip.c45
-rw-r--r--src/intf_line.c22
-rw-r--r--src/log.c6
-rw-r--r--src/log.h1
-rw-r--r--src/octoi/octoi.c9
-rw-r--r--src/octoi/octoi_clnt_vty.c4
-rw-r--r--src/octoi/octoi_srv_fsm.c2
-rw-r--r--src/octoi/octoi_srv_vty.c64
-rw-r--r--src/octoi/octoi_vty.h2
-rw-r--r--src/vty.c73
13 files changed, 469 insertions, 12 deletions
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 @@ osmo_e1gen_SOURCES = \
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 <laforge@osmocom.org>
+ *
+ * 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 @@ struct e1_line {
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 @@ struct e1_intf {
uint16_t fine;
} gpsdo;
} usb;
+ struct {
+ char *name;
+ } dahdi_trunkdev;
bool vty_created;
enum e1_driver drv;
@@ -210,6 +214,9 @@ e1d_find_intf(struct e1_daemon *e1d, uint8_t id);
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 @@ e1d_vpair_create(struct e1_daemon *e1d, unsigned int num_lines);
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 @@ find_line_by_usb_serial(struct e1_daemon *e1d, const char *serial_str, uint8_t i
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 @@ find_line_for_account(struct e1_daemon *e1d, const struct octoi_account *acc)
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 @@ _e1d_octoi_client_connected_cb(struct octoi_server *srv, struct octoi_peer *peer
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 @@ _e1d_octoi_peer_disconnected_cb(struct octoi_peer *peer)
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 @@ e1d_find_intf_by_usb_serial(struct e1_daemon *e1d, const char *serial_str)
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 @@ static struct octoi_client *octoi_client_by_line(struct e1_line *line)
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 @@ static const struct log_info_cat default_categories[] = {
.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 @@ static struct octoi_client *client4account(struct octoi_account *acc)
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 @@ int octoi_vty_go_parent(struct vty *vty)
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 @@ void octoi_client_vty_init(void)
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 @@ static void srv_st_init(struct osmo_fsm_inst *fi, uint32_t event, void *data)
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 @@ const struct value_string octoi_account_mode_name[] = {
{ 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 @@ DEFUN(cfg_srv_no_account, cfg_serv_no_account_cmd,
#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 @@ gDEFUN(cfg_account_mode, cfg_account_mode_cmd,
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 @@ void octoi_vty_show_one_account(struct vty *vty, const char *pfx, struct octoi_a
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 @@ void octoi_vty_write_one_account(struct vty *vty, const struct octoi_account *ac
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 @@ void octoi_server_vty_init(void)
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_serno_cmd;
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 void vty_dump_ts(struct vty *vty, const struct e1_ts *ts)
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 @@ DEFUN(cfg_e1d_if_vpair, cfg_e1d_if_vpair_cmd, "interface <0-255> vpair",
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 @@ DEFUN(cfg_e1d_if_no_gpsdo_manual, cfg_e1d_if_no_gpsdo_manual_cmd,
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 @@ static int config_write_e1d(struct vty *vty)
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 @@ void e1d_vty_init(struct e1_daemon *e1d)
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);