VTY interface support
Let's add a VTY interface on TCP port 4269. The purpose is - for now - not for configuration storage, but for state introspection. Change-Id: I47b6e4efaad52e68e2b50a7993076f3706f86628
This commit is contained in:
parent
0b621b43e7
commit
9144ba0373
|
@ -33,6 +33,7 @@ PKG_PROG_PKG_CONFIG([0.20])
|
|||
PKG_CHECK_MODULES(TALLOC, [talloc >= 2.0.1])
|
||||
|
||||
PKG_CHECK_MODULES(LIBOSMOCORE, libosmocore >= 1.0.1.120)
|
||||
PKG_CHECK_MODULES(LIBOSMOVTY, libosmovty)
|
||||
PKG_CHECK_MODULES(LIBOSMOUSB, libosmousb)
|
||||
PKG_CHECK_MODULES(LIBUSB, libusb-1.0 >= 1.0.21)
|
||||
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
LIBVERSION=0:0:0
|
||||
|
||||
AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
|
||||
AM_CFLAGS=-Wall -Wno-unused-result $(LIBOSMOCORE_CFLAGS) $(LIBOSMOUSB_LIBS) $(LIBUSB_CFLAGS)
|
||||
AM_CFLAGS=-Wall -Wno-unused-result $(LIBOSMOCORE_CFLAGS) \
|
||||
$(LIBOSMOVTY_LIBS) $(LIBOSMOUSB_LIBS) $(LIBUSB_CFLAGS)
|
||||
|
||||
lib_LTLIBRARIES = libosmo-e1d.la
|
||||
|
||||
|
@ -34,6 +35,8 @@ osmo_e1d_SOURCES = \
|
|||
log.c \
|
||||
osmo-e1d.c \
|
||||
usb.c \
|
||||
vty.c \
|
||||
$(NULL)
|
||||
|
||||
osmo_e1d_LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOUSB_LIBS) $(LIBUSB_LIBS) libosmo-e1d.la
|
||||
osmo_e1d_LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOVTY_LIBS) \
|
||||
$(LIBOSMOUSB_LIBS) $(LIBUSB_LIBS) libosmo-e1d.la
|
||||
|
|
12
src/ctl.c
12
src/ctl.c
|
@ -38,8 +38,8 @@
|
|||
#include "e1d.h"
|
||||
|
||||
|
||||
static struct e1_intf *
|
||||
_e1d_find_intf(struct e1_daemon *e1d, uint8_t id)
|
||||
struct e1_intf *
|
||||
e1d_find_intf(struct e1_daemon *e1d, uint8_t id)
|
||||
{
|
||||
struct e1_intf *intf;
|
||||
|
||||
|
@ -137,7 +137,7 @@ _e1d_ctl_intf_query(void *data, struct msgb *msgb, struct msgb *rmsgb, int *rfd)
|
|||
|
||||
/* Process query and find interface */
|
||||
if (hdr->intf != E1DP_INVALID) {
|
||||
intf = _e1d_find_intf(e1d, hdr->intf);
|
||||
intf = e1d_find_intf(e1d, hdr->intf);
|
||||
n = intf ? 1 : 0;
|
||||
} else {
|
||||
n = llist_count(&e1d->interfaces);
|
||||
|
@ -174,7 +174,7 @@ _e1d_ctl_line_query(void *data, struct msgb *msgb, struct msgb *rmsgb, int *rfd)
|
|||
int n;
|
||||
|
||||
/* Process query and find line */
|
||||
intf = _e1d_find_intf(e1d, hdr->intf);
|
||||
intf = e1d_find_intf(e1d, hdr->intf);
|
||||
if (!intf)
|
||||
return 0;
|
||||
|
||||
|
@ -216,7 +216,7 @@ _e1d_ctl_ts_query(void *data, struct msgb *msgb, struct msgb *rmsgb, int *rfd)
|
|||
int n;
|
||||
|
||||
/* Process query and find timeslot */
|
||||
intf = _e1d_find_intf(e1d, hdr->intf);
|
||||
intf = e1d_find_intf(e1d, hdr->intf);
|
||||
if (!intf)
|
||||
return 0;
|
||||
|
||||
|
@ -262,7 +262,7 @@ _e1d_ctl_ts_open(void *data, struct msgb *msgb, struct msgb *rmsgb, int *rfd)
|
|||
int ret;
|
||||
|
||||
/* Process query and find timeslot */
|
||||
intf = _e1d_find_intf(e1d, hdr->intf);
|
||||
intf = e1d_find_intf(e1d, hdr->intf);
|
||||
if (!intf)
|
||||
return 0;
|
||||
|
||||
|
|
|
@ -84,6 +84,9 @@ struct e1_daemon {
|
|||
struct e1_intf *
|
||||
e1_intf_new(struct e1_daemon *e1d, void *drv_data);
|
||||
|
||||
struct e1_intf *
|
||||
e1d_find_intf(struct e1_daemon *e1d, uint8_t id);
|
||||
|
||||
struct e1_line *
|
||||
e1_line_new(struct e1_intf *intf, void *drv_data);
|
||||
|
||||
|
@ -92,3 +95,6 @@ e1_line_mux_out(struct e1_line *line, uint8_t *buf, int fts);
|
|||
|
||||
int
|
||||
e1_line_demux_in(struct e1_line *line, const uint8_t *buf, int size);
|
||||
|
||||
void
|
||||
e1d_vty_init(struct e1_daemon *e1d);
|
||||
|
|
|
@ -28,23 +28,30 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <getopt.h>
|
||||
|
||||
#include <talloc.h>
|
||||
|
||||
#include <osmocom/core/application.h>
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/core/select.h>
|
||||
#include <osmocom/vty/telnet_interface.h>
|
||||
|
||||
#include <osmocom/e1d/proto_srv.h>
|
||||
|
||||
#include "e1d.h"
|
||||
#include "log.h"
|
||||
|
||||
#ifndef OSMO_VTY_PORT_E1D
|
||||
#define OSMO_VTY_PORT_E1D 4269
|
||||
#endif
|
||||
|
||||
extern struct osmo_e1dp_server_handler e1d_ctl_handlers[];
|
||||
extern int e1_usb_probe(struct e1_daemon *e1d);
|
||||
|
||||
|
||||
|
||||
static const char *g_config_file = "osmo-e1d.cfg";
|
||||
static void *g_e1d_ctx = NULL;
|
||||
static int g_shutdown = 0;
|
||||
|
||||
|
@ -71,6 +78,61 @@ static void sig_handler(int signo)
|
|||
}
|
||||
}
|
||||
|
||||
static struct vty_app_info vty_info = {
|
||||
.name = "osmo-e1d",
|
||||
.version = PACKAGE_VERSION,
|
||||
.copyright =
|
||||
"(C) 2019 by Sylvain Munaut <tnt@246tNt.com>\r\n",
|
||||
"License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl-2.0.html>\r\n"
|
||||
"This is free software: you are free to change and redistribute it.\r\n"
|
||||
"There is NO WARRANTY, to the extent permitted by law.\r\n",
|
||||
};
|
||||
|
||||
static void print_help(void)
|
||||
{
|
||||
printf(" Some useful help...\n");
|
||||
printf(" -h --help This text.\n");
|
||||
printf(" -d --debug option --debug=DE1D:DXFR enable debugging.\n");
|
||||
printf(" -c --config-file filename The config file to use.\n");
|
||||
}
|
||||
|
||||
static void handle_options(int argc, char **argv)
|
||||
{
|
||||
while (1) {
|
||||
int option_index = 0, c;
|
||||
static const struct option long_options[] = {
|
||||
{"help", 0, 0, 'h'},
|
||||
{"debug", 1, 0, 'd'},
|
||||
{"config-file", 1, 0, 'c'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
c = getopt_long(argc, argv, "hd:c:", long_options, &option_index);
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
switch (c) {
|
||||
case 'h':
|
||||
print_help();
|
||||
exit(0);
|
||||
break;
|
||||
case 'd':
|
||||
log_parse_category_mask(osmo_stderr_target, optarg);
|
||||
break;
|
||||
case 'c':
|
||||
g_config_file = optarg;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Error in command line options. Exiting.\n");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
if (argc > optind) {
|
||||
fprintf(stderr, "Unsupported positional arguments on command line\n");
|
||||
exit(2);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
|
@ -82,6 +144,7 @@ int main(int argc, char *argv[])
|
|||
/* talloc init */
|
||||
g_e1d_ctx = talloc_named_const(NULL, 0, "osmo-e1d");
|
||||
msgb_talloc_ctx_init(g_e1d_ctx, 0);
|
||||
vty_info.tall_ctx = g_e1d_ctx;
|
||||
|
||||
/* logging init */
|
||||
osmo_init_logging2(g_e1d_ctx, &log_info);
|
||||
|
@ -108,6 +171,23 @@ int main(int argc, char *argv[])
|
|||
OSMO_ASSERT(e1d);
|
||||
|
||||
INIT_LLIST_HEAD(&e1d->interfaces);
|
||||
vty_init(&vty_info);
|
||||
e1d_vty_init(e1d);
|
||||
|
||||
handle_options(argc, argv);
|
||||
|
||||
rv = vty_read_config_file(g_config_file, NULL);
|
||||
if (rv < 0) {
|
||||
LOGP(DE1D, LOGL_FATAL, "Failed to parse the config file '%s'\n", g_config_file);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
rv = telnet_init_dynif(g_e1d_ctx, e1d, vty_get_bind_addr(), OSMO_VTY_PORT_E1D);
|
||||
if (rv != 0) {
|
||||
LOGP(DE1D, LOGL_FATAL, "Failed to bind VTY interface to %s:%u\n",
|
||||
vty_get_bind_addr(), OSMO_VTY_PORT_E1D);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* probe devices */
|
||||
rv = e1_usb_probe(e1d);
|
||||
|
|
|
@ -0,0 +1,139 @@
|
|||
/* osmo-e1d VTY interface */
|
||||
/* (C) 2020 by Harald Welte <laforge@osmocom.org>
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation; either version 3 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE /* struct ucred */
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
|
||||
#include <osmocom/vty/command.h>
|
||||
#include <osmocom/vty/buffer.h>
|
||||
#include <osmocom/vty/vty.h>
|
||||
#include <osmocom/vty/logging.h>
|
||||
#include <osmocom/vty/stats.h>
|
||||
#include <osmocom/vty/telnet_interface.h>
|
||||
#include <osmocom/vty/misc.h>
|
||||
#include <osmocom/vty/tdef_vty.h>
|
||||
|
||||
#include <osmocom/e1d/proto.h>
|
||||
#include "e1d.h"
|
||||
|
||||
static struct e1_daemon *vty_e1d;
|
||||
|
||||
#if 0
|
||||
static void vty_dump_ts(struct vty *vty, const struct e1_ts *ts)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
static void vty_dump_intf(struct vty *vty, const struct e1_intf *intf)
|
||||
{
|
||||
vty_out(vty, "Interface #%u, Driver: FIXME%s", intf->id, VTY_NEWLINE);
|
||||
}
|
||||
|
||||
DEFUN(show_intf, show_intf_cmd, "show interface [<0-255>]",
|
||||
SHOW_STR "Display information about an E1 Interface/Card\n")
|
||||
{
|
||||
struct e1_intf *intf;
|
||||
|
||||
if (argc) {
|
||||
int id = atoi(argv[0]);
|
||||
intf = e1d_find_intf(vty_e1d, id);
|
||||
if (!intf) {
|
||||
vty_out(vty, "%% Unknown interface %u%s\n", id, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
vty_dump_intf(vty, intf);
|
||||
} else {
|
||||
llist_for_each_entry(intf, &vty_e1d->interfaces, list)
|
||||
vty_dump_intf(vty, intf);
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static int get_remote_pid(int fd)
|
||||
{
|
||||
struct ucred uc;
|
||||
socklen_t len = sizeof(uc);
|
||||
int rc;
|
||||
|
||||
rc = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &uc, &len);
|
||||
if (rc != 0)
|
||||
return -1;
|
||||
return uc.pid;
|
||||
}
|
||||
|
||||
static const struct value_string e1_ts_mode_names[] = {
|
||||
{ E1_TS_MODE_OFF, "OFF" },
|
||||
{ E1_TS_MODE_RAW, "RAW" },
|
||||
{ E1_TS_MODE_HDLCFCS, "HDLC-FCS" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
static void vty_dump_line(struct vty *vty, const struct e1_line *line)
|
||||
{
|
||||
int tn;
|
||||
|
||||
vty_out(vty, "Interface #%u, Line #%u:%s", line->intf->id, line->id, VTY_NEWLINE);
|
||||
|
||||
for (tn = 0; tn < ARRAY_SIZE(line->ts); tn++) {
|
||||
const struct e1_ts *ts = &line->ts[tn];
|
||||
vty_out(vty, " TS%02u: Mode %s, FD %d, Peer PID %d%s",
|
||||
ts->id, get_value_string(e1_ts_mode_names, ts->mode),
|
||||
ts->fd, get_remote_pid(ts->fd), VTY_NEWLINE);
|
||||
}
|
||||
}
|
||||
|
||||
DEFUN(show_line, show_line_cmd, "show line [<0-255>]",
|
||||
SHOW_STR "Display information about an E1 Line\n")
|
||||
{
|
||||
struct e1_line *line;
|
||||
struct e1_intf *intf;
|
||||
|
||||
if (argc) {
|
||||
int id = atoi(argv[0]);
|
||||
intf = e1d_find_intf(vty_e1d, id);
|
||||
if (!intf) {
|
||||
vty_out(vty, "%% Unknown interface %u%s\n", id, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
llist_for_each_entry(line, &intf->lines, list)
|
||||
vty_dump_line(vty, line);
|
||||
} else {
|
||||
llist_for_each_entry(intf, &vty_e1d->interfaces, list) {
|
||||
llist_for_each_entry(line, &intf->lines, list)
|
||||
vty_dump_line(vty, line);
|
||||
}
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
void e1d_vty_init(struct e1_daemon *e1d)
|
||||
{
|
||||
vty_e1d = e1d;
|
||||
install_element_ve(&show_intf_cmd);
|
||||
install_element_ve(&show_line_cmd);
|
||||
}
|
Loading…
Reference in New Issue