diff options
author | Harald Welte <laforge@osmocom.org> | 2022-11-10 01:19:35 +0100 |
---|---|---|
committer | Harald Welte <laforge@osmocom.org> | 2023-02-01 11:24:49 +0100 |
commit | 8aba31092f75ff6d0012bd615c355bae7a8a5922 (patch) | |
tree | 6868ec9cc8ec05292edf1dd6c9e71a6445c5a9b6 /src | |
parent | 632517011d756da5b0e5ddb38348df0454254621 (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.am | 5 | ||||
-rw-r--r-- | src/dahdi_trunkdev.c | 233 | ||||
-rw-r--r-- | src/e1d.h | 15 | ||||
-rw-r--r-- | src/e1oip.c | 45 | ||||
-rw-r--r-- | src/intf_line.c | 22 | ||||
-rw-r--r-- | src/log.c | 6 | ||||
-rw-r--r-- | src/log.h | 1 | ||||
-rw-r--r-- | src/octoi/octoi.c | 9 | ||||
-rw-r--r-- | src/octoi/octoi_clnt_vty.c | 4 | ||||
-rw-r--r-- | src/octoi/octoi_srv_fsm.c | 2 | ||||
-rw-r--r-- | src/octoi/octoi_srv_vty.c | 64 | ||||
-rw-r--r-- | src/octoi/octoi_vty.h | 2 | ||||
-rw-r--r-- | src/vty.c | 73 |
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; +} @@ -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; @@ -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...) \ 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); @@ -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); |