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
This commit is contained in:
parent
632517011d
commit
8aba31092f
15
configure.ac
15
configure.ac
|
@ -75,6 +75,21 @@ then
|
|||
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,
|
||||
|
|
|
@ -11,7 +11,7 @@ enum octoi_account_mode {
|
|||
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 octoi_account {
|
|||
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_ops {
|
|||
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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
15
src/e1d.h
15
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);
|
||||
|
||||
|
|
45
src/e1oip.c
45
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,
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
enum {
|
||||
DE1D,
|
||||
DXFR,
|
||||
DTRUNKDEV,
|
||||
};
|
||||
|
||||
#define LOGPIF(itf, ss, lvl, fmt, args...) \
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
73
src/vty.c
73
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);
|
||||
|
|
Loading…
Reference in New Issue