Compare commits
6 Commits
Author | SHA1 | Date |
---|---|---|
Harald Welte | 5255769504 | |
Harald Welte | e9a4598c1f | |
Harald Welte | de9bd096c9 | |
Harald Welte | 89b6df7593 | |
Harald Welte | 68395096f0 | |
Harald Welte | 3b90fdbba1 |
|
@ -17,7 +17,7 @@ CFLAGS += \
|
||||||
#-Wformat=2
|
#-Wformat=2
|
||||||
endif
|
endif
|
||||||
|
|
||||||
SUBDIRS = xpp doc hotplug
|
SUBDIRS = xpp doc hotplug trunkdev
|
||||||
|
|
||||||
if PPPD
|
if PPPD
|
||||||
SUBDIRS += ppp
|
SUBDIRS += ppp
|
||||||
|
|
|
@ -182,6 +182,7 @@ AST_EXT_LIB_SETUP([PCAP], [pcap], [pcap])
|
||||||
AST_C_DEFINE_CHECK([DAHDI], [DAHDI_CODE], [dahdi/user.h])
|
AST_C_DEFINE_CHECK([DAHDI], [DAHDI_CODE], [dahdi/user.h])
|
||||||
DAHDI23_DIR="${DAHDI_DIR}"
|
DAHDI23_DIR="${DAHDI_DIR}"
|
||||||
AST_C_DEFINE_CHECK([DAHDI23], [DAHDI_CONFIG_NTTE], [dahdi/user.h])
|
AST_C_DEFINE_CHECK([DAHDI23], [DAHDI_CONFIG_NTTE], [dahdi/user.h])
|
||||||
|
AST_C_DEFINE_CHECK([TRUNKDEV], [DAHDI_TRUNKDEV_CREATE], [dahdi/user.h])
|
||||||
AST_EXT_LIB_CHECK([NEWT], [newt], [newtBell], [newt.h])
|
AST_EXT_LIB_CHECK([NEWT], [newt], [newtBell], [newt.h])
|
||||||
AST_EXT_LIB_CHECK([USB], [usb], [usb_init], [usb.h])
|
AST_EXT_LIB_CHECK([USB], [usb], [usb_init], [usb.h])
|
||||||
AST_EXT_LIB_CHECK([PCAP], [pcap], [pcap_compile], [pcap.h])
|
AST_EXT_LIB_CHECK([PCAP], [pcap], [pcap_compile], [pcap.h])
|
||||||
|
@ -193,6 +194,7 @@ CPPFLAGS="$saved_CPPFLAGS"
|
||||||
|
|
||||||
AM_CONDITIONAL([PBX_NEWT], [test "$PBX_NEWT" = "1"])
|
AM_CONDITIONAL([PBX_NEWT], [test "$PBX_NEWT" = "1"])
|
||||||
AM_CONDITIONAL([PBX_PCAP], [test "$PBX_PCAP" = "1" -a "$DAHDI_TXMIRROR" = "1"])
|
AM_CONDITIONAL([PBX_PCAP], [test "$PBX_PCAP" = "1" -a "$DAHDI_TXMIRROR" = "1"])
|
||||||
|
AM_CONDITIONAL([PBX_TRUNKDEV], [test "$PBX_TRUNKDEV" = "1"])
|
||||||
|
|
||||||
AC_CHECK_FUNCS([semtimedop])
|
AC_CHECK_FUNCS([semtimedop])
|
||||||
AC_CHECK_FUNCS([alarm bzero gettimeofday memset pow regcomp select socket strcasecmp strchr strdup strerror strrchr strstr strtol strtoul])
|
AC_CHECK_FUNCS([alarm bzero gettimeofday memset pow regcomp select socket strcasecmp strchr strdup strerror strrchr strstr strtol strtoul])
|
||||||
|
@ -390,6 +392,7 @@ AC_CONFIG_FILES([
|
||||||
xpp/xtalk/Makefile
|
xpp/xtalk/Makefile
|
||||||
xpp/oct612x/Makefile
|
xpp/oct612x/Makefile
|
||||||
xpp/perl_modules/Makefile
|
xpp/perl_modules/Makefile
|
||||||
|
trunkdev/Makefile
|
||||||
])
|
])
|
||||||
AC_OUTPUT
|
AC_OUTPUT
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# jenkins build helper script for dahdi-tools. This is how we build on jenkins.osmocom.org
|
||||||
|
|
||||||
|
if ! [ -x "$(command -v osmo-build-dep.sh)" ]; then
|
||||||
|
echo "Error: We need to have scripts/osmo-deps.sh from http://git.osmocom.org/osmo-ci/ in PATH !"
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
set -ex
|
||||||
|
|
||||||
|
base="$PWD"
|
||||||
|
deps="$base/deps"
|
||||||
|
inst="$deps/install"
|
||||||
|
export deps inst
|
||||||
|
|
||||||
|
osmo-clean-workspace.sh
|
||||||
|
|
||||||
|
mkdir "$deps" || true
|
||||||
|
|
||||||
|
cd "$deps"
|
||||||
|
if [ -d dahdi-linux ]; then
|
||||||
|
(cd dahdi-linux && git fetch && git checkout -f -B master origin/master)
|
||||||
|
else
|
||||||
|
git clone https://git.osmocom.org/dahdi-linux
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd $base
|
||||||
|
|
||||||
|
autoreconf -fi
|
||||||
|
./configure --with-dahdi="$deps/dahdi-linux"
|
||||||
|
$MAKE $PARALLEL_MAKE
|
||||||
|
|
||||||
|
osmo-clean-workspace.sh
|
36
dahdi_pcap.c
36
dahdi_pcap.c
|
@ -41,6 +41,7 @@
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
#include <linux/if_packet.h>
|
||||||
|
|
||||||
#define BLOCK_SIZE 512
|
#define BLOCK_SIZE 512
|
||||||
#define MAX_CHAN 16
|
#define MAX_CHAN 16
|
||||||
|
@ -100,7 +101,7 @@ int make_mirror(long type, int chan)
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
int log_packet(struct chan_fds * fd, char is_read, pcap_dumper_t * dump)
|
int log_packet(struct chan_fds * fd, char is_read, int we_are_network, pcap_dumper_t * dump)
|
||||||
{
|
{
|
||||||
unsigned char buf[BLOCK_SIZE * 4];
|
unsigned char buf[BLOCK_SIZE * 4];
|
||||||
int res = 0;
|
int res = 0;
|
||||||
|
@ -161,10 +162,10 @@ int log_packet(struct chan_fds * fd, char is_read, pcap_dumper_t * dump)
|
||||||
hdr.caplen = res+sizeof(struct lapd_sll_hdr)-2;
|
hdr.caplen = res+sizeof(struct lapd_sll_hdr)-2;
|
||||||
hdr.len = res+sizeof(struct lapd_sll_hdr)-2;
|
hdr.len = res+sizeof(struct lapd_sll_hdr)-2;
|
||||||
|
|
||||||
lapd->sll_pkttype = 3;
|
lapd->sll_pkttype = htons(is_read ? PACKET_HOST : PACKET_OUTGOING);
|
||||||
lapd->sll_hatype = 0;
|
lapd->sll_hatype = 0;
|
||||||
lapd->sll_halen = res;
|
lapd->sll_halen = htons(8);
|
||||||
// lapd->sll_addr = ???
|
lapd->sll_addr[0] = we_are_network;
|
||||||
lapd->sll_protocol[0] = 0x00;
|
lapd->sll_protocol[0] = 0x00;
|
||||||
lapd->sll_protocol[1] = 0x30;
|
lapd->sll_protocol[1] = 0x30;
|
||||||
|
|
||||||
|
@ -197,10 +198,11 @@ void usage()
|
||||||
printf("Usage: dahdi_pcap [OPTIONS]\n");
|
printf("Usage: dahdi_pcap [OPTIONS]\n");
|
||||||
printf("Capture packets from DAHDI channels to pcap file\n\n");
|
printf("Capture packets from DAHDI channels to pcap file\n\n");
|
||||||
printf("Options:\n");
|
printf("Options:\n");
|
||||||
printf(" -p, --proto=[mtp2|lapd] The protocol to capture, default mtp2\n");
|
printf(" -p, --proto=[mtp2|lapd] The protocol to capture, default mtp2\n");
|
||||||
printf(" -c, --chan=<channels> Comma separated list of channels to capture from, max %d. Mandatory\n", MAX_CHAN);
|
printf(" -c, --chan=<channels> Comma separated list of channels to capture from, max %d. Mandatory\n", MAX_CHAN);
|
||||||
printf(" -f, --file=<filename> The pcap file to capture to. Mandatory\n");
|
printf(" -r, --role=[network|user] Is the local side the network or user side in ISDN?\n");
|
||||||
printf(" -h, --help Display this text\n");
|
printf(" -f, --file=<filename> The pcap file to capture to. Mandatory\n");
|
||||||
|
printf(" -h, --help Display this text\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
|
@ -210,6 +212,7 @@ int main(int argc, char **argv)
|
||||||
int num_chans = 0;
|
int num_chans = 0;
|
||||||
int max_fd = 0;
|
int max_fd = 0;
|
||||||
int proto = DLT_MTP2_WITH_PHDR;
|
int proto = DLT_MTP2_WITH_PHDR;
|
||||||
|
int we_are_network = 0;
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
int packetcount;
|
int packetcount;
|
||||||
|
@ -220,12 +223,13 @@ int main(int argc, char **argv)
|
||||||
static struct option long_options[] = {
|
static struct option long_options[] = {
|
||||||
{"proto", required_argument, 0, 'p'},
|
{"proto", required_argument, 0, 'p'},
|
||||||
{"chan", required_argument, 0, 'c'},
|
{"chan", required_argument, 0, 'c'},
|
||||||
|
{"role", required_argument, 0, 'r'},
|
||||||
{"file", required_argument, 0, 'f'},
|
{"file", required_argument, 0, 'f'},
|
||||||
{"help", 0, 0, 'h'},
|
{"help", 0, 0, 'h'},
|
||||||
{0, 0, 0, 0}
|
{0, 0, 0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
c = getopt_long(argc, argv, "p:c:f:?",
|
c = getopt_long(argc, argv, "p:c:r:f:?",
|
||||||
long_options, &option_index);
|
long_options, &option_index);
|
||||||
if (c == -1)
|
if (c == -1)
|
||||||
break;
|
break;
|
||||||
|
@ -268,6 +272,16 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
max_fd++;
|
max_fd++;
|
||||||
break;
|
break;
|
||||||
|
case 'r':
|
||||||
|
if (!strcasecmp("network", optarg))
|
||||||
|
we_are_network = 1;
|
||||||
|
else if (!strcasecmp("user", optarg))
|
||||||
|
we_are_network = 0;
|
||||||
|
else {
|
||||||
|
fprintf(stderr, "Role must be user or network!\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'f':
|
case 'f':
|
||||||
// File to capture to
|
// File to capture to
|
||||||
filename=optarg;
|
filename=optarg;
|
||||||
|
@ -317,11 +331,11 @@ int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
if(FD_ISSET(chans[i].rfd, &rd_set))
|
if(FD_ISSET(chans[i].rfd, &rd_set))
|
||||||
{
|
{
|
||||||
packetcount += log_packet(&chans[i], 1, dump);
|
packetcount += log_packet(&chans[i], 1, we_are_network, dump);
|
||||||
}
|
}
|
||||||
if(FD_ISSET(chans[i].tfd, &rd_set))
|
if(FD_ISSET(chans[i].tfd, &rd_set))
|
||||||
{
|
{
|
||||||
packetcount += log_packet(&chans[i], 0, dump);
|
packetcount += log_packet(&chans[i], 0, we_are_network, dump);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
printf("Packets captured: %d\r", packetcount);
|
printf("Packets captured: %d\r", packetcount);
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
CFLAGS += -g -Wall -O2 $(DAHDI_INCLUDE)
|
||||||
|
|
||||||
|
if PBX_TRUNKDEV
|
||||||
|
|
||||||
|
sbin_PROGRAMS = \
|
||||||
|
dahdi_trunkdev \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
dahdi_trunkdev_SOURCES = \
|
||||||
|
trunkdev-tool.c \
|
||||||
|
dahdi-sysfs.c \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
endif
|
|
@ -0,0 +1,88 @@
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
#include "dahdi-sysfs.h"
|
||||||
|
|
||||||
|
/* read a sysfs attribute from a file, stripping any trailing newline */
|
||||||
|
char *sysfs_read_attr(const char *path)
|
||||||
|
{
|
||||||
|
FILE *f;
|
||||||
|
char *buf;
|
||||||
|
|
||||||
|
f = fopen(path, "r");
|
||||||
|
if (!f)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
buf = malloc(256);
|
||||||
|
if (!buf)
|
||||||
|
goto out_close;
|
||||||
|
|
||||||
|
if (!fgets(buf, 256, f))
|
||||||
|
goto out_free;
|
||||||
|
|
||||||
|
if (strlen(buf) && buf[strlen(buf)-1] == '\n')
|
||||||
|
buf[strlen(buf)-1] = '\0';
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
printf("%s: %s\n", path, buf);
|
||||||
|
return buf;
|
||||||
|
|
||||||
|
out_free:
|
||||||
|
free(buf);
|
||||||
|
out_close:
|
||||||
|
fclose(f);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *sysfs_read_span_attr(unsigned int spanno, const char *name)
|
||||||
|
{
|
||||||
|
char path[PATH_MAX];
|
||||||
|
snprintf(path, sizeof(path), "/sys/bus/dahdi_spans/devices/span-%u/%s", spanno, name);
|
||||||
|
return sysfs_read_attr(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sysfs_read_span_attr_int(unsigned int spanno, const char *name)
|
||||||
|
{
|
||||||
|
char *attr;
|
||||||
|
int attr_int;
|
||||||
|
|
||||||
|
attr = sysfs_read_span_attr(spanno, name);
|
||||||
|
if (!attr)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
attr_int = atoi(attr);
|
||||||
|
free(attr);
|
||||||
|
|
||||||
|
return attr_int;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* return number of channels in span */
|
||||||
|
int dahdi_span_get_basechan(unsigned int spanno)
|
||||||
|
{
|
||||||
|
return sysfs_read_span_attr_int(spanno, "basechan");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* return number of channels in span */
|
||||||
|
int dahdi_span_get_channels(unsigned int spanno)
|
||||||
|
{
|
||||||
|
return sysfs_read_span_attr_int(spanno, "channels");
|
||||||
|
}
|
||||||
|
|
||||||
|
char *dahdi_span_get_name(unsigned int spanno)
|
||||||
|
{
|
||||||
|
return sysfs_read_span_attr(spanno, "name");
|
||||||
|
}
|
||||||
|
|
||||||
|
char *dahdi_span_get_desc(unsigned int spanno)
|
||||||
|
{
|
||||||
|
return sysfs_read_span_attr(spanno, "desc");
|
||||||
|
}
|
||||||
|
|
||||||
|
char *dahdi_span_get_spantype(unsigned int spanno)
|
||||||
|
{
|
||||||
|
return sysfs_read_span_attr(spanno, "spantype");
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
char *sysfs_read_attr(const char *path);
|
||||||
|
|
||||||
|
int dahdi_span_get_basechan(unsigned int spanno);
|
||||||
|
int dahdi_span_get_channels(unsigned int spanno);
|
||||||
|
char *dahdi_span_get_name(unsigned int spanno);
|
||||||
|
char *dahdi_span_get_desc(unsigned int spanno);
|
||||||
|
char *dahdi_span_get_spantype(unsigned int spanno);
|
|
@ -0,0 +1,334 @@
|
||||||
|
/*
|
||||||
|
* trunkdev configuration program for DAHDI Telephony Interface
|
||||||
|
*
|
||||||
|
* Copyright (C) 2022 Harald Welte <laforge@osmocom.org>
|
||||||
|
* Copyright (C) 2001-2008 Digium, Inc.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software, distributed under the terms of
|
||||||
|
* the GNU General Public License Version 2 as published by the
|
||||||
|
* Free Software Foundation. See the LICENSE file included with
|
||||||
|
* this program for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <dahdi/user.h>
|
||||||
|
|
||||||
|
#include "dahdi-sysfs.h"
|
||||||
|
|
||||||
|
static int g_fd = -1;
|
||||||
|
|
||||||
|
|
||||||
|
/* wrapper around DAHDI_TRUNKDEV_CREATE */
|
||||||
|
static int trunkdev_create(int fd, const char *name)
|
||||||
|
{
|
||||||
|
struct dahdi_trunkdev_create td_c = { 0 };
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
strncpy(td_c.name, name, sizeof(td_c.name));
|
||||||
|
td_c.name[sizeof(td_c.name)-1] = 0;
|
||||||
|
|
||||||
|
rc = ioctl(fd, DAHDI_TRUNKDEV_CREATE, &td_c);
|
||||||
|
if (rc)
|
||||||
|
fprintf(stderr, "Error creating trunkdev '%s': %s\n", name, strerror(errno));
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* wrapper around DAHDI_TRUNKDEV_DELETE */
|
||||||
|
static int trunkdev_delete(int fd, const char *name)
|
||||||
|
{
|
||||||
|
struct dahdi_trunkdev_delete td_d = { 0 };
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
strncpy(td_d.name, name, sizeof(td_d.name));
|
||||||
|
td_d.name[sizeof(td_d.name)-1] = 0;
|
||||||
|
|
||||||
|
rc = ioctl(fd, DAHDI_TRUNKDEV_DELETE, &td_d);
|
||||||
|
if (rc)
|
||||||
|
fprintf(stderr, "Error deleting trunkdev '%s': %s\n", name, strerror(errno));
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* wrapper around DAHDI_TRUNKDEV_SPECIFY */
|
||||||
|
static int trunkdev_specify(int fd, const char *name)
|
||||||
|
{
|
||||||
|
struct dahdi_trunkdev_open td_o = { 0 };
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
strncpy(td_o.name, name, sizeof(td_o.name));
|
||||||
|
td_o.name[sizeof(td_o.name)-1] = 0;
|
||||||
|
|
||||||
|
rc = ioctl(fd, DAHDI_TRUNKDEV_OPEN, &td_o);
|
||||||
|
if (rc < 0) {
|
||||||
|
fprintf(stderr, "Error opening trunkdev '%s': %s\n", name, strerror(errno));
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
return td_o.spanno;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* wrapper around DAHDI_SPANCONFIG (assuming E1 with CRC4) */
|
||||||
|
static int spanconfig(int fd, int spanno)
|
||||||
|
{
|
||||||
|
struct dahdi_lineconfig dlc = {
|
||||||
|
.span = spanno,
|
||||||
|
.lbo = 0,
|
||||||
|
.lineconfig = DAHDI_CONFIG_CRC4,
|
||||||
|
.sync = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
return ioctl(fd, DAHDI_SPANCONFIG, &dlc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* wrapper around DAHDI_CHANCONFIG (assuming E1/ALAW/CLEAR; unless dchan -> HDLCFCS) */
|
||||||
|
static int chanconfig(int fd, int channo, bool dchan)
|
||||||
|
{
|
||||||
|
struct dahdi_chanconfig dcc = {
|
||||||
|
.chan = channo,
|
||||||
|
.sigtype = DAHDI_SIG_CLEAR,
|
||||||
|
.deflaw = DAHDI_LAW_ALAW,
|
||||||
|
.master = 0,
|
||||||
|
.idlebits = 0,
|
||||||
|
};
|
||||||
|
if (dchan)
|
||||||
|
dcc.sigtype = DAHDI_SIG_HDLCFCS;
|
||||||
|
|
||||||
|
return ioctl(fd, DAHDI_CHANCONFIG, &dcc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int chanconfig_hdlc_master(int fd, int channo, const char *netdev_name)
|
||||||
|
{
|
||||||
|
struct dahdi_chanconfig dcc = {
|
||||||
|
.chan = channo,
|
||||||
|
.sigtype = DAHDI_SIG_HDLCNET,
|
||||||
|
.deflaw = DAHDI_LAW_ALAW,
|
||||||
|
.master = 0,
|
||||||
|
.idlebits = 0,
|
||||||
|
};
|
||||||
|
strncpy(dcc.netdev_name, netdev_name, sizeof(dcc.netdev_name));
|
||||||
|
dcc.netdev_name[sizeof(dcc.netdev_name)-1] = '\0';
|
||||||
|
|
||||||
|
return ioctl(fd, DAHDI_CHANCONFIG, &dcc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int chanconfig_hdlc_slave(int fd, int channo, int master)
|
||||||
|
{
|
||||||
|
struct dahdi_chanconfig dcc = {
|
||||||
|
.chan = channo,
|
||||||
|
.sigtype = DAHDI_SIG_SLAVE,
|
||||||
|
.deflaw = DAHDI_LAW_ALAW,
|
||||||
|
.master = master,
|
||||||
|
.idlebits = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
return ioctl(fd, DAHDI_CHANCONFIG, &dcc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* high-level wrapper to configure an E1 span + all its channels */
|
||||||
|
static int config(int spanno, const char *hdlc_netdev)
|
||||||
|
{
|
||||||
|
struct dahdi_spaninfo dsi = {
|
||||||
|
.spanno = spanno,
|
||||||
|
};
|
||||||
|
int fd, rc;
|
||||||
|
|
||||||
|
fd = open("/dev/dahdi/ctl", O_RDWR);
|
||||||
|
if (fd < 0) {
|
||||||
|
fprintf(stderr, "Unable to open /dev/dahd/ctl: %s\n", strerror(errno));
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = ioctl(fd, DAHDI_SPANSTAT, &dsi);
|
||||||
|
if (rc < 0) {
|
||||||
|
fprintf(stderr, "Error during spanstat: %s\n", strerror(errno));
|
||||||
|
close(fd);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
printf("Span %u (%s: %s)\n", dsi.spanno, dsi.name, dsi.desc);
|
||||||
|
printf(" numchans=%u, totalchans=%u\n", dsi.numchans, dsi.totalchans);
|
||||||
|
|
||||||
|
rc = spanconfig(fd, spanno);
|
||||||
|
if (rc < 0) {
|
||||||
|
fprintf(stderr, "Error during spanconfig: %s\n", strerror(errno));
|
||||||
|
close(fd);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* resolve basechan + num_chan via sysfs */
|
||||||
|
int basechan = dahdi_span_get_basechan(spanno);
|
||||||
|
int num_chan = dahdi_span_get_channels(spanno);
|
||||||
|
if (basechan < 0 || num_chan < 0) {
|
||||||
|
fprintf(stderr, "Error getting basechan=%d or channels=%d for spanno=%d: %s\n",
|
||||||
|
basechan, num_chan, spanno, strerror(errno));
|
||||||
|
close(fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int i = basechan; i < basechan+num_chan; i++) {
|
||||||
|
if (!hdlc_netdev) {
|
||||||
|
/* ISDN: we assume a standard ISDN configuration with TS16 == D-channel */
|
||||||
|
rc = chanconfig(fd, i, i == basechan + 15);
|
||||||
|
} else {
|
||||||
|
/* HDLC: we assume TS 1-31 as superchannel */
|
||||||
|
if (i == basechan)
|
||||||
|
rc = chanconfig_hdlc_master(fd, i, hdlc_netdev);
|
||||||
|
else
|
||||||
|
rc = chanconfig_hdlc_slave(fd, i, basechan);
|
||||||
|
}
|
||||||
|
if (rc < 0) {
|
||||||
|
fprintf(stderr, "Error during spanconfig: %s\n", strerror(errno));
|
||||||
|
close(fd);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_help(void)
|
||||||
|
{
|
||||||
|
printf("\n");
|
||||||
|
printf( "dahdi_trunkdev create NAME\n"
|
||||||
|
" Create a new dahdi trunkdev named NAME\n"
|
||||||
|
"dahdi_trunkdev delete NAME\n"
|
||||||
|
" Delete an existing dahdi trunkdev named NAME\n"
|
||||||
|
"dahdi_trunkdev config NAME\n"
|
||||||
|
" Configure span + all channels of trunkdev named NAME for ISDN\n"
|
||||||
|
"dahdi_trunkdev config-hdlc NAME\n"
|
||||||
|
" Configure span + all channels of trunkdev named NAME for HDLC\n"
|
||||||
|
"dahdi_trunkdev read NAME\n"
|
||||||
|
" Continuously read + discard frames from trunkdev named NAME\n"
|
||||||
|
"dahdi_trunkdev rdwr NAME\n"
|
||||||
|
" Continuously read + loop back (write) frames of trunkdev named NAME\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
printf("DAHDI trunkdev tool (C) 2022 by Harald Welte <laforge@osmocom.org>\n\n");
|
||||||
|
|
||||||
|
if (argc < 2) {
|
||||||
|
fprintf(stderr, "First argument must specify the command\n");
|
||||||
|
print_help();
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp(argv[1], "help") || !strcmp(argv[1], "--help")) {
|
||||||
|
print_help();
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_fd = open("/dev/dahdi/trunkdev", O_RDWR);
|
||||||
|
if (g_fd < 0) {
|
||||||
|
fprintf(stderr, "Unable to open trunkdev: %s\n", strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp(argv[1], "create")) {
|
||||||
|
/* dahdi_trunkdev create foo */
|
||||||
|
if (argc < 3) {
|
||||||
|
fprintf(stderr, "Second argument must specify the name\n");
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
rc = trunkdev_create(g_fd, argv[2]);
|
||||||
|
if (rc < 0) {
|
||||||
|
fprintf(stderr, "Unable to create trunkdev: %s\n", strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
printf("DAHDI trunkdev %s created; span number %d\n", argv[2], rc);
|
||||||
|
} else if (!strcmp(argv[1], "delete")) {
|
||||||
|
/* dahdi_trunkdev create foo */
|
||||||
|
if (argc < 3) {
|
||||||
|
fprintf(stderr, "Second argument must specify the name\n");
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
rc = trunkdev_delete(g_fd, argv[2]);
|
||||||
|
if (rc < 0) {
|
||||||
|
fprintf(stderr, "Unable to create trunkdev: %s\n", strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
printf("DAHDI trunkdev %s deleted\n", argv[2]);
|
||||||
|
} else if (!strcmp(argv[1], "config")) {
|
||||||
|
/* dahdi_trunkdev config foo */
|
||||||
|
if (argc < 3) {
|
||||||
|
fprintf(stderr, "Second argument must specify the name\n");
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
rc = trunkdev_specify(g_fd, argv[2]);
|
||||||
|
if (rc < 0) {
|
||||||
|
fprintf(stderr, "Unable to specify trunkdev: %s\n", strerror(errno));
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
rc = config(rc, NULL);
|
||||||
|
if (rc < 0)
|
||||||
|
exit(2);
|
||||||
|
printf("DAHDI trunkdev %s configured\n", argv[2]);
|
||||||
|
} else if (!strcmp(argv[1], "config-hdlc")) {
|
||||||
|
/* dahdi_trunkdev config-hdlc foo hdlc-foo */
|
||||||
|
if (argc < 3) {
|
||||||
|
fprintf(stderr, "Second argument must specify the name\n");
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
if (argc < 4) {
|
||||||
|
fprintf(stderr, "Third argument must specify the net-device name\n");
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
rc = trunkdev_specify(g_fd, argv[2]);
|
||||||
|
if (rc < 0) {
|
||||||
|
fprintf(stderr, "Unable to specify trunkdev: %s\n", strerror(errno));
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
rc = config(rc, argv[3]);
|
||||||
|
if (rc < 0)
|
||||||
|
exit(2);
|
||||||
|
printf("DAHDI trunkdev %s configured as netdev %s\n", argv[2], argv[3]);
|
||||||
|
} else if (!strcmp(argv[1], "read") || !strcmp(argv[1], "rdwr")) {
|
||||||
|
/* dahdi_trunkdev (read|rdwr) foo */
|
||||||
|
if (argc < 3) {
|
||||||
|
fprintf(stderr, "Second argument must specify the name\n");
|
||||||
|
exit(2);
|
||||||
|
}
|
||||||
|
rc = trunkdev_specify(g_fd, argv[2]);
|
||||||
|
if (rc < 0) {
|
||||||
|
fprintf(stderr, "Unable to specify trunkdev: %s\n", strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (!strcmp(argv[1], "read"))
|
||||||
|
printf("Reading + Disccarding from DAHDI trunkdev %s\n", argv[2]);
|
||||||
|
else
|
||||||
|
printf("Reading + Writing (looping back) DAHDI trunkdev %s\n", argv[2]);
|
||||||
|
while (1) {
|
||||||
|
uint8_t buf[32*8];
|
||||||
|
rc = read(g_fd, buf, sizeof(buf));
|
||||||
|
if (rc <= 0) {
|
||||||
|
fprintf(stderr, "Error %d reading: %s\n", rc, strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
fputc('.', stdout);
|
||||||
|
if (!strcmp(argv[1], "rdwr")) {
|
||||||
|
rc = write(g_fd, buf, rc);
|
||||||
|
if (rc <= 0) {
|
||||||
|
fprintf(stderr, "Error %d writing: %s\n", rc, strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
exit(23);
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
|
@ -60,7 +60,7 @@ union XTALK_PDATA(XTALK) {
|
||||||
MEMBER(XTALK, ACK);
|
MEMBER(XTALK, ACK);
|
||||||
MEMBER(XTALK, PROTO_GET);
|
MEMBER(XTALK, PROTO_GET);
|
||||||
MEMBER(XTALK, PROTO_GET_REPLY);
|
MEMBER(XTALK, PROTO_GET_REPLY);
|
||||||
} PACKED members;
|
} PACKED _members;
|
||||||
|
|
||||||
const struct xtalk_protocol xtalk_sync_proto = {
|
const struct xtalk_protocol xtalk_sync_proto = {
|
||||||
.name = "XTALK-SYNC",
|
.name = "XTALK-SYNC",
|
||||||
|
|
Loading…
Reference in New Issue