summaryrefslogtreecommitdiffstats
path: root/usr.sbin
diff options
context:
space:
mode:
authorphk <phk@FreeBSD.org>1998-12-27 21:47:14 +0000
committerphk <phk@FreeBSD.org>1998-12-27 21:47:14 +0000
commitc7ecc129d72ba32b5d83c9a6019e93fd181d719c (patch)
tree8d5099bc7ef24151b4f6deb00d1d34a7e7ac694a /usr.sbin
parent3f431df8ec46b86090ad59ee153872c45d4d429d (diff)
downloadFreeBSD-src-c7ecc129d72ba32b5d83c9a6019e93fd181d719c.zip
FreeBSD-src-c7ecc129d72ba32b5d83c9a6019e93fd181d719c.tar.gz
Initial entry of ISDN4BSD into the FreeBSD tree.
ISDN4BSD is the work of our brand-new comitter: Hellmuth Michaelis, who has done a tremendous amount of work to bring us this far. There are still some outstanding issues and files to bring into the tree, and for now it will be needed to pick up all the extra docs from the isdn4bsd release. It is probably also a very good idea to subscribe to the isdn@freebsd.org mailing list before you try this out. These files correspond to release "beta Version 0.70.00 / December 1998" from Hellmuth.
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/Makefile3
-rw-r--r--usr.sbin/i4b/Makefile4
-rw-r--r--usr.sbin/i4b/Makefile.inc14
-rw-r--r--usr.sbin/i4b/alawulaw/Makefile7
-rw-r--r--usr.sbin/i4b/alawulaw/alaw2ulaw.170
-rw-r--r--usr.sbin/i4b/alawulaw/alaw2ulaw.c151
-rw-r--r--usr.sbin/i4b/alawulaw/ulaw2alaw.170
-rw-r--r--usr.sbin/i4b/isdnd/Makefile32
-rw-r--r--usr.sbin/i4b/isdnd/alias.c191
-rw-r--r--usr.sbin/i4b/isdnd/config.h61
-rw-r--r--usr.sbin/i4b/isdnd/controller.c329
-rw-r--r--usr.sbin/i4b/isdnd/curses.c633
-rw-r--r--usr.sbin/i4b/isdnd/dial.c153
-rw-r--r--usr.sbin/i4b/isdnd/exec.c280
-rw-r--r--usr.sbin/i4b/isdnd/fsm.c446
-rw-r--r--usr.sbin/i4b/isdnd/isdnd.8419
-rw-r--r--usr.sbin/i4b/isdnd/isdnd.acct.5108
-rw-r--r--usr.sbin/i4b/isdnd/isdnd.h754
-rw-r--r--usr.sbin/i4b/isdnd/isdnd.rates.5115
-rw-r--r--usr.sbin/i4b/isdnd/isdnd.rc.5642
-rw-r--r--usr.sbin/i4b/isdnd/log.c242
-rw-r--r--usr.sbin/i4b/isdnd/main.c707
-rw-r--r--usr.sbin/i4b/isdnd/monitor.c811
-rw-r--r--usr.sbin/i4b/isdnd/msghdl.c983
-rw-r--r--usr.sbin/i4b/isdnd/pathnames.h54
-rw-r--r--usr.sbin/i4b/isdnd/pcause.c227
-rw-r--r--usr.sbin/i4b/isdnd/process.c219
-rw-r--r--usr.sbin/i4b/isdnd/rates.c473
-rw-r--r--usr.sbin/i4b/isdnd/rc_config.c1140
-rw-r--r--usr.sbin/i4b/isdnd/rc_parse.y388
-rw-r--r--usr.sbin/i4b/isdnd/rc_scan.l170
-rw-r--r--usr.sbin/i4b/isdnd/support.c831
-rw-r--r--usr.sbin/i4b/isdnd/timer.c411
-rw-r--r--usr.sbin/i4b/isdnd/vararray.h120
-rw-r--r--usr.sbin/i4b/isdndebug/Makefile5
-rw-r--r--usr.sbin/i4b/isdndebug/isdndebug.8102
-rw-r--r--usr.sbin/i4b/isdndebug/main.c553
-rw-r--r--usr.sbin/i4b/isdndecode/Makefile7
-rw-r--r--usr.sbin/i4b/isdndecode/decode.h74
-rw-r--r--usr.sbin/i4b/isdndecode/facility.c906
-rw-r--r--usr.sbin/i4b/isdndecode/facility.h154
-rw-r--r--usr.sbin/i4b/isdndecode/isdndecode.8190
-rw-r--r--usr.sbin/i4b/isdndecode/layer1.c80
-rw-r--r--usr.sbin/i4b/isdndecode/layer2.c298
-rw-r--r--usr.sbin/i4b/isdndecode/layer3.c508
-rw-r--r--usr.sbin/i4b/isdndecode/layer3_subr.c1045
-rw-r--r--usr.sbin/i4b/isdndecode/main.c774
-rw-r--r--usr.sbin/i4b/isdndecode/pcause.c328
-rw-r--r--usr.sbin/i4b/isdndecode/pcause.h109
-rw-r--r--usr.sbin/i4b/isdnmonitor/Makefile8
-rw-r--r--usr.sbin/i4b/isdnmonitor/isdnmonitor.840
-rw-r--r--usr.sbin/i4b/isdnmonitor/main.c675
-rw-r--r--usr.sbin/i4b/isdnmonitor/monitor.h263
-rw-r--r--usr.sbin/i4b/isdntel/Makefile6
-rw-r--r--usr.sbin/i4b/isdntel/alias.c139
-rw-r--r--usr.sbin/i4b/isdntel/alias.h49
-rw-r--r--usr.sbin/i4b/isdntel/defs.h156
-rw-r--r--usr.sbin/i4b/isdntel/display.c252
-rw-r--r--usr.sbin/i4b/isdntel/files.c306
-rw-r--r--usr.sbin/i4b/isdntel/isdntel.894
-rw-r--r--usr.sbin/i4b/isdntel/main.c395
-rw-r--r--usr.sbin/i4b/isdntelctl/Makefile5
-rw-r--r--usr.sbin/i4b/isdntelctl/isdntelctl.878
-rw-r--r--usr.sbin/i4b/isdntelctl/main.c203
-rw-r--r--usr.sbin/i4b/isdntest/Makefile8
-rw-r--r--usr.sbin/i4b/isdntest/isdntest.8103
-rw-r--r--usr.sbin/i4b/isdntest/main.c738
-rw-r--r--usr.sbin/i4b/isdntrace/1tr6.c754
-rw-r--r--usr.sbin/i4b/isdntrace/Makefile8
-rw-r--r--usr.sbin/i4b/isdntrace/cable.txt60
-rw-r--r--usr.sbin/i4b/isdntrace/isdntrace.8205
-rw-r--r--usr.sbin/i4b/isdntrace/pcause_1tr6.c164
-rw-r--r--usr.sbin/i4b/isdntrace/pcause_1tr6.h68
-rw-r--r--usr.sbin/i4b/isdntrace/pcause_q850.c328
-rw-r--r--usr.sbin/i4b/isdntrace/pcause_q850.h109
-rw-r--r--usr.sbin/i4b/isdntrace/q921.c275
-rw-r--r--usr.sbin/i4b/isdntrace/q931.c783
-rw-r--r--usr.sbin/i4b/isdntrace/q931_util.c697
-rw-r--r--usr.sbin/i4b/isdntrace/q932_fac.c926
-rw-r--r--usr.sbin/i4b/isdntrace/q932_fac.h174
-rw-r--r--usr.sbin/i4b/isdntrace/trace.c809
-rw-r--r--usr.sbin/i4b/isdntrace/trace.h90
-rw-r--r--usr.sbin/i4b/man/Makefile5
-rw-r--r--usr.sbin/i4b/man/daic.498
-rw-r--r--usr.sbin/i4b/man/i4b.4108
-rw-r--r--usr.sbin/i4b/man/i4bctl.450
-rw-r--r--usr.sbin/i4b/man/i4bipr.498
-rw-r--r--usr.sbin/i4b/man/i4bisppp.4107
-rw-r--r--usr.sbin/i4b/man/i4bq921.449
-rw-r--r--usr.sbin/i4b/man/i4bq931.449
-rw-r--r--usr.sbin/i4b/man/i4brbch.450
-rw-r--r--usr.sbin/i4b/man/i4btel.452
-rw-r--r--usr.sbin/i4b/man/i4btrc.452
-rw-r--r--usr.sbin/i4b/man/isic.4380
94 files changed, 26456 insertions, 1 deletions
diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile
index 60a7a5f..ce29976 100644
--- a/usr.sbin/Makefile
+++ b/usr.sbin/Makefile
@@ -1,5 +1,5 @@
# From: @(#)Makefile 5.20 (Berkeley) 6/12/93
-# $Id: Makefile,v 1.139 1998/12/27 16:43:15 phk Exp $
+# $Id: Makefile,v 1.140 1998/12/27 21:30:39 phk Exp $
# XXX MISSING: mkproto
SUBDIR= IPXrouted \
@@ -22,6 +22,7 @@ SUBDIR= IPXrouted \
dev_mkdb \
diskpart \
edquota \
+ i4b \
inetd \
iostat \
ipfstat \
diff --git a/usr.sbin/i4b/Makefile b/usr.sbin/i4b/Makefile
new file mode 100644
index 0000000..3c12d78
--- /dev/null
+++ b/usr.sbin/i4b/Makefile
@@ -0,0 +1,4 @@
+SUBDIR = isdntrace isdndebug isdnd alawulaw man isdntest \
+ isdntel isdntelctl isdnmonitor isdndecode
+
+.include <bsd.subdir.mk>
diff --git a/usr.sbin/i4b/Makefile.inc b/usr.sbin/i4b/Makefile.inc
new file mode 100644
index 0000000..691d738
--- /dev/null
+++ b/usr.sbin/i4b/Makefile.inc
@@ -0,0 +1,14 @@
+# if you don't like curses stuff in the daemon (i.e. don't intend
+# to ever run it in the foreground but are using the monitoring
+# utilities instead) define this to compile it without.
+#I4B_WITHOUT_CURSES = 1
+
+# if you would like monitoring support, define this
+I4B_EXTERNAL_MONITOR = 1
+
+# for the security conscious type: restrict monitoring to the
+# local machine by not compiling any tcp/ip support for monitoring
+# at all
+#I4B_NOTCPIP_MONITOR = 1
+
+.include "${.CURDIR}/../../Makefile.inc"
diff --git a/usr.sbin/i4b/alawulaw/Makefile b/usr.sbin/i4b/alawulaw/Makefile
new file mode 100644
index 0000000..1daa481
--- /dev/null
+++ b/usr.sbin/i4b/alawulaw/Makefile
@@ -0,0 +1,7 @@
+PROG = alaw2ulaw
+SRC = alaw2ulaw.c
+CFLAGS += -Wall -g -DDEBUG
+LINKS = ${BINDIR}/alaw2ulaw ${BINDIR}/ulaw2alaw
+MAN1 = alaw2ulaw.1 ulaw2alaw.1
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/i4b/alawulaw/alaw2ulaw.1 b/usr.sbin/i4b/alawulaw/alaw2ulaw.1
new file mode 100644
index 0000000..fea7fa5
--- /dev/null
+++ b/usr.sbin/i4b/alawulaw/alaw2ulaw.1
@@ -0,0 +1,70 @@
+.\"
+.\" Copyright (c) 1998 Hellmuth Michaelis. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id: alaw2ulaw.1,v 1.3 1998/12/05 18:02:35 hm Exp $
+.\"
+.\" last edit-date: [Sat Dec 5 17:57:34 1998]
+.\"
+.\" -hm writing manual pages
+.\"
+.\"
+.Dd January 23, 1998
+.Dt alaw2ulaw 1
+.Sh NAME
+.Nm alaw2ulaw
+.Nd convert sound data
+.Sh SYNOPSIS
+.Nm
+.Sh DESCRIPTION
+.Nm alaw2ulaw
+is part of the isdn4bsd package and is used convert sound data between
+uLaw coded data to ALaw coded data and vice versa.
+.Pp
+It reads data from stdin and outputs converted data to stdout.
+.Pp
+In case it is run as
+.Em alaw2ulaw
+it converts ALaw input data to uLaw output.
+.Pp
+In case it is run as
+.Em ulaw2alaw
+it converts uLaw input data to ALaw output.
+.Pp
+
+.Sh EXAMPLES
+The command:
+.Bd -literal -offset indent
+alaw2ulaw <file.alaw >file.ulaw
+.Ed
+.Pp
+converts ALaw input data file file.alaw to uLaw output file file.ulaw.
+
+.Sh STANDARDS
+ITU Recommendations G.711
+
+.Sh AUTHOR
+The
+.Nm
+utility and this man page were written by Hellmuth Michaelis. He can be
+contacted at hm@kts.org.
diff --git a/usr.sbin/i4b/alawulaw/alaw2ulaw.c b/usr.sbin/i4b/alawulaw/alaw2ulaw.c
new file mode 100644
index 0000000..d13e41d
--- /dev/null
+++ b/usr.sbin/i4b/alawulaw/alaw2ulaw.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 1997 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * convert a-law / u-law sound files
+ * ---------------------------------
+ *
+ * last edit-date: [Sat Dec 5 17:57:56 1998]
+ *
+ * $Id: alaw2ulaw.c,v 1.2 1998/12/05 18:02:36 hm Exp $
+ *
+ * -hm telephony is ready
+ *
+ *---------------------------------------------------------------------------*/
+
+#include <string.h>
+#include <unistd.h>
+
+#define BUF_SIZ 2048
+
+unsigned char alaw_ulaw[];
+unsigned char ulaw_alaw[];
+
+int main(int argc, char *argv[])
+{
+ int i, j;
+ unsigned char buffer[BUF_SIZ];
+ char *p;
+ unsigned char *cp;
+
+ if((p = rindex(*argv, '/')) != NULL)
+ p++;
+ else
+ p = *argv;
+
+ if(!strcmp(p, "ulaw2alaw"))
+ {
+ cp = ulaw_alaw;
+ }
+ else if(!strcmp(p, "alaw2ulaw"))
+ {
+ cp = alaw_ulaw;
+ }
+ else
+ {
+ return(1);
+ }
+
+ while(((j = read(0, buffer, BUF_SIZ)) > 0))
+ {
+ for(i = 0; i < j; i++)
+ buffer[i] = cp[buffer[i]];
+ write(1, buffer, j);
+ }
+ return(0);
+}
+
+unsigned char alaw_ulaw[] = {
+ 0x002a, 0x00a9, 0x005f, 0x00e3, 0x001f, 0x009f, 0x0048, 0x00c8,
+ 0x0039, 0x00b9, 0x006f, 0x00f7, 0x001f, 0x009f, 0x0055, 0x00d7,
+ 0x0022, 0x00a1, 0x005b, 0x00dd, 0x001f, 0x009f, 0x0040, 0x00c0,
+ 0x0031, 0x00b1, 0x0067, 0x00eb, 0x001f, 0x009f, 0x004e, 0x00cf,
+ 0x002e, 0x00ad, 0x0063, 0x00e7, 0x001f, 0x009f, 0x004c, 0x00cc,
+ 0x003d, 0x00bd, 0x0077, 0x00ff, 0x001f, 0x009f, 0x0059, 0x00db,
+ 0x0026, 0x00a5, 0x005d, 0x00df, 0x001f, 0x009f, 0x0044, 0x00c4,
+ 0x0035, 0x00b5, 0x006b, 0x00ef, 0x001f, 0x009f, 0x0051, 0x00d3,
+ 0x0028, 0x00a7, 0x005f, 0x00e3, 0x001f, 0x009f, 0x0046, 0x00c6,
+ 0x0037, 0x00b7, 0x006f, 0x00f7, 0x001f, 0x009f, 0x0053, 0x00d5,
+ 0x0020, 0x009f, 0x005b, 0x00dd, 0x001f, 0x009f, 0x003f, 0x00bf,
+ 0x002f, 0x00af, 0x0067, 0x00eb, 0x001f, 0x009f, 0x004d, 0x00ce,
+ 0x002c, 0x00ab, 0x0063, 0x00e7, 0x001f, 0x009f, 0x004a, 0x00ca,
+ 0x003b, 0x00bb, 0x0077, 0x00ff, 0x001f, 0x009f, 0x0057, 0x00d9,
+ 0x0024, 0x00a3, 0x005d, 0x00df, 0x001f, 0x009f, 0x0042, 0x00c2,
+ 0x0033, 0x00b3, 0x006b, 0x00ef, 0x001f, 0x009f, 0x004f, 0x00d1,
+ 0x002b, 0x00aa, 0x0063, 0x00e3, 0x001f, 0x009f, 0x0049, 0x00c9,
+ 0x003a, 0x00ba, 0x0077, 0x00f7, 0x001f, 0x009f, 0x0057, 0x00d7,
+ 0x0023, 0x00a2, 0x005d, 0x00dd, 0x001f, 0x009f, 0x0041, 0x00c1,
+ 0x0032, 0x00b2, 0x006b, 0x00eb, 0x001f, 0x009f, 0x004f, 0x00cf,
+ 0x002f, 0x00ae, 0x0067, 0x00e7, 0x001f, 0x009f, 0x004d, 0x00cd,
+ 0x003e, 0x00be, 0x00ff, 0x00ff, 0x001f, 0x009f, 0x005b, 0x00db,
+ 0x0027, 0x00a6, 0x005f, 0x00df, 0x001f, 0x009f, 0x0045, 0x00c5,
+ 0x0036, 0x00b6, 0x006f, 0x00ef, 0x001f, 0x009f, 0x0053, 0x00d3,
+ 0x0029, 0x00a8, 0x005f, 0x00e3, 0x001f, 0x009f, 0x0047, 0x00c7,
+ 0x0038, 0x00b8, 0x006f, 0x00f7, 0x001f, 0x009f, 0x0055, 0x00d5,
+ 0x0021, 0x00a0, 0x005b, 0x00dd, 0x001f, 0x009f, 0x003f, 0x00bf,
+ 0x0030, 0x00b0, 0x0067, 0x00eb, 0x001f, 0x009f, 0x004e, 0x00ce,
+ 0x002d, 0x00ac, 0x0063, 0x00e7, 0x001f, 0x009f, 0x004b, 0x00cb,
+ 0x003c, 0x00bc, 0x0077, 0x00ff, 0x001f, 0x009f, 0x0059, 0x00d9,
+ 0x0025, 0x00a4, 0x005d, 0x00df, 0x001f, 0x009f, 0x0043, 0x00c3,
+ 0x0034, 0x00b4, 0x006b, 0x00ef, 0x001f, 0x009f, 0x0051, 0x00d1
+};
+
+unsigned char ulaw_alaw[] = {
+ 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc,
+ 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc,
+ 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc,
+ 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00fc, 0x00ac,
+ 0x0050, 0x00d0, 0x0010, 0x0090, 0x0070, 0x00f0, 0x0030, 0x00b0,
+ 0x0040, 0x00c0, 0x0000, 0x0080, 0x0060, 0x00e0, 0x0020, 0x00a0,
+ 0x00d8, 0x0018, 0x0098, 0x0078, 0x00f8, 0x0038, 0x00b8, 0x0048,
+ 0x00c8, 0x0008, 0x0088, 0x0068, 0x00e8, 0x0028, 0x00a8, 0x00d6,
+ 0x0096, 0x0076, 0x00f6, 0x0036, 0x00b6, 0x0046, 0x00c6, 0x0006,
+ 0x0086, 0x0066, 0x00e6, 0x0026, 0x00a6, 0x00de, 0x009e, 0x00fe,
+ 0x00fe, 0x00be, 0x00be, 0x00ce, 0x00ce, 0x008e, 0x008e, 0x00ee,
+ 0x00ee, 0x00d2, 0x00d2, 0x00f2, 0x00f2, 0x00c2, 0x00c2, 0x00e2,
+ 0x00e2, 0x00e2, 0x00da, 0x00da, 0x00da, 0x00da, 0x00fa, 0x00fa,
+ 0x00fa, 0x00fa, 0x00ca, 0x00ca, 0x00ca, 0x00ca, 0x00ea, 0x00ea,
+ 0x00ea, 0x00ea, 0x00ea, 0x00ea, 0x00eb, 0x00eb, 0x00eb, 0x00eb,
+ 0x00eb, 0x00eb, 0x00eb, 0x00eb, 0x00eb, 0x00eb, 0x00eb, 0x00eb,
+ 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd,
+ 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd,
+ 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd,
+ 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd, 0x00fd,
+ 0x00d1, 0x0011, 0x0091, 0x0071, 0x00f1, 0x0031, 0x00b1, 0x0041,
+ 0x00c1, 0x0001, 0x0081, 0x0061, 0x00e1, 0x0021, 0x00a1, 0x0059,
+ 0x00d9, 0x0019, 0x0099, 0x0079, 0x00f9, 0x0039, 0x00b9, 0x0049,
+ 0x00c9, 0x0009, 0x0089, 0x0069, 0x00e9, 0x0029, 0x00a9, 0x0057,
+ 0x0017, 0x0097, 0x0077, 0x00f7, 0x0037, 0x00b7, 0x0047, 0x00c7,
+ 0x0007, 0x0087, 0x0067, 0x00e7, 0x0027, 0x00a7, 0x00df, 0x009f,
+ 0x009f, 0x00ff, 0x00ff, 0x00bf, 0x00bf, 0x00cf, 0x00cf, 0x008f,
+ 0x008f, 0x00ef, 0x00ef, 0x00af, 0x00af, 0x00d3, 0x00d3, 0x00f3,
+ 0x00f3, 0x00f3, 0x00c3, 0x00c3, 0x00c3, 0x00c3, 0x00e3, 0x00e3,
+ 0x00e3, 0x00e3, 0x00db, 0x00db, 0x00db, 0x00db, 0x00fb, 0x00fb,
+ 0x00fb, 0x00fb, 0x00fb, 0x00fb, 0x00cb, 0x00cb, 0x00cb, 0x00cb,
+ 0x00cb, 0x00cb, 0x00cb, 0x00cb, 0x00eb, 0x00eb, 0x00eb, 0x00eb
+};
+
+/* EOF */
diff --git a/usr.sbin/i4b/alawulaw/ulaw2alaw.1 b/usr.sbin/i4b/alawulaw/ulaw2alaw.1
new file mode 100644
index 0000000..4c43c15
--- /dev/null
+++ b/usr.sbin/i4b/alawulaw/ulaw2alaw.1
@@ -0,0 +1,70 @@
+.\"
+.\" Copyright (c) 1998 Hellmuth Michaelis. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id: ulaw2alaw.1,v 1.3 1998/12/05 18:02:37 hm Exp $
+.\"
+.\" last edit-date: [Sat Dec 5 17:58:07 1998]
+.\"
+.\" -hm writing manual pages
+.\"
+.\"
+.Dd January 23, 1998
+.Dt ulaw2alaw 1
+.Sh NAME
+.Nm ulaw2alaw
+.Nd convert sound data
+.Sh SYNOPSIS
+.Nm
+.Sh DESCRIPTION
+.Nm ulaw2alaw
+is part of the isdn4bsd package and is used convert sound data between
+uLaw coded data to ALaw coded data and vice versa.
+.Pp
+It reads data from stdin and outputs converted data to stdout.
+.Pp
+In case it is run as
+.Em alaw2ulaw
+it converts ALaw input data to uLaw output.
+.Pp
+In case it is run as
+.Em ulaw2alaw
+it converts uLaw input data to ALaw output.
+.Pp
+
+.Sh EXAMPLES
+The command:
+.Bd -literal -offset indent
+ulaw2alaw <file.ulaw >file.alaw
+.Ed
+.Pp
+converts uLaw input data file file.ulaw to ALaw output file file.alaw.
+
+.Sh STANDARDS
+ITU Recommendations G.711
+
+.Sh AUTHOR
+The
+.Nm
+utility and this man page were written by Hellmuth Michaelis. He can be
+contacted at hm@kts.org.
diff --git a/usr.sbin/i4b/isdnd/Makefile b/usr.sbin/i4b/isdnd/Makefile
new file mode 100644
index 0000000..2bda2bb
--- /dev/null
+++ b/usr.sbin/i4b/isdnd/Makefile
@@ -0,0 +1,32 @@
+
+PROG = isdnd
+
+SRCS = rc_parse.y rc_scan.l main.c rc_config.c log.c curses.c \
+ process.c rates.c msghdl.c fsm.c support.c timer.c \
+ exec.c dial.c monitor.c pcause.c controller.c alias.c \
+ y.tab.h
+
+COPTS += -I${.CURDIR}/../isdnmonitor -I${.CURDIR}/../isdntel -I${.OBJDIR}
+
+# compile debug support
+COPTS += -DDEBUG
+
+# enable rtprio usage
+COPTS += -DUSE_RTPRIO
+
+MAN8 = isdnd.8
+MAN5 = isdnd.rc.5 isdnd.rates.5 isdnd.acct.5
+
+.include <bsd.prog.mk>
+
+.if !defined(I4B_WITHOUT_CURSES)
+COPTS += -DUSE_CURSES
+LDADD += -lcurses
+.endif
+
+.if defined(I4B_EXTERNAL_MONITOR)
+COPTS += -DI4B_EXTERNAL_MONITOR
+.if defined(I4B_NOTCPIP_MONITOR)
+COPTS += -DI4B_NOTCPIP_MONITOR
+.endif
+.endif
diff --git a/usr.sbin/i4b/isdnd/alias.c b/usr.sbin/i4b/isdnd/alias.c
new file mode 100644
index 0000000..b802776
--- /dev/null
+++ b/usr.sbin/i4b/isdnd/alias.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * isdnd - common aliasfile handling
+ * =================================
+ *
+ * NOTE: this has to stay in sync with isdntel/alias.c to be able
+ * to share a common aliasfile!
+ *
+ * $Id: alias.c,v 1.5 1998/12/05 18:03:03 hm Exp $
+ *
+ * last edit-date: [Sat Dec 5 18:05:40 1998]
+ *
+ *----------------------------------------------------------------------------*/
+
+#include "isdnd.h"
+
+static struct alias *firsta = NULL;
+
+#define MAXBUFSZ 256
+
+static void free_alias(struct alias *ptr);
+
+/*---------------------------------------------------------------------------*
+ * read in and init aliases
+ *---------------------------------------------------------------------------*/
+void
+init_alias(char *filename)
+{
+ FILE *fp;
+ char buffer[MAXBUFSZ + 1];
+ char number[MAXBUFSZ + 1];
+ char name[MAXBUFSZ + 1];
+ char *s, *d;
+ struct alias *newa = NULL;
+ struct alias *lasta = NULL;
+
+ firsta = NULL;
+
+ if((fp = fopen(filename, "r")) == NULL)
+ {
+ log(LL_ERR, "init_alias: error opening aliasfile %s: %s!", filename, strerror(errno));
+ exit(1);
+ }
+
+ while((fgets(buffer, MAXBUFSZ, fp)) != NULL)
+ {
+ if(buffer[0] == '#' || buffer[0] == ' ' ||
+ buffer[0] == '\t' || buffer[0] == '\n')
+ {
+ continue;
+ }
+
+ s = buffer;
+ d = number;
+
+ while(*s && (isdigit(*s)))
+ *d++ = *s++;
+
+ *d = '\0';
+
+ while(*s && (isspace(*s)))
+ s++;
+
+ d = name;
+
+ while(*s && (isprint(*s)))
+ *d++ = *s++;
+
+ *d = '\0';
+
+ if((strlen(number) > 1) && (strlen(name) > 1))
+ {
+ if((newa = (struct alias *) malloc(sizeof(struct alias))) == NULL)
+ {
+ log(LL_ERR, "init_alias: malloc failed for struct alias!\n");
+ exit(1);
+ }
+
+ if((newa->number = (char *) malloc(strlen(number)+1)) == NULL)
+ {
+ log(LL_ERR, "init_alias: malloc failed for number alias!\n");
+ exit(1);
+ }
+
+ if((newa->name = (char *) malloc(strlen(name)+1)) == NULL)
+ {
+ log(LL_ERR, "init_alias: malloc failed for name alias!\n");
+ exit(1);
+ }
+
+ strcpy(newa->name, name);
+ strcpy(newa->number, number);
+ newa->next = NULL;
+
+ if(firsta == NULL)
+ {
+ firsta = newa;
+ }
+ else
+ {
+ lasta->next = newa;
+ }
+ lasta = newa;
+ }
+ }
+ fclose(fp);
+}
+
+/*---------------------------------------------------------------------------*
+ * free all aliases
+ *---------------------------------------------------------------------------*/
+void
+free_aliases(void)
+{
+ free_alias(firsta);
+}
+
+/*---------------------------------------------------------------------------*
+ * free aliases
+ *---------------------------------------------------------------------------*/
+static void
+free_alias(struct alias *ptr)
+{
+
+ if(ptr == NULL)
+ return;
+
+ if(ptr->next != NULL)
+ free_alias(ptr->next);
+
+ if(ptr->number != NULL)
+ free(ptr->number);
+
+ if(ptr->name != NULL)
+ free(ptr->name);
+
+ free(ptr);
+}
+
+/*---------------------------------------------------------------------------*
+ * try to find alias for number. if no alias found, return number.
+ *---------------------------------------------------------------------------*/
+char *
+get_alias(char *number)
+{
+ struct alias *ca = NULL;
+
+ if(firsta == NULL)
+ return(number);
+
+ ca = firsta;
+
+ for(;;)
+ {
+ if(strlen(number) == strlen(ca->number))
+ {
+ if(!(strcmp(number, ca->number)))
+ return(ca->name);
+ }
+ if(ca->next == NULL)
+ break;
+ ca = ca->next;
+ }
+ return(number);
+}
+
+/* EOF */
diff --git a/usr.sbin/i4b/isdnd/config.h b/usr.sbin/i4b/isdnd/config.h
new file mode 100644
index 0000000..22c947a
--- /dev/null
+++ b/usr.sbin/i4b/isdnd/config.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * i4b daemon - compile time configuration header file
+ * ---------------------------------------------------
+ *
+ * $Id: config.h,v 1.6 1998/12/05 18:03:05 hm Exp $
+ *
+ * last edit-date: [Sat Dec 5 18:05:56 1998]
+ *
+ *---------------------------------------------------------------------------*/
+
+#ifndef _CONFIG_H_
+#define _CONFIG_H_
+
+/* general values */
+
+#define UMASK 022 /* file creation perm mask */
+#define CFG_ENTRY_MAX 32 /* max no of config entries */
+#define ISDN_CTRL_MAX 4 /* max no of controllers */
+#define MAX_RE 8 /* max regular expression entries */
+
+/* monitor max values */
+
+#define MAX_MHOSTS 8 /* max allowed monitor hosts */
+
+/* timouts */
+
+#define TIMEOUT_CONNECT_ACTIVE 30 /* seconds to wait for MSG_CONN_ACT */
+
+/* utility programs forked */
+
+#define REGPROG_DEF "program" /* default program to use for regexpr */
+#define ANSWERPROG_DEF "answer" /* default telephone answer program */
+
+#endif /* _CONFIG_H_ */
+
+/* EOF */
diff --git a/usr.sbin/i4b/isdnd/controller.c b/usr.sbin/i4b/isdnd/controller.c
new file mode 100644
index 0000000..b3cfcf9
--- /dev/null
+++ b/usr.sbin/i4b/isdnd/controller.c
@@ -0,0 +1,329 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * i4b daemon - controller state support routines
+ * ----------------------------------------------
+ *
+ * $Id: controller.c,v 1.10 1998/12/05 18:03:06 hm Exp $
+ *
+ * last edit-date: [Sat Dec 5 18:06:10 1998]
+ *
+ *---------------------------------------------------------------------------*/
+
+#include "isdnd.h"
+
+/*--------------------------------------------------------------------------*
+ * init controller state table entry
+ *--------------------------------------------------------------------------*/
+int
+init_controller_state(int controller, int ctrl_type, int card_type, int tei)
+{
+ if((controller < 0) || (controller >= ncontroller))
+ {
+ log(LL_ERR, "init_controller_state: invalid controller number [%d]!", controller);
+ return(ERROR);
+ }
+
+ /* init controller tab */
+
+ if(ctrl_type == CTRL_PASSIVE)
+ {
+ if((card_type > CARD_TYPEP_UNK) &&
+ (card_type <= CARD_TYPEP_MAX))
+ {
+ isdn_ctrl_tab[controller].ctrl_type = ctrl_type;
+ isdn_ctrl_tab[controller].card_type = card_type;
+ isdn_ctrl_tab[controller].state = CTRL_UP;
+ isdn_ctrl_tab[controller].stateb1 = CHAN_IDLE;
+ isdn_ctrl_tab[controller].stateb2 = CHAN_IDLE;
+ isdn_ctrl_tab[controller].freechans = MAX_CHANCTRL;
+ isdn_ctrl_tab[controller].tei = tei;
+ log(LL_DMN, "init_controller_state: controller %d is %s",
+ controller,
+ name_of_controller(isdn_ctrl_tab[controller].ctrl_type,
+ isdn_ctrl_tab[controller].card_type));
+ }
+ else
+ {
+ log(LL_ERR, "init_controller_state: unknown card type %d", card_type);
+ return(ERROR);
+ }
+
+ }
+ else if(ctrl_type == CTRL_DAIC)
+ {
+ isdn_ctrl_tab[controller].ctrl_type = ctrl_type;
+ isdn_ctrl_tab[controller].card_type = card_type;
+ isdn_ctrl_tab[controller].state = CTRL_DOWN;
+ isdn_ctrl_tab[controller].stateb1 = CHAN_IDLE;
+ isdn_ctrl_tab[controller].stateb2 = CHAN_IDLE;
+ isdn_ctrl_tab[controller].freechans = MAX_CHANCTRL;
+ isdn_ctrl_tab[controller].tei = -1;
+ log(LL_DMN, "init_controller_state: controller %d is %s",
+ controller,
+ name_of_controller(isdn_ctrl_tab[controller].ctrl_type,
+ isdn_ctrl_tab[controller].card_type));
+ }
+ else
+ {
+ /* XXX active controller init here !!! */
+
+ log(LL_ERR, "init_controller_state: unknown controller type %d", ctrl_type);
+ return(ERROR);
+ }
+ return(GOOD);
+}
+
+/*--------------------------------------------------------------------------*
+ * set controller state to UP/DOWN
+ *--------------------------------------------------------------------------*/
+int
+set_controller_state(int controller, int state)
+{
+ if((controller < 0) || (controller >= ncontroller))
+ {
+ log(LL_ERR, "set_controller_state: invalid controller number [%d]!", controller);
+ return(ERROR);
+ }
+
+ if(state == CTRL_UP)
+ {
+ isdn_ctrl_tab[controller].state = CTRL_UP;
+ DBGL(DL_CNST, (log(LL_DBG, "set_controller_state: controller [%d] set UP!", controller)));
+ }
+ else if (state == CTRL_DOWN)
+ {
+ isdn_ctrl_tab[controller].state = CTRL_DOWN;
+ DBGL(DL_CNST, (log(LL_DBG, "set_controller_state: controller [%d] set DOWN!", controller)));
+ }
+ else
+ {
+ log(LL_ERR, "set_controller_state: invalid controller state [%d]!", state);
+ return(ERROR);
+ }
+ return(GOOD);
+}
+
+/*--------------------------------------------------------------------------*
+ * get controller state
+ *--------------------------------------------------------------------------*/
+int
+get_controller_state(int controller)
+{
+ if((controller < 0) || (controller >= ncontroller))
+ {
+ log(LL_ERR, "set_controller_state: invalid controller number [%d]!", controller);
+ return(ERROR);
+ }
+ return(isdn_ctrl_tab[controller].state);
+}
+
+/*--------------------------------------------------------------------------*
+ * decrement number of free channels for controller
+ *--------------------------------------------------------------------------*/
+int
+decr_free_channels(int controller)
+{
+ if((controller < 0) || (controller >= ncontroller))
+ {
+ log(LL_ERR, "decr_free_channels: invalid controller number [%d]!", controller);
+ return(ERROR);
+ }
+ if(isdn_ctrl_tab[controller].freechans > 0)
+ {
+ (isdn_ctrl_tab[controller].freechans)--;
+ DBGL(DL_CNST, (log(LL_DBG, "decr_free_channels: ctrl %d, now %d chan free", controller, isdn_ctrl_tab[controller].freechans)));
+ return(GOOD);
+ }
+ else
+ {
+ log(LL_ERR, "decr_free_channels: controller [%d] already 0 free chans!", controller);
+ return(ERROR);
+ }
+}
+
+/*--------------------------------------------------------------------------*
+ * increment number of free channels for controller
+ *--------------------------------------------------------------------------*/
+int
+incr_free_channels(int controller)
+{
+ if((controller < 0) || (controller >= ncontroller))
+ {
+ log(LL_ERR, "incr_free_channels: invalid controller number [%d]!", controller);
+ return(ERROR);
+ }
+ if(isdn_ctrl_tab[controller].freechans < MAX_CHANCTRL)
+ {
+ (isdn_ctrl_tab[controller].freechans)++;
+ DBGL(DL_CNST, (log(LL_DBG, "incr_free_channels: ctrl %d, now %d chan free", controller, isdn_ctrl_tab[controller].freechans)));
+ return(GOOD);
+ }
+ else
+ {
+ log(LL_ERR, "incr_free_channels: controller [%d] already 2 free chans!", controller);
+ return(ERROR);
+ }
+}
+
+/*--------------------------------------------------------------------------*
+ * get number of free channels for controller
+ *--------------------------------------------------------------------------*/
+int
+get_free_channels(int controller)
+{
+ if((controller < 0) || (controller >= ncontroller))
+ {
+ log(LL_ERR, "get_free_channels: invalid controller number [%d]!", controller);
+ return(ERROR);
+ }
+ DBGL(DL_CNST, (log(LL_DBG, "get_free_channels: ctrl %d, %d chan free", controller, isdn_ctrl_tab[controller].freechans)));
+ return(isdn_ctrl_tab[controller].freechans);
+}
+
+/*--------------------------------------------------------------------------*
+ * set channel state to busy
+ *--------------------------------------------------------------------------*/
+int
+set_channel_busy(int controller, int channel)
+{
+ if((controller < 0) || (controller >= ncontroller))
+ {
+ log(LL_ERR, "set_channel_busy: invalid controller number [%d]!", controller);
+ return(ERROR);
+ }
+
+ switch(channel)
+ {
+ case CHAN_B1:
+ if(isdn_ctrl_tab[controller].stateb1 == CHAN_RUN)
+ {
+ DBGL(DL_CNST, (log(LL_DBG, "set_channel_busy: controller [%d] channel B1 already busy!", controller)));
+ }
+ else
+ {
+ isdn_ctrl_tab[controller].stateb1 = CHAN_RUN;
+ DBGL(DL_CNST, (log(LL_DBG, "set_channel_busy: controller [%d] channel B1 set to BUSY!", controller)));
+ }
+ break;
+
+ case CHAN_B2:
+ if(isdn_ctrl_tab[controller].stateb2 == CHAN_RUN)
+ {
+ DBGL(DL_CNST, (log(LL_DBG, "set_channel_busy: controller [%d] channel B2 already busy!", controller)));
+ }
+ else
+ {
+ isdn_ctrl_tab[controller].stateb2 = CHAN_RUN;
+ DBGL(DL_CNST, (log(LL_DBG, "set_channel_busy: controller [%d] channel B2 set to BUSY!", controller)));
+ }
+ break;
+
+ default:
+ log(LL_ERR, "set_channel_busy: controller [%d], invalid channel [%d]!", controller, channel);
+ return(ERROR);
+ break;
+ }
+ return(GOOD);
+}
+
+/*--------------------------------------------------------------------------*
+ * set channel state to idle
+ *--------------------------------------------------------------------------*/
+int
+set_channel_idle(int controller, int channel)
+{
+ if((controller < 0) || (controller >= ncontroller))
+ {
+ log(LL_ERR, "set_channel_idle: invalid controller number [%d]!", controller);
+ return(ERROR);
+ }
+
+ switch(channel)
+ {
+ case CHAN_B1:
+ if(isdn_ctrl_tab[controller].stateb1 == CHAN_IDLE)
+ {
+ DBGL(DL_CNST, (log(LL_DBG, "set_channel_idle: controller [%d] channel B1 already idle!", controller)));
+ }
+ else
+ {
+ isdn_ctrl_tab[controller].stateb1 = CHAN_IDLE;
+ DBGL(DL_CNST, (log(LL_DBG, "set_channel_idle: controller [%d] channel B1 set to IDLE!", controller)));
+ }
+ break;
+
+ case CHAN_B2:
+ if(isdn_ctrl_tab[controller].stateb2 == CHAN_IDLE)
+ {
+ DBGL(DL_CNST, (log(LL_DBG, "set_channel_idle: controller [%d] channel B2 already idle!", controller)));
+ }
+ else
+ {
+ isdn_ctrl_tab[controller].stateb2 = CHAN_IDLE;
+ DBGL(DL_CNST, (log(LL_DBG, "set_channel_idle: controller [%d] channel B2 set to IDLE!", controller)));
+ }
+ break;
+
+ default:
+ log(LL_ERR, "set_channel_idle: controller [%d], invalid channel [%d]!", controller, channel);
+ return(ERROR);
+ break;
+ }
+ return(GOOD);
+}
+
+/*--------------------------------------------------------------------------*
+ * return channel state
+ *--------------------------------------------------------------------------*/
+int
+ret_channel_state(int controller, int channel)
+{
+ if((controller < 0) || (controller >= ncontroller))
+ {
+ log(LL_ERR, "ret_channel_state: invalid controller number [%d]!", controller);
+ return(ERROR);
+ }
+
+ switch(channel)
+ {
+ case CHAN_B1:
+ return(isdn_ctrl_tab[controller].stateb1);
+ break;
+
+ case CHAN_B2:
+ return(isdn_ctrl_tab[controller].stateb2);
+ break;
+
+ default:
+ log(LL_ERR, "ret_channel_state: controller [%d], invalid channel [%d]!", controller, channel);
+ return(ERROR);
+ break;
+ }
+ return(ERROR);
+}
+
+/* EOF */
diff --git a/usr.sbin/i4b/isdnd/curses.c b/usr.sbin/i4b/isdnd/curses.c
new file mode 100644
index 0000000..b505382
--- /dev/null
+++ b/usr.sbin/i4b/isdnd/curses.c
@@ -0,0 +1,633 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * i4b daemon - curses fullscreen output
+ * -------------------------------------
+ *
+ * $Id: curses.c,v 1.27 1998/12/05 18:03:08 hm Exp $
+ *
+ * last edit-date: [Sat Dec 5 18:06:24 1998]
+ *
+ *---------------------------------------------------------------------------*/
+
+#ifdef USE_CURSES
+
+#include "isdnd.h"
+
+#define CHPOS(cfgp) (((cfgp)->isdncontrollerused*2) + (cfgp)->isdnchannelused)
+
+/*---------------------------------------------------------------------------*
+ * init curses fullscreen display
+ *---------------------------------------------------------------------------*/
+void
+init_screen(void)
+{
+ char buffer[512];
+ int uheight, lheight;
+ int i, j;
+ cfg_entry_t *p;
+
+ initscr(); /* curses init */
+
+ if((COLS < 80) || (LINES < 24))
+ {
+ log(LL_ERR, "ERROR, minimal screensize must be 80x24, is %dx%d, terminating!",COLS, LINES);
+ do_exit(1);
+ }
+
+ noecho();
+ raw();
+
+ uheight = ncontroller * 2; /* cards * b-channels */
+ lheight = LINES - uheight - 6 + 1; /* rest of display */
+
+ if((upper_w = newwin(uheight, COLS, UPPER_B, 0)) == NULL)
+ {
+ log(LL_ERR, "ERROR, curses init upper window, terminating!");
+ exit(1);
+ }
+
+ if((mid_w = newwin(1, COLS, UPPER_B+uheight+1, 0)) == NULL)
+ {
+ log(LL_ERR, "ERROR, curses init mid window, terminating!");
+ exit(1);
+ }
+
+ if((lower_w = newwin(lheight, COLS, UPPER_B+uheight+3, 0)) == NULL)
+ {
+ log(LL_ERR, "ERROR, curses init lower window, LINES = %d, lheight = %d, uheight = %d, terminating!", LINES, lheight, uheight);
+ exit(1);
+ }
+
+ scrollok(lower_w, 1);
+
+ sprintf(buffer, "----- isdn controller channel state ------------- isdnd %02d.%02d.%d [pid %d] -", VERSION, REL, STEP, (int)getpid());
+
+ while(strlen(buffer) < COLS)
+ strcat(buffer, "-");
+
+ move(0, 0);
+ standout();
+ addstr(buffer);
+ standend();
+
+ move(1, 0);
+ /* 01234567890123456789012345678901234567890123456789012345678901234567890123456789 */
+ addstr("c tei b remote iface dir outbytes obps inbytes ibps units");
+
+ sprintf(buffer, "----- isdn userland interface state ------------------------------------------");
+ while(strlen(buffer) < COLS)
+ strcat(buffer, "-");
+
+ move(uheight+2, 0);
+ standout();
+ addstr(buffer);
+ standend();
+
+ sprintf(buffer, "----- isdnd logfile display --------------------------------------------------");
+ while(strlen(buffer) < COLS)
+ strcat(buffer, "-");
+
+ move(uheight+4, 0);
+ standout();
+ addstr(buffer);
+ standend();
+
+ move(uheight+5, 0);
+ addstr("Date Time Typ Information Description");
+
+ refresh();
+
+ for(i=0, j=0; i <= ncontroller; i++, j+=2)
+ {
+ if(isdn_ctrl_tab[i].tei == -1)
+ mvwprintw(upper_w, j, H_CNTL, "%d --- 1 ", i);
+ else
+ mvwprintw(upper_w, j, H_CNTL, "%d %3d 1 ", i, isdn_ctrl_tab[i].tei);
+ mvwprintw(upper_w, j+1, H_CNTL, " L12 2 ");
+ }
+ wrefresh(upper_w);
+
+ for(i=0, j=0; i < nentries; i++) /* walk thru all entries */
+ {
+ p = &cfg_entry_tab[i]; /* get ptr to enry */
+
+ mvwprintw(mid_w, 0, j, "%s%d ", bdrivername(p->usrdevicename), p->usrdeviceunit);
+
+ p->fs_position = j;
+
+ j += ((strlen(bdrivername(p->usrdevicename)) + (p->usrdeviceunit > 9 ? 2 : 1) + 1));
+ }
+ wrefresh(mid_w);
+
+ wmove(lower_w, 0, 0);
+ wrefresh(lower_w);
+
+ curses_ready = 1;
+}
+
+/*---------------------------------------------------------------------------*
+ * curses menu for fullscreen command mode
+ *---------------------------------------------------------------------------*/
+void
+do_menu(void)
+{
+ static char *menu[WMITEMS] =
+ {
+ "1 - (D)isplay refresh",
+ "2 - (H)angup (choose a channel)",
+ "3 - (R)eread config file",
+ "4 - (Q)uit the program",
+ };
+
+ WINDOW *menu_w;
+ int c;
+ int mpos;
+ fd_set set;
+ struct timeval timeout;
+
+ /* create a new window in the lower screen area */
+
+ if((menu_w = newwin(WMENU_HGT, WMENU_LEN, WMENU_POSLN, WMENU_POSCO )) == NULL)
+ {
+ log(LL_WRN, "ERROR, curses init menu window!");
+ return;
+ }
+
+ /* create a border around the window */
+
+ box(menu_w, '|', '-');
+
+ /* add a title */
+
+ wstandout(menu_w);
+ mvwaddstr(menu_w, 0, (WMENU_LEN / 2) - (strlen(WMENU_TITLE) / 2), WMENU_TITLE);
+ wstandend(menu_w);
+
+ /* fill the window with the menu options */
+
+ for(mpos=0; mpos <= (WMITEMS-1); mpos++)
+ mvwaddstr(menu_w, mpos + 2, 2, menu[mpos]);
+
+ /* highlight the first menu option */
+
+ mpos = 0;
+ wstandout(menu_w);
+ mvwaddstr(menu_w, mpos + 2, 2, menu[mpos]);
+ wstandend(menu_w);
+
+ /* input loop */
+
+ for(;;)
+ {
+ wrefresh(menu_w);
+
+ FD_ZERO(&set);
+ FD_SET(STDIN_FILENO, &set);
+ timeout.tv_sec = WMTIMEOUT;
+ timeout.tv_usec = 0;
+
+ /* if no char is available within timeout, exit menu*/
+
+ if((select(STDIN_FILENO + 1, &set, NULL, NULL, &timeout)) <= 0)
+ goto mexit;
+
+ c = wgetch(menu_w);
+
+ switch(c)
+ {
+ case ' ':
+ case '\t': /* hilite next option */
+ mvwaddstr(menu_w, mpos + 2, 2, menu[mpos]);
+ mpos++;
+ if(mpos >= WMITEMS)
+ mpos = 0;
+ wstandout(menu_w);
+ mvwaddstr(menu_w, mpos + 2, 2, menu[mpos]);
+ wstandend(menu_w);
+ break;
+
+ case ('0'+WREFRESH+1): /* display refresh */
+ case 'D':
+ case 'd':
+ wrefresh(curscr);
+ goto mexit;
+
+ case ('0'+WQUIT+1): /* quit program */
+ case 'Q':
+ case 'q':
+ do_exit(0);
+ goto mexit;
+
+ case ('0'+WHANGUP+1): /* hangup connection */
+ case 'H':
+ case 'h':
+ display_chans();
+ goto mexit;
+
+ case ('0'+WREREAD+1): /* reread config file */
+ case 'R':
+ case 'r':
+ rereadconfig(42);
+ goto mexit;
+
+ case '\n':
+ case '\r': /* exec highlighted option */
+ switch(mpos)
+ {
+ case WREFRESH:
+ wrefresh(curscr);
+ break;
+
+ case WQUIT:
+ do_exit(0);
+ break;
+
+ case WHANGUP:
+ display_chans();
+ break;
+
+ case WREREAD:
+ rereadconfig(42);
+ break;
+ }
+ goto mexit;
+ break;
+
+ default:
+ goto mexit;
+ break;
+ }
+ }
+
+mexit:
+ /* delete the menu window */
+
+ delwin(menu_w);
+
+ /* re-display the original lower window contents */
+
+ touchwin(lower_w);
+ wrefresh(lower_w);
+}
+
+/*---------------------------------------------------------------------------*
+ * display the charge in units
+ *---------------------------------------------------------------------------*/
+void
+display_charge(cfg_entry_t *cep)
+{
+ mvwprintw(upper_w, CHPOS(cep), H_UNITS, "%d", cep->charge);
+ wclrtoeol(upper_w);
+ wrefresh(upper_w);
+}
+
+/*---------------------------------------------------------------------------*
+ * display the calculated charge in units
+ *---------------------------------------------------------------------------*/
+void
+display_ccharge(cfg_entry_t *cep, int units)
+{
+ mvwprintw(upper_w, CHPOS(cep), H_UNITS, "(%d)", units);
+ wclrtoeol(upper_w);
+ wrefresh(upper_w);
+}
+
+/*---------------------------------------------------------------------------*
+ * display accounting information
+ *---------------------------------------------------------------------------*/
+void
+display_acct(cfg_entry_t *cep)
+{
+ mvwprintw(upper_w, CHPOS(cep), H_OUT, "%-10d", cep->outbytes);
+ mvwprintw(upper_w, CHPOS(cep), H_OUTBPS, "%-4d", cep->outbps);
+ mvwprintw(upper_w, CHPOS(cep), H_IN, "%-10d", cep->inbytes);
+ mvwprintw(upper_w, CHPOS(cep), H_INBPS, "%-4d", cep->inbps);
+ wrefresh(upper_w);
+}
+
+/*---------------------------------------------------------------------------*
+ * display connect information
+ *---------------------------------------------------------------------------*/
+void
+display_connect(cfg_entry_t *cep)
+{
+ char buffer[256];
+
+ /* remote telephone number */
+
+ if(aliasing)
+ {
+ if(cep->direction == DIR_IN)
+ sprintf(buffer, "%s", get_alias(cep->real_phone_incoming));
+ else
+ sprintf(buffer, "%s", get_alias(cep->remote_phone_dialout));
+ }
+ else
+ {
+ if(cep->direction == DIR_IN)
+ sprintf(buffer, "%s/%s", cep->name, cep->real_phone_incoming);
+ else
+ sprintf(buffer, "%s/%s", cep->name, cep->remote_phone_dialout);
+ }
+
+ buffer[H_IFN - H_TELN - 1] = '\0';
+
+ mvwprintw(upper_w, CHPOS(cep), H_TELN, "%s", buffer);
+
+ /* interface */
+
+ mvwprintw(upper_w, CHPOS(cep), H_IFN, "%s%d ",
+ bdrivername(cep->usrdevicename), cep->usrdeviceunit);
+
+ mvwprintw(upper_w, CHPOS(cep), H_IO,
+ cep->direction == DIR_OUT ? "out" : "in");
+
+ mvwprintw(upper_w, CHPOS(cep), H_OUT, "-");
+ mvwprintw(upper_w, CHPOS(cep), H_OUTBPS, "-");
+ mvwprintw(upper_w, CHPOS(cep), H_IN, "-");
+ mvwprintw(upper_w, CHPOS(cep), H_INBPS, "-");
+
+ if(do_bell)
+ display_bell();
+
+ wrefresh(upper_w);
+}
+
+/*---------------------------------------------------------------------------*
+ * erase line at disconnect time
+ *---------------------------------------------------------------------------*/
+void
+display_disconnect(cfg_entry_t *cep)
+{
+ wmove(upper_w, CHPOS(cep),
+ H_TELN);
+ wclrtoeol(upper_w);
+ wrefresh(upper_w);
+
+ if(do_bell)
+ display_bell();
+
+}
+
+/*---------------------------------------------------------------------------*
+ * display interface up/down information
+ *---------------------------------------------------------------------------*/
+void
+display_updown(cfg_entry_t *cep, int updown)
+{
+ if(updown)
+ wstandend(mid_w);
+ else
+ wstandout(mid_w);
+
+ mvwprintw(mid_w, 0, cep->fs_position, "%s%d ",
+ bdrivername(cep->usrdevicename), cep->usrdeviceunit);
+
+ wstandend(mid_w);
+ wrefresh(mid_w);
+}
+
+/*---------------------------------------------------------------------------*
+ * display interface up/down information
+ *---------------------------------------------------------------------------*/
+void
+display_l12stat(int controller, int layer, int state)
+{
+ if(controller > ncontroller)
+ return;
+ if(!(layer == 1 || layer == 2))
+ return;
+
+ if(state)
+ wstandout(upper_w);
+ else
+ wstandend(upper_w);
+
+ if(layer == 1)
+ {
+ mvwprintw(upper_w, (controller*2)+1, H_TEI+1, "1");
+ if(!state)
+ mvwprintw(upper_w, (controller*2)+1, H_TEI+2, "2");
+ }
+ else if(layer == 2)
+ {
+ mvwprintw(upper_w, (controller*2)+1, H_TEI+2, "2");
+ if(state)
+ mvwprintw(upper_w, (controller*2)+1, H_TEI+1, "1");
+ }
+
+ wstandend(upper_w);
+ wrefresh(upper_w);
+}
+
+/*---------------------------------------------------------------------------*
+ * display TEI
+ *---------------------------------------------------------------------------*/
+void
+display_tei(int controller, int tei)
+{
+ if(controller > ncontroller)
+ return;
+
+ if(tei == -1)
+ mvwprintw(upper_w, controller*2, H_TEI, "---");
+ else
+ mvwprintw(upper_w, controller*2, H_TEI, "%3d", tei);
+
+ wrefresh(upper_w);
+}
+
+/*---------------------------------------------------------------------------*
+ * display bell :-)
+ *---------------------------------------------------------------------------*/
+void
+display_bell(void)
+{
+ static char bell[1] = { 0x07 };
+ write(STDOUT_FILENO, &bell[0], 1);
+}
+
+/*---------------------------------------------------------------------------*
+ * display channel information for shutdown
+ *---------------------------------------------------------------------------*/
+void
+display_chans(void)
+{
+ char buffer[80];
+ int i;
+ int cnt = 0;
+ WINDOW *chan_w;
+ int nlines, ncols, pos_x, pos_y;
+ fd_set set;
+ struct timeval timeout;
+ cfg_entry_t *cep = NULL;
+
+ /* need this later to close the connection */
+ struct ctlr_chan {
+ int cntl;
+ int chn;
+ } *cc = NULL;
+
+ for (i = 0; i < ncontroller; i++)
+ {
+ if((get_controller_state(i)) != CTRL_UP)
+ continue;
+ if((ret_channel_state(i, CHAN_B1)) == CHAN_RUN)
+ cnt++;
+ if((ret_channel_state(i, CHAN_B2)) == CHAN_RUN)
+ cnt++;
+ }
+
+ if(cnt > 0)
+ {
+ if ((cc = (struct ctlr_chan *)malloc (cnt *
+ sizeof (struct ctlr_chan))) == NULL)
+ {
+ return;
+ }
+ nlines = cnt + 4;
+ ncols = 60;
+ }
+ else
+ {
+ nlines = 5;
+ ncols = 22;
+ }
+
+ pos_y = WMENU_POSLN + 4;
+ pos_x = WMENU_POSCO + 10;
+
+ /* create a new window in the lower screen area */
+
+ if((chan_w = newwin(nlines, ncols, pos_y, pos_x )) == NULL)
+ {
+ log(LL_WRN, "ERROR, curses init channel window!");
+ if (cnt > 0)
+ free(cc);
+ return;
+ }
+
+ /* create a border around the window */
+
+ box(chan_w, '|', '-');
+
+ /* add a title */
+
+ wstandout(chan_w);
+ mvwaddstr(chan_w, 0, (ncols / 2) - (strlen("Channels") / 2), "Channels");
+ wstandend(chan_w);
+
+ /* no active channels */
+ if (cnt == 0)
+ {
+ mvwaddstr(chan_w, 2, 2, "No active channels");
+ wrefresh(chan_w);
+ sleep(1);
+
+ /* delete the channels window */
+
+ delwin(chan_w);
+ return;
+ }
+
+ nlines = 2;
+ ncols = 1;
+
+ for (i = 0; i < ncontroller; i++)
+ {
+ if((get_controller_state(i)) != CTRL_UP)
+ continue;
+
+ if((ret_channel_state(i, CHAN_B1)) == CHAN_RUN)
+ {
+ sprintf(buffer, "%d - Controller %d channel %s", ncols, i, "B1");
+ mvwaddstr(chan_w, nlines, 2, buffer);
+ cc[ncols - 1].cntl = i;
+ cc[ncols - 1].chn = CHAN_B1;
+ nlines++;
+ ncols++;
+ }
+ if((ret_channel_state(i, CHAN_B2)) == CHAN_RUN)
+ {
+ sprintf(buffer, "%d - Controller %d channel %s", ncols, i, "B2");
+ mvwaddstr(chan_w, nlines, 2, buffer);
+ cc[ncols - 1].cntl = i;
+ cc[ncols - 1].chn = CHAN_B2;
+ nlines++;
+ ncols++;
+ }
+ }
+
+ for(;;)
+ {
+ wrefresh(chan_w);
+
+ FD_ZERO(&set);
+ FD_SET(STDIN_FILENO, &set);
+ timeout.tv_sec = WMTIMEOUT;
+ timeout.tv_usec = 0;
+
+ /* if no char is available within timeout, exit menu*/
+
+ if((select(STDIN_FILENO + 1, &set, NULL, NULL, &timeout)) <= 0)
+ break;
+
+ ncols = wgetch(chan_w);
+
+ if (!(isdigit(ncols)))
+ {
+ display_bell();
+ continue;
+ }
+
+ nlines = ncols - '0';
+
+ if ((nlines == 0) || (nlines > cnt))
+ {
+ display_bell();
+ continue;
+ }
+
+ if((cep = get_cep_by_cc(cc[nlines-1].cntl, cc[nlines-1].chn))
+ != NULL)
+ {
+ log(LL_CHD, "%05d %s manual disconnect (fullscreen menu)", cep->cdid, cep->name);
+ cep->hangup = 1;
+ break;
+ }
+ }
+
+ free(cc);
+
+ /* delete the channels window */
+
+ delwin(chan_w);
+}
+
+#endif
+
+/* EOF */
diff --git a/usr.sbin/i4b/isdnd/dial.c b/usr.sbin/i4b/isdnd/dial.c
new file mode 100644
index 0000000..4308f98
--- /dev/null
+++ b/usr.sbin/i4b/isdnd/dial.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * i4b daemon - dial handling routines
+ * -----------------------------------
+ *
+ * $Id: dial.c,v 1.6 1998/12/05 18:03:09 hm Exp $
+ *
+ * last edit-date: [Sat Dec 5 18:06:36 1998]
+ *
+ *---------------------------------------------------------------------------*/
+
+#include "isdnd.h"
+
+/*---------------------------------------------------------------------------*
+ * select the first remote number to dial according to the
+ * dial strategy
+ *---------------------------------------------------------------------------*/
+void
+select_first_dialno(cfg_entry_t *cep)
+{
+ int i, j;
+
+ if(cep->remote_numbers_count < 1)
+ {
+ log(LL_ERR, "select_first_dialno: remote_numbers_count < 1!");
+ return;
+ }
+
+ if(cep->remote_numbers_count == 1)
+ {
+ strcpy(cep->remote_phone_dialout, cep->remote_numbers[0].number);
+ DBGL(DL_DIAL, (log(LL_DBG, "select_first_dialno: only one no, no = %s", cep->remote_phone_dialout)));
+ cep->last_remote_number = 0;
+ return;
+ }
+
+ if(cep->remote_numbers_handling == RNH_FIRST)
+ {
+ strcpy(cep->remote_phone_dialout, cep->remote_numbers[0].number);
+ DBGL(DL_DIAL, (log(LL_DBG, "select_first_dialno: use first, no = %s", cep->remote_phone_dialout)));
+ cep->last_remote_number = 0;
+ return;
+ }
+
+ i = cep->last_remote_number;
+
+ for(j = cep->remote_numbers_count; j > 0; j--)
+ {
+ if(cep->remote_numbers[i].flag == RNF_SUCC)
+ {
+ if(cep->remote_numbers_handling == RNH_LAST)
+ {
+ strcpy(cep->remote_phone_dialout, cep->remote_numbers[i].number);
+ DBGL(DL_DIAL, (log(LL_DBG, "select_first_dialno: use last, no = %s", cep->remote_phone_dialout)));
+ cep->last_remote_number = i;
+ return;
+ }
+ else
+ {
+ if(++i >= cep->remote_numbers_count)
+ i = 0;
+
+ strcpy(cep->remote_phone_dialout, cep->remote_numbers[i].number);
+ DBGL(DL_DIAL, (log(LL_DBG, "select_first_dialno: use next, no = %s", cep->remote_phone_dialout)));
+ cep->last_remote_number = i;
+ return;
+ }
+ }
+
+ if(++i >= cep->remote_numbers_count)
+ i = 0;
+ }
+ strcpy(cep->remote_phone_dialout, cep->remote_numbers[0].number);
+ DBGL(DL_DIAL, (log(LL_DBG, "select_first_dialno: no last found (use 0), no = %s", cep->remote_phone_dialout)));
+ cep->last_remote_number = 0;
+}
+
+/*---------------------------------------------------------------------------*
+ * select next remote number to dial (last was unsuccesfull)
+ *---------------------------------------------------------------------------*/
+void
+select_next_dialno(cfg_entry_t *cep)
+{
+ if(cep->remote_numbers_count < 1)
+ {
+ log(LL_ERR, "select_next_dialno: remote_numbers_count < 1!");
+ return;
+ }
+
+ if(cep->remote_numbers_count == 1)
+ {
+ strcpy(cep->remote_phone_dialout, cep->remote_numbers[0].number);
+ DBGL(DL_DIAL, (log(LL_DBG, "select_next_dialno: only one no, no = %s", cep->remote_phone_dialout)));
+ cep->last_remote_number = 0;
+ return;
+ }
+
+ /* mark last try as bad */
+
+ cep->remote_numbers[cep->last_remote_number].flag = RNF_IDLE;
+
+ /* next one to try */
+
+ cep->last_remote_number++;
+
+ if(cep->last_remote_number >= cep->remote_numbers_count)
+ cep->last_remote_number = 0;
+
+ strcpy(cep->remote_phone_dialout, cep->remote_numbers[cep->last_remote_number].number);
+
+ DBGL(DL_DIAL, (log(LL_DBG, "select_next_dialno: index=%d, no=%s",
+ cep->last_remote_number,
+ cep->remote_numbers[cep->last_remote_number].number)));
+}
+
+/*---------------------------------------------------------------------------*
+ * dial succeded, store this number as the last successful
+ *---------------------------------------------------------------------------*/
+void
+select_this_dialno(cfg_entry_t *cep)
+{
+ cep->remote_numbers[cep->last_remote_number].flag = RNF_SUCC;
+
+ DBGL(DL_DIAL, (log(LL_DBG, "select_this_dialno: index = %d, no = %s",
+ cep->last_remote_number,
+ cep->remote_numbers[cep->last_remote_number].number)));
+}
+
+/* EOF */
diff --git a/usr.sbin/i4b/isdnd/exec.c b/usr.sbin/i4b/isdnd/exec.c
new file mode 100644
index 0000000..1ed81a1
--- /dev/null
+++ b/usr.sbin/i4b/isdnd/exec.c
@@ -0,0 +1,280 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * exec.h - supplemental program/script execution
+ * ----------------------------------------------
+ *
+ * $Id: exec.c,v 1.10 1998/12/05 18:03:11 hm Exp $
+ *
+ * last edit-date: [Sat Dec 5 18:06:49 1998]
+ *
+ *---------------------------------------------------------------------------*/
+
+#include "isdnd.h"
+
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#define MAX_PIDS 32
+
+static struct pid_tab {
+ pid_t pid;
+ cfg_entry_t *cep;
+} pid_tab[MAX_PIDS];
+
+/*---------------------------------------------------------------------------*
+ * SIGCHLD signal handler
+ *---------------------------------------------------------------------------*/
+void
+sigchild_handler(int sig)
+{
+ int retstat;
+ register int i;
+ pid_t pid;
+
+ if((pid = waitpid(-1, &retstat, WNOHANG)) <= 0)
+ {
+ log(LL_ERR, "ERROR, waitpid: %s", strerror(errno));
+ do_exit(1);
+ }
+ else
+ {
+ if(WIFEXITED(retstat))
+ {
+ DBGL(DL_PROC, (log(LL_DBG, "normal child (pid=%d) termination, exitstat = %d",
+ pid, WEXITSTATUS(retstat))));
+ }
+ else if(WIFSIGNALED(retstat))
+ {
+ if(WCOREDUMP(retstat))
+ log(LL_WRN, "child (pid=%d) termination due to signal %d (coredump)",
+ pid, WTERMSIG(retstat));
+ else
+ log(LL_WRN, "child (pid=%d) termination due to signal %d",
+ pid, WTERMSIG(retstat));
+ }
+ }
+
+ /* check if hangup required */
+
+ for(i=0; i < MAX_PIDS; i++)
+ {
+ if(pid_tab[i].pid == pid)
+ {
+ if(pid_tab[i].cep->cdid != CDID_UNUSED)
+ {
+ DBGL(DL_PROC, (log(LL_DBG, "sigchild_handler: scheduling hangup for cdid %d, pid %d",
+ pid_tab[i].cep->cdid, pid_tab[i].pid)));
+ pid_tab[i].cep->hangup = 1;
+ }
+ pid_tab[i].pid = 0;
+ break;
+ }
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * execute prog as a subprocess and pass an argumentlist
+ *---------------------------------------------------------------------------*/
+pid_t
+exec_prog(char *prog, char **arglist)
+{
+ char tmp[MAXPATHLEN];
+ char path[MAXPATHLEN+1];
+ pid_t pid;
+ int a;
+
+ sprintf(path, "%s/%s", ETCPATH, prog);
+
+ arglist[0] = path;
+
+ tmp[0] = '\0';
+
+ for(a=1; arglist[a] != NULL; ++a )
+ {
+ strcat(tmp, " " );
+ strcat(tmp, arglist[a]);
+ }
+
+ DBGL(DL_PROC, (log(LL_DBG, "exec_prog: %s, args:%s", path, tmp)));
+
+ switch(pid = fork())
+ {
+ case -1: /* error */
+ log(LL_ERR, "ERROR, exec_prog/fork: %s", strerror(errno));
+ do_exit(1);
+ case 0: /* child */
+ break;
+ default: /* parent */
+ return(pid);
+ }
+
+ /* this is the child now */
+
+ if(execvp(path,arglist) < 0 )
+ _exit(127);
+
+ return(-1);
+}
+
+/*---------------------------------------------------------------------------*
+ * run interface up/down script
+ *---------------------------------------------------------------------------*/
+int
+exec_connect_prog(cfg_entry_t *cep, const char *prog, int link_down)
+{
+ char *argv[32], **av = argv;
+ char devicename[MAXPATHLEN], addr[100];
+ char *device;
+ int s;
+ struct ifreq ifr;
+
+ /* the obvious things */
+ device = bdrivername(cep->usrdevicename);
+ sprintf(devicename, "%s%d", device, cep->usrdeviceunit);
+ *av++ = (char*)prog;
+ *av++ = "-d";
+ *av++ = devicename;
+ *av++ = "-f";
+ *av++ = link_down ? "down" : "up";
+
+ /* try to figure AF_INET address of interface */
+ addr[0] = '\0';
+ memset(&ifr, 0, sizeof ifr);
+ ifr.ifr_addr.sa_family = AF_INET;
+ strncpy(ifr.ifr_name, devicename, sizeof(ifr.ifr_name));
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s >= 0) {
+ if (ioctl(s, SIOCGIFADDR, (caddr_t)&ifr) >= 0) {
+ struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
+ strcpy(addr, inet_ntoa(sin->sin_addr));
+ *av++ = "-a";
+ *av++ = addr;
+ }
+ close(s);
+ }
+
+ /* terminate argv */
+ *av++ = NULL;
+
+ return exec_prog((char*)prog, argv);
+}
+
+/*---------------------------------------------------------------------------*
+ * run answeringmachine application
+ *---------------------------------------------------------------------------*/
+int
+exec_answer(cfg_entry_t *cep)
+{
+ char *argv[32];
+ u_char devicename[MAXPATHLEN];
+ int pid;
+ char *device;
+
+ device = bdrivername(cep->usrdevicename);
+
+ sprintf(devicename, "/dev/i4b%s%d", device, cep->usrdeviceunit);
+
+ argv[0] = cep->answerprog;
+ argv[1] = "-D";
+ argv[2] = devicename;
+ argv[3] = "-d";
+ argv[4] = "unknown";
+ argv[5] = "-s";
+ argv[6] = "unknown";
+ argv[7] = NULL;
+
+ /* if destination telephone number avail, add it as argument */
+
+ if(*cep->local_phone_incoming)
+ argv[4] = cep->local_phone_incoming;
+
+ /* if source telephone number avail, add it as argument */
+
+ if(*cep->real_phone_incoming)
+ argv[6] = cep->real_phone_incoming;
+
+ if(*cep->display)
+ {
+ argv[7] = "-t";
+ argv[8] = cep->display;
+ argv[9] = NULL;
+ }
+
+ /* exec program */
+
+ DBGL(DL_PROC, (log(LL_DBG, "exec_answer: prog=[%s]", cep->answerprog)));
+
+ pid = exec_prog(cep->answerprog, argv);
+
+ /* enter pid and conf ptr entry addr into table */
+
+ if(pid != -1)
+ {
+ int i;
+
+ for(i=0; i < MAX_PIDS; i++)
+ {
+ if(pid_tab[i].pid == 0)
+ {
+ pid_tab[i].pid = pid;
+ pid_tab[i].cep = cep;
+ break;
+ }
+ }
+ return(GOOD);
+ }
+ return(ERROR);
+}
+
+/*---------------------------------------------------------------------------*
+ * check if a connection has an outstanding process, if yes, kill it
+ *---------------------------------------------------------------------------*/
+void
+check_and_kill(cfg_entry_t *cep)
+{
+ int i;
+
+ for(i=0; i < MAX_PIDS; i++)
+ {
+ if(pid_tab[i].cep == cep)
+ {
+ pid_t kp;
+
+ DBGL(DL_PROC, (log(LL_DBG, "check_and_kill: killing pid %d", pid_tab[i].pid)));
+
+ kp = pid_tab[i].pid;
+ pid_tab[i].pid = 0;
+ kill(kp, SIGHUP);
+ break;
+ }
+ }
+}
+
+/* EOF */
diff --git a/usr.sbin/i4b/isdnd/fsm.c b/usr.sbin/i4b/isdnd/fsm.c
new file mode 100644
index 0000000..13d5778
--- /dev/null
+++ b/usr.sbin/i4b/isdnd/fsm.c
@@ -0,0 +1,446 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * FSM for isdnd
+ * -------------
+ *
+ * $Id: fsm.c,v 1.15 1998/12/05 18:03:12 hm Exp $
+ *
+ * last edit-date: [Sat Dec 5 18:07:31 1998]
+ *
+ *---------------------------------------------------------------------------*/
+
+#include "isdnd.h"
+
+/* table of state descriptions */
+
+static char *state_text[N_STATES] = {
+ "idle",
+ "dialing",
+ "waitdialretry",
+ "dialretry",
+
+ "pcb-dialing",
+ "pcb-dialfail",
+ "pcb-waitcall",
+
+ "acb-waitdisc",
+ "acb-waitdial",
+ "acb-dialing",
+ "acb-dialfail",
+
+ "accepted",
+ "connected",
+ "waitdisconnect",
+ "down",
+ "alert",
+
+ "Illegal State"
+};
+
+/* table of event descriptions */
+
+static char *event_text[N_EVENTS] = {
+
+ /* incoming messages */
+
+ "msg-con-ind",
+ "msg-con-act-ind",
+ "msg-disc-ind",
+ "msg-dialout",
+
+ /* local events */
+
+ "timeout",
+ "disconnect-req",
+ "callback-req",
+ "alert-req",
+
+ /* illegal */
+
+ "Illegal Event"
+};
+
+/*---------------------------------------------------------------------------*
+ * illegal state default action
+ *---------------------------------------------------------------------------*/
+static void
+F_ill(cfg_entry_t *cep)
+{
+ DBGL(DL_STATE, (log(LL_DBG, "F_ill: Illegal State reached !!!")));
+}
+
+/*---------------------------------------------------------------------------*
+ * No change, No action
+ *---------------------------------------------------------------------------*/
+static void
+F_NcNa(cfg_entry_t *cep)
+{
+}
+
+/*---------------------------------------------------------------------------*
+ * incoming CONNECT, accepting call
+ *---------------------------------------------------------------------------*/
+static void
+F_MCI(cfg_entry_t *cep)
+{
+ DBGL(DL_STATE, (log(LL_DBG, "F_MCI: tx SETUP_RESP_ACCEPT")));
+ sendm_connect_resp(cep, cep->cdid, SETUP_RESP_ACCEPT, 0);
+ start_timer(cep, TIMEOUT_CONNECT_ACTIVE);
+}
+
+/*---------------------------------------------------------------------------*
+ * incoming connect active, call is now active
+ *---------------------------------------------------------------------------*/
+static void
+F_MCAI(cfg_entry_t *cep)
+{
+ DBGL(DL_STATE, (log(LL_DBG, "F_MCAI: Connection active!")));
+
+ stop_timer(cep);
+
+ if((cep->dialin_reaction == REACT_ANSWER) &&
+ (cep->b1protocol == BPROT_NONE))
+ {
+ exec_answer(cep);
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * timeout
+ *---------------------------------------------------------------------------*/
+static void
+F_TIMO(cfg_entry_t *cep)
+{
+ DBGL(DL_STATE, (log(LL_DBG, "F_TIMO: Timout occured!")));
+ sendm_disconnect_req(cep, (CAUSET_I4B << 8) | CAUSE_I4B_NORMAL);
+ cep->cdid = CDID_UNUSED;
+}
+
+/*---------------------------------------------------------------------------*
+ * incoming disconnect indication
+ *---------------------------------------------------------------------------*/
+static void
+F_IDIS(cfg_entry_t *cep)
+{
+ DBGL(DL_STATE, (log(LL_DBG, "F_IDIS: disconnect indication")));
+ cep->cdid = CDID_UNUSED;
+}
+
+/*---------------------------------------------------------------------------*
+ * local disconnect request
+ *---------------------------------------------------------------------------*/
+static void
+F_DRQ(cfg_entry_t *cep)
+{
+ DBGL(DL_STATE, (log(LL_DBG, "F_DRQ: local disconnect request")));
+ sendm_disconnect_req(cep, (CAUSET_I4B << 8) | CAUSE_I4B_NORMAL);
+}
+
+/*---------------------------------------------------------------------------*
+ * disconnect indication after local disconnect req
+ *---------------------------------------------------------------------------*/
+static void
+F_MDI(cfg_entry_t *cep)
+{
+ DBGL(DL_STATE, (log(LL_DBG, "F_MDI: disconnect indication, local disconnected")));
+ cep->cdid = CDID_UNUSED;
+}
+
+/*---------------------------------------------------------------------------*
+ * local requested outgoing dial
+ *---------------------------------------------------------------------------*/
+static void
+F_DIAL(cfg_entry_t *cep)
+{
+ DBGL(DL_STATE, (log(LL_DBG, "F_DIAL: local dial out request")));
+
+ if(cep->dialrandincr)
+ cep->randomtime = (random() & RANDOM_MASK) + cep->recoverytime;
+
+ cep->dial_count = 0;
+
+ select_first_dialno(cep);
+
+ sendm_connect_req(cep);
+}
+
+/*---------------------------------------------------------------------------*
+ * outgoing dial successfull
+ *---------------------------------------------------------------------------*/
+static void
+F_DOK(cfg_entry_t *cep)
+{
+ DBGL(DL_STATE, (log(LL_DBG, "F_DOK: dial out ok")));
+ select_this_dialno(cep);
+}
+
+/*---------------------------------------------------------------------------*
+ * outgoing dial fail (ST_SUSE !!!)
+ *---------------------------------------------------------------------------*/
+static void
+F_DFL(cfg_entry_t *cep)
+{
+ cep->last_release_time = time(NULL);
+
+ if(cep->dialouttype == DIALOUT_NORMAL)
+ {
+ cep->dial_count++;
+
+ if(cep->dial_count < cep->dialretries)
+ {
+ /* inside normal retry cycle */
+
+ DBGL(DL_STATE, (log(LL_DBG, "F_DFL: dial fail, dial retry")));
+ select_next_dialno(cep);
+ cep->cdid = CDID_RESERVED;
+ cep->state = ST_DIALRTMRCHD;
+ return;
+ }
+
+ /* retries exhausted */
+
+ if(!cep->usedown)
+ {
+ DBGL(DL_STATE, (log(LL_DBG, "F_DFL: dial retry fail, dial retries exhausted")));
+ dialresponse(cep, DSTAT_TFAIL);
+ cep->cdid = CDID_UNUSED;
+ cep->dial_count = 0;
+ cep->state = ST_IDLE;
+ return;
+ }
+
+ /* interface up/down active */
+
+ cep->down_retry_count++;
+
+ if(cep->down_retry_count > cep->downtries)
+ {
+ /* set interface down */
+ DBGL(DL_STATE, (log(LL_DBG, "F_DFL: dial retry cycle fail, setting interface down!")));
+ dialresponse(cep, DSTAT_PFAIL);
+ if_down(cep);
+ cep->state = ST_DOWN;
+ }
+ else
+ {
+ /* enter new dial retry cycle */
+ DBGL(DL_STATE, (log(LL_DBG, "F_DFL: dial retry cycle fail, enter new retry cycle!")));
+ select_next_dialno(cep);
+ cep->state = ST_DIALRTMRCHD;
+ }
+
+ cep->dial_count = 0;
+ cep->cdid = CDID_RESERVED;
+ }
+ else /* cdp->dialouttype == DIALOUT_CALLEDBACK */
+ {
+ DBGL(DL_STATE, (log(LL_DBG, "F_DFL: calledback dial done, wait for incoming call")));
+ cep->cdid = CDID_RESERVED;
+ cep->state = ST_PCB_WAITCALL;
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * local requested outgoing dial
+ *---------------------------------------------------------------------------*/
+static void
+F_ACBW(cfg_entry_t *cep)
+{
+ DBGL(DL_STATE, (log(LL_DBG, "F_ACBW: local callback, wait callback recovery time")));
+
+ if(cep->dialrandincr)
+ cep->randomtime = (random() & RANDOM_MASK) + cep->recoverytime;
+
+ cep->dial_count = 0;
+
+ cep->cdid = CDID_RESERVED;
+}
+
+/*---------------------------------------------------------------------------*
+ * active callback dialout retry (ST_SUSE !!!)
+ *---------------------------------------------------------------------------*/
+static void
+F_ACBR(cfg_entry_t *cep)
+{
+ cep->dial_count++;
+
+ if(cep->dial_count < cep->dialretries)
+ {
+ /* inside normal retry cycle */
+
+ DBGL(DL_STATE, (log(LL_DBG, "F_ACBR: dial fail, dial retry")));
+ select_next_dialno(cep);
+ cep->cdid = CDID_RESERVED;
+ cep->state = ST_ACB_DIALFAIL;
+ return;
+ }
+
+ /* retries exhausted */
+
+ if(!cep->usedown)
+ {
+ DBGL(DL_STATE, (log(LL_DBG, "F_ACBR: dial retry fail, dial retries exhausted")));
+ dialresponse(cep, DSTAT_TFAIL);
+ cep->cdid = CDID_UNUSED;
+ cep->dial_count = 0;
+ cep->state = ST_IDLE;
+ return;
+ }
+
+ /* interface up/down active */
+
+ cep->down_retry_count++;
+
+ if(cep->down_retry_count > cep->downtries)
+ {
+ /* set interface down */
+ DBGL(DL_STATE, (log(LL_DBG, "F_ACBR: dial retry cycle fail, setting interface down!")));
+ dialresponse(cep, DSTAT_PFAIL);
+ if_down(cep);
+ cep->state = ST_DOWN;
+ }
+ else
+ {
+ /* enter new dial retry cycle */
+ DBGL(DL_STATE, (log(LL_DBG, "F_ACBR: dial retry cycle fail, enter new retry cycle!")));
+ select_next_dialno(cep);
+ cep->state = ST_ACB_DIALFAIL;
+ }
+
+ cep->dial_count = 0;
+ cep->cdid = CDID_RESERVED;
+}
+
+/*---------------------------------------------------------------------------*
+ * local requested to send ALERT message
+ *---------------------------------------------------------------------------*/
+static void
+F_ALRT(cfg_entry_t *cep)
+{
+ DBGL(DL_STATE, (log(LL_DBG, "F_ALRT: local send alert request")));
+
+ cep->alert_time = cep->alert;
+
+ sendm_alert_req(cep);
+}
+
+/*---------------------------------------------------------------------------*
+ * isdn daemon state transition table
+ *---------------------------------------------------------------------------*/
+struct state_tab {
+ void(*func)(cfg_entry_t *cep); /* function to execute */
+ int newstate; /* next state */
+} state_tab[N_EVENTS][N_STATES] = {
+
+/* STATE: ST_IDLE ST_DIAL ST_DIALRTMRCHD ST_DIALRETRY ST_PCB_DIAL ST_PCB_DIALFAIL ST_PCB_WAITCALL ST_ACB_WAITDISC ST_ACB_WAITDIAL ST_ACB_DIAL ST_ACB_DIALFAIL ST_ACCEPTED ST_CONNECTED ST_WAITDISCI ST_DOWN ST_ALERT ST_ILLEGAL */
+/* -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
+/* messages */
+/* EV_MCI */{{F_MCI, ST_ACCEPTED}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_MCI, ST_ACCEPTED}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_MCI, ST_ACCEPTED}, {F_ill, ST_ILL}},
+/* EV_MCAI */{{F_ill, ST_ILL}, {F_DOK, ST_CONNECTED}, {F_ill, ST_ILL}, {F_DOK, ST_CONNECTED}, {F_DOK, ST_CONNECTED}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_DOK, ST_CONNECTED}, {F_ill, ST_ILL}, {F_MCAI,ST_CONNECTED}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}},
+/* EV_MDI */{{F_ill, ST_ILL}, {F_DFL, ST_SUSE}, {F_ill, ST_ILL}, {F_DFL, ST_SUSE}, {F_DFL, ST_SUSE}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ACBW,ST_ACB_WAITDIAL},{F_ill, ST_ILL}, {F_ACBR, ST_SUSE}, {F_ACBR,ST_SUSE}, {F_IDIS,ST_IDLE}, {F_IDIS,ST_IDLE}, {F_MDI, ST_IDLE}, {F_ill, ST_ILL}, {F_MDI, ST_IDLE}, {F_ill, ST_ILL}},
+/* EV_MDO */{{F_DIAL,ST_DIAL}, {F_NcNa,ST_DIAL}, {F_NcNa,ST_DIALRTMRCHD},{F_NcNa,ST_DIALRETRY}, {F_NcNa,ST_PCB_DIAL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}},
+
+/* local requests */
+/* EV_TIMO */{{F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_TIMO,ST_IDLE}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}},
+/* EV_DRQ */{{F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_DRQ, ST_WAITDISCI}, {F_NcNa,ST_WAITDISCI}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}},
+/* EV_CBRQ */{{F_NcNa,ST_ACB_WAITDIAL},{F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_NcNa,ST_ACB_WAITDIAL},{F_NcNa, ST_ACB_DIAL}, {F_NcNa,ST_ACB_DIALFAIL},{F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}},
+/* EV_ALRT */{{F_ALRT,ST_ALERT}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}},
+
+/* illegal */
+
+/* EV_ILL */{{F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}, {F_ill, ST_ILL}}
+};
+
+/*---------------------------------------------------------------------------*
+ * event handler
+ *---------------------------------------------------------------------------*/
+void
+next_state(cfg_entry_t *cep, int event)
+{
+ int currstate, newstate;
+
+ if(event > N_EVENTS)
+ {
+ log(LL_ERR, "FSM: event > N_EVENTS");
+ do_exit(1);
+ }
+
+ currstate = cep->state;
+
+ if(currstate > N_STATES)
+ {
+ log(LL_ERR, "FSM: currstate > N_STATES");
+ do_exit(1);
+ }
+
+ newstate = state_tab[event][currstate].newstate;
+
+ if(newstate > N_STATES)
+ {
+ log(LL_ERR, "FSM: newstate > N_STATES");
+ do_exit(1);
+ }
+
+ if(newstate != ST_SUSE)
+ {
+ DBGL(DL_STATE, (log(LL_DBG, "FSM event [%s]: [%s => %s]", event_text[event],
+ state_text[currstate],
+ state_text[newstate])));
+ }
+
+ (*state_tab[event][currstate].func)(cep);
+
+ if(newstate == ST_ILL)
+ {
+ log(LL_ERR, "FSM ILLEGAL STATE, event=%s: oldstate=%s => newstate=%s]",
+ event_text[event],
+ state_text[currstate],
+ state_text[newstate]);
+ }
+
+ if(newstate == ST_SUSE)
+ {
+ DBGL(DL_STATE, (log(LL_DBG, "FSM (SUSE) event [%s]: [%s => %s]", event_text[event],
+ state_text[currstate],
+ state_text[cep->state])));
+ }
+ else
+ {
+ cep->state = newstate;
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * return pointer to current state description
+ *---------------------------------------------------------------------------*/
+char *
+printstate(cfg_entry_t *cep)
+{
+ return((char *) state_text[cep->state]);
+}
+
+/* EOF */
diff --git a/usr.sbin/i4b/isdnd/isdnd.8 b/usr.sbin/i4b/isdnd/isdnd.8
new file mode 100644
index 0000000..9913487
--- /dev/null
+++ b/usr.sbin/i4b/isdnd/isdnd.8
@@ -0,0 +1,419 @@
+.\"
+.\" Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id: isdnd.8,v 1.20 1998/12/18 09:47:09 hm Exp $
+.\"
+.\" last edit-date: [Sat Dec 12 21:13:59 1998]
+.\"
+.Dd November 3, 1998
+.Dt isdnd 8
+.Sh NAME
+.Nm isdnd
+.Nd isdn4bsd ISDN connection management daemon
+.Sh SYNOPSIS
+.Nm isdnd
+.Op Fl b
+.Op Fl c Ar configfile
+.Op Fl d Ar debuglevel
+.Op Fl f
+.Op Fl F
+.Op Fl l
+.Op Fl L Ar logfile
+.Op Fl P
+.Op Fl r Ar device
+.Op Fl s Ar facility
+.Op Fl t Ar terminaltype
+.Op Fl u Ar charging unit length
+.Op Fl m
+.Sh DESCRIPTION
+.Nm Isdnd
+is the isdn4bsd package demon which manages all ISDN related connection
+and disconnection of ISDN devices supported by the package.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl b
+Bell: in full-screen mode, ring the bell when connecting
+or disconnecting a call.
+.It Fl c
+Use
+.Ar configfile
+as the name of the runtime configuration filename for
+.Nm isdnd
+instead of the default file
+.Li /etc/isdn/isdnd.rc .
+.It Fl d
+If debugging support is compiled into
+.Nm isdnd
+this option is used to specify the debugging level, or better which kind
+of debugging messages are displayed. The debugging level is the sum of the
+following values:
+.Pp
+.Bl -tag -width Ds -compact -offset indent
+.It Ar 0x001
+general debugging.
+.It Ar 0x002
+rates calculation.
+.It Ar 0x004
+timing calculations.
+.It Ar 0x008
+state transitions.
+.It Ar 0x010
+retry handling.
+.It Ar 0x020
+dialing.
+.It Ar 0x040
+process handling.
+.It Ar 0x080
+isdn4bsd kernel i/o calls.
+.It Ar 0x100
+controller and channel busy/free messages.
+.El
+.Pp
+The value can be specified in any number base supported by the
+.Xr sscanf 3
+library routine.
+.Pp
+In addition, this option accepts also the character 'n' as an argument to
+disable displaying debug messages on the full-screen display.
+.Pp
+.It Fl f
+Specifying this option causes
+.Nm isdnd
+to enter the full-screen mode of operation. When operating in this mode,
+entering the control character
+.Em Control-L
+causes the display to be refreshed and entering
+.Em Carriage-Return
+or
+.Em Enter
+will pop-up a command window. Because the
+.Nm
+daemon will not listen to messages while the command window is active,
+this command window will disappear automatically after 5 seconds without
+any command key press.
+.Pp
+While the command window is active,
+.Em Tab
+or
+.Em Space
+advances to the next menu item. To execute a command, press
+.Em Return
+or
+.Em Enter
+for the highlighted menu item, or enter the number corresponding to the
+item to be executed or enter the capitalized character in the menu item
+description.
+.It Fl l
+If this option is set, logging is not done via the
+.Xr syslogd 8
+facility but instead is appended to a file.
+.It Fl L
+Specifies the name of the logfile which is used when the option
+.Em -l
+is set.
+.It Fl P
+This option prints out the parsed and verified isdnd configuration in the same
+format as the isdnd.rc file. This output can be used as an isdnd.rc file. This
+feature is especially useful when debugging an isdnd.rc file to see, what the
+default settings of options are when they are not set in the isdnd.rc input
+file.
+.Pp
+The
+.Nm
+exits after the printout is done.
+.It Fl F
+This option prevents
+.Nm isdnd
+to detach from the controlling tty and become a daemon.
+.It Fl r
+In conjunction with the
+.Fl t
+option,
+.Ar device
+specifies a terminal device which becomes the controlling tty for
+.Nm isdnd
+and on which the full-screen mode output is displayed.
+.It Fl s
+This option may be used to specify the logging facility in case
+.Xr syslog 3
+logging is configured and another facility than the default LOCAL0
+facility shall be used. The facility is to be specified as an integer in
+the range 0-11 or 16-23 (see the file /usr/include/syslog.h).
+.It Fl t
+In conjunction with the
+.Fl f
+and
+.Fl r
+options,
+.Ar terminaltype
+specifies a terminal type or termcap entry name (such as vt220) for the device
+used for
+.Nm isdnd
+full-screen output. This is useful if an unused (no getty running) tty line is
+used for full-screen output for which no
+.Li TERM
+environment variable exists.
+.It Fl u
+Specifies the length of a charging unit in case the config file entry
+keyword
+.Em unitlenghtsrc
+is set to
+.Em cmdl .
+.It Fl m
+If the isdn daemon is compiled with local or remote monitoring support,
+this option disables all monitoring access. It overrides the config
+file option
+.Em monitor-allowed .
+.El
+.Pp
+.Sh INTERACTION WITH THE KERNEL
+.Nm Isdnd
+communicates with the kernel part of isdn4bsd by receiving status and
+event messages (
+.Xr read 2
+from device /dev/i4b ) and by transmitting commands and responses (
+.Xr ioctl 2
+from device /dev/i4b ).
+.Pp
+The messages and message parameters are documented in the include
+file
+.Em /usr/include/machine/i4b_ioctl.h .
+.Pp
+Supported command and response messages (ioctl's) to the kernel are:
+.Bl -tag -width Ds -compact -offset indent
+.It Ar I4B_CDID_REQ
+Request a unique Call Description IDentifier (cdid) which identifies
+uniquely a single interaction of the local D channel with the exchange.
+.It Ar I4B_CONNECT_REQ
+Actively request a call setup to a remote ISDN subscriber.
+.It Ar I4B_CONNECT_RESP
+Respond to an incoming call, either accept, reject or ignore it.
+.It Ar I4B_DISCONNECT_REQ
+Actively terminate a connection.
+.It Ar I4B_CTRL_INFO_REQ
+Request information about an installed ISDN controller card.
+.It Ar I4B_DIALOUT_RESP
+Give information about call setup to driver who requested dialing out.
+.It Ar I4B_TIMEOUT_UPD
+Update the kernels timeout value(s) in case of dynamically calculated
+shorthold mode timing changes.
+.It Ar I4B_UPDOWN_IND
+Inform the kernel userland drivers about interface soft up/down status
+changes.
+.It Ar I4B_CTRL_DOWNLOAD
+Download firmware to active card(s).
+.It Ar I4B_ACTIVE_DIAGNOSTIC
+Return diagnostic information from active cards.
+.El
+.Pp
+.Pp
+Supported status and event messages from the kernel are:
+.Bl -tag -width Ds -compact -offset indent
+.It Ar MSG_CONNECT_IND
+An incoming call from a remote ISDN user is indicated.
+.It Ar MSG_CONNECT_ACTIVE_IND
+After an incoming call has been accepted locally or an outgoing call has
+been accepted by a remote, the exchange signaled an active connection
+and the corresponding B-channel is switched through.
+.It Ar MSG_DISCONNECT_IND
+A call was terminated.
+.It Ar MSG_DIALOUT_IND
+A userland interface driver requests the daemon to dial out (typically a
+network interface when a packet arrives in its send queue).
+.It Ar MSG_IDLE_TIMEOUT_IND
+A call was terminated by the isdn4bsd kernel driver because a B-channel
+idle timeout occurred.
+.It Ar MSG_ACCT_IND
+Accounting information from a network driver.
+.It Ar MSG_CHARGING_IND
+Charging information from the kernel.
+.El
+.Pp
+.Ss OUTGOING CALLS
+Currently the only possibility to trigger an outgoing call is that an
+isdn4bsd network driver
+.Em (ipr<n>)
+sends a
+.Em MSG_DIALOUT_IND
+to the
+.Nm
+daemon.
+.Pp
+The daemon requests a new CDID from the kernel by using the
+.Em I4B_CDID_REQ
+ioctl message, this CDID is now used in all interactions with the kernel
+to identify this single call until a disconnect occurs.
+.Pp
+After getting the CDID, the daemon looks up several additional information
+in its entry section of the configuration corresponding to that connection
+and issues a
+.Em I4B_CONNECT_REQ
+ioctl message to the kernel. The kernel now dials the remote side and
+if the remote side accepts the call, the kernel sends a
+.Em MSG_CONNECT_ACTIVE_IND
+to the daemon.
+.Pp
+The call is terminated by either the local site timing out or the remote
+side hanging up the connection or the local side actively sending a
+.Em DISCONNECT_REQ
+ioctl message, both events are signaled to the
+.Nm
+by the kernel sending the
+.Em DISCONNECT_IND
+message and the CDID corresponding to the call is no longer valid.
+.Pp
+.Ss INCOMING CALLS
+Incoming calls are signaled to the
+.Nm
+by the kernel transmitting the
+.Em MSG_CONNECT_IND
+message to the daemon.
+.Pp
+With the information contained in this message, the
+.Nm
+searches the entry section of its configuration database and if a match is
+found, it accepts or rejects the call or, of no match is found, it ignores the
+call - all by issuing a
+.Em I4B_CONNECT_RESP
+ioctl message with the appropriate parameters to the kernel.
+.Pp
+In case the daemon decided to accept the message, the kernel signal the then
+active connection by sending a
+.Em MSG_CONNECT_ACTIVE_IND
+message to the daemon.
+.Pp
+The call is terminated by either the local site timing out or the remote
+side hanging up the connection or the local side actively sending a
+.Em DISCONNECT_REQ
+ioctl message, both events are signaled to the
+.Nm
+by the kernel sending the
+.Em DISCONNECT_IND
+message and the CDID corresponding to the call is no longer valid.
+.Pp
+
+.Sh SIGNALS
+
+Sending a HUP signal to
+.Nm
+causes all open connections to be terminated and the configuration file is
+reread. In case aliasfile handling was enabled, the aliasfile is also
+reread.
+
+Sending a USR1 signal to
+.Nm
+causes the accounting file and the logfile (if logging to a file is used
+instead of logging via the
+.Xr syslog 3
+facility) to be closed and reopened to make logfile rotation possible.
+
+.Sh ENVIRONMENT
+The following environment variables affect the execution of
+.Nm isdnd :
+.Bl -tag -width Ds
+.It Ev TERM
+The terminal type when running in full-screen display mode.
+See
+.Xr environ 7
+for more information.
+.El
+
+.Sh FILES
+.Bl -tag -width /etc/isdn/isdnd.rates -compact
+.It Pa /dev/i4b
+The device-file used to communicate with the kernel ISDN driver subsystem.
+
+.It Pa /var/log/messages
+A record of the actions in case of syslogd logging support.
+
+.It Pa /var/log/isdnd.acct
+The default accounting information filename (if accounting is configured).
+
+.It Pa /var/log/isdnd.log
+The default logging filename (if logging to a file is configured).
+
+.It Pa /var/run/isdnd.pid
+The process id of the isdn daemon (also known as "lockfile" to isdnd, preventing multiple invocations of it).
+
+.It Pa /usr/local/lib/isdn
+.It Pa /etc/isdn
+The directory where isdnd expects some supplementary data files and programs
+for telephone answering support.
+
+.It Pa /etc/isdn/isdnd.rc
+The default runtime configuration file.
+
+.It Pa /etc/isdn/isdnd.rates
+The default unit charging rates specification file.
+
+.It Pa /etc/isdn/isdntel.alias
+The default table (if aliasing is enabled) to convert phone number to caller's name.
+.El
+
+.Sh EXAMPLES
+For a first try, the following command should be used to start
+.Nm
+in foreground mode for better debugging the configuration setup:
+.Bd -literal -offset indent
+isdnd -d0xf9 -F
+.Ed
+.Pp
+This will start isdnd with reasonable debugging settings and produce
+output on the current terminal.
+.Nm Isdnd
+can then be terminated by entering Control-C.
+.Pp
+Another example, the command:
+.Bd -literal -offset indent
+isdnd -d0xf9 -f -r /dev/ttyv3 -t vt100
+.Ed
+.Pp
+will start
+.Nm isdnd
+with reasonable debugging messages enabled, full-screen mode of operation,
+full-screen display redirected to /dev/ttyv03 and using a termcap entry
+for vt100 on this display.
+
+.Sh DIAGNOSTICS
+Exit status is 0 on success, 1 on error.
+.Pp
+
+.Sh SEE ALSO
+.Xr syslogd 8 ,
+.Xr isdntrace 8 ,
+.Xr isdntel 8 ,
+.Xr isdnd.rc 5 ,
+.Xr isdnd.rates 5 ,
+.Xr i4bisppp 4 ,
+.Xr i4bipr 4
+
+.Sh BUGS
+Still one or more left.
+
+.Sh AUTHOR
+The
+.Nm
+daemon and this manual page were written by Hellmuth Michaelis. He can
+be contacted at hm@kts.org or hm@hcs.de.
diff --git a/usr.sbin/i4b/isdnd/isdnd.acct.5 b/usr.sbin/i4b/isdnd/isdnd.acct.5
new file mode 100644
index 0000000..9329e80
--- /dev/null
+++ b/usr.sbin/i4b/isdnd/isdnd.acct.5
@@ -0,0 +1,108 @@
+.\"
+.\" Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id: isdnd.acct.5,v 1.6 1998/12/05 18:03:18 hm Exp $
+.\"
+.\" last edit-date: [Sat Dec 5 18:09:33 1998]
+.\"
+.Dd September 11, 1998
+.Dt isdnd.acct 5
+.Sh NAME
+.Nm isdnd.acct
+.Nd isdn4bsd ISDN management daemon accounting file format
+.Sh DESCRIPTION
+The file
+.Pa isdnd.acct
+contains accounting information which is written if the variable
+.Em useacctfile
+in the
+.Xr isdnd 8
+configuration file
+.Xr isdnd.rc 5
+is set to
+.Em on
+and charging information transmission has been subscribed for the
+ISDN connection (AOCD or AOCE).
+.Pp
+If the variable
+.Em acctall
+is set to
+.Em on ,
+accounting information is written even if the local site was not charged
+or no charging information is available or is not subscribed.
+.Pp
+The general format of an accounting line is a follows:
+.Pp
+.Dl FROM - UNTIL NAME UNITS (SECONDS) (INBYTES/OUTBYTES)
+.Pp
+.Em FROM
+is the time the connection was established in the format
+.Dl Day:Month:Year Hour:Minutes:seconds
+.Pp
+.Em UNTIL
+is the time the connection was closed. The format is the same as
+described for
+.Em FROM
+above.
+.Pp
+.Em NAME
+is the symbolic name got from the
+.Em name
+entry of the
+.Xr isdnd.rc 5
+config file for this connection.
+.Pp
+.Em UNITS
+is the amount of charging units billed for the connection.
+.Pp
+.Em SECONDS
+is the number of seconds the connection lasted.
+.Pp
+.Em INBYTES
+and
+.Em OUTBYTES
+is the (optional) number of bytes that were transferred.
+
+.Sh FILES
+.Bl -tag -width /var/log/isdnd.acct -compact
+.It Pa /var/log/isdnd.acct
+The default accounting information file for the
+.Nm isdnd
+ISDN daemon.
+
+.Sh EXAMPLES
+This is a typical accounting line:
+.Pp
+.Dl 12.06.97 10:41:37 - 12.06.97 10:45:18 GROGGY 2 (65) (4711/1147)
+
+.Sh SEE ALSO
+.Xr isdnd 8 ,
+.Xr isdnd.rc 5
+
+.Sh AUTHOR
+The
+.Xr isdnd 8
+daemon and this manual page were written by Hellmuth Michaelis.
+He can be contacted at hm@kts.org or hm@hcs.de.
+
diff --git a/usr.sbin/i4b/isdnd/isdnd.h b/usr.sbin/i4b/isdnd/isdnd.h
new file mode 100644
index 0000000..009a2dd
--- /dev/null
+++ b/usr.sbin/i4b/isdnd/isdnd.h
@@ -0,0 +1,754 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * i4b daemon - main header file
+ * -----------------------------
+ *
+ * $Id: isdnd.h,v 1.56 1998/12/16 13:39:46 hm Exp $
+ *
+ * last edit-date: [Mon Dec 14 10:06:39 1998]
+ *
+ *---------------------------------------------------------------------------*/
+
+#ifndef _ISDND_H_
+#define _ISDND_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <strings.h>
+#include <ctype.h>
+#include <syslog.h>
+#include <regex.h>
+
+#ifdef USE_CURSES
+#include <curses.h>
+#endif
+
+#include <fcntl.h>
+#include <errno.h>
+#include <signal.h>
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+
+#ifdef USE_RTPRIO
+#include <sys/rtprio.h>
+#endif
+
+#include <machine/i4b_ioctl.h>
+#include <machine/i4b_cause.h>
+
+#include "config.h" /* compile time configuration */
+#include "pathnames.h" /* location of files */
+#include "alias.h" /* alias file processing */
+
+/*---------------------------------------------------------------------------*
+ * some general definitions
+ *---------------------------------------------------------------------------*/
+#define GOOD 0 /* general "good" or "ok" return*/
+#define ERROR (-1) /* general error return */
+#define WARNING (-2) /* warning return */
+#define INVALID (-1) /* an invalid integer */
+
+/*---------------------------------------------------------------------------*
+ * misc
+ *---------------------------------------------------------------------------*/
+#define RTPRIO_NOTUSED (-1) /* rtprio is not used for isdnd */
+
+/*---------------------------------------------------------------------------*
+ * debug flag bits
+ *---------------------------------------------------------------------------*/
+#define DL_MSG 0x0001 /* general debug messages */
+#define DL_RATES 0x0002 /* messages related to rates */
+#define DL_TIME 0x0004 /* messages related to timing */
+#define DL_STATE 0x0008 /* messages related to states changes */
+#define DL_RCVRY 0x0010 /* messages related to dial recovery */
+#define DL_DIAL 0x0020 /* messages related to dial recovery */
+#define DL_PROC 0x0040 /* messages related to process handling */
+#define DL_DRVR 0x0080 /* messages related to kernel i4b msg i/o*/
+#define DL_CNST 0x0100 /* messages related to controller state */
+
+#ifdef DEBUG
+#define DBGL(cond, dolog) if(cond & debug_flags) dolog
+#else
+#define DBGL(cond, dolog)
+#endif
+
+/*---------------------------------------------------------------------------*
+ * curses fullscreen display definitions
+ *---------------------------------------------------------------------------*/
+
+/* window dimensions */
+#define UPPER_B 2 /* upper window start */
+
+/* horizontal positions for upper window */
+#define H_CNTL 0 /* controller */
+#define H_TEI 2 /* TEI */
+#define H_CHAN (H_TEI+4) /* channel */
+#define H_TELN (H_CHAN+2) /* telephone number */
+#define H_IFN (H_TELN+23) /* interfacename */
+#define H_IO (H_IFN+7) /* incoming or outgoing */
+#define H_OUT (H_IO+4) /* # of bytes out */
+#define H_OUTBPS (H_OUT+11) /* bytes per second out */
+#define H_IN (H_OUTBPS+5) /* # of bytes in */
+#define H_INBPS (H_IN+11) /* bytes per second in */
+#define H_UNITS (H_INBPS+6) /* # of charging units */
+
+/* fullscreen mode menu window */
+#define WMENU_LEN 35 /* width of menu window */
+#define WMENU_TITLE "Command" /* title string */
+#define WMENU_POSLN 10 /* menu position, line */
+#define WMENU_POSCO 5 /* menu position, col */
+#define WMITEMS 4 /* no of menu items */
+#define WMENU_HGT (WMITEMS + 4) /* menu window height */
+
+#define WREFRESH 0
+#define WHANGUP 1
+#define WREREAD 2
+#define WQUIT 3
+
+#define WMTIMEOUT 5 /* timeout in seconds */
+
+/*---------------------------------------------------------------------------*
+ * charging rates
+ *---------------------------------------------------------------------------*/
+#define NDAYS 7 /* number of days in a week */
+#define NRATES 4 /* number of rate structures supported */
+
+/* struct for rates - each day has one or more */
+struct rates
+{
+ int start_hr; /* hour at which this rate starts, e.g. 12 */
+ int start_min; /* minute of start ... */
+ int end_hr; /* hour at which this rate ends, e.g. 19 */
+ int end_min; /* minute of end ... */
+ int rate; /* how long can I telephone at this price, seconds */
+ struct rates *next;
+};
+
+/*---------------------------------------------------------------------------*
+ * the internal identifiers for isdnd log levels. CAUTION: this has to stay
+ * in sync with the loglevel to text and sysloglevel table in log.c !!
+ *---------------------------------------------------------------------------*/
+enum logids
+{
+ LL_ERR, /* error conditions - everything which caused an error */
+ LL_WRN, /* warning conditions - nonfatal abnormal conditions */
+ LL_DMN, /* normal but significant condition - status of daemon */
+ LL_CHD, /* informational - everything regarding call handling */
+ LL_DBG /* debug messages - everything which helps debugging */
+};
+
+/*---------------------------------------------------------------------------*
+ * state machine events
+ *---------------------------------------------------------------------------*/
+enum events
+{
+ /* incoming messages */
+
+ EV_MCI, /* MSG_CONNECT_IND */
+ EV_MCAI, /* MSG_CONNECT_ACTIVE_IND */
+ EV_MDI, /* MSG_DISCONNECT_IND */
+ EV_MDO, /* MSG_DIALOUT */
+
+ /* local requests */
+
+ EV_TIMO, /* timer expired */
+ EV_DRQ, /* disconnect request */
+ EV_CBRQ, /* callback request */
+ EV_ALRT, /* alerting request */
+
+ /* illegal */
+
+ EV_ILL /* illegal event */
+};
+
+#define N_EVENTS (EV_ILL+1) /* no of possible events */
+
+/*---------------------------------------------------------------------------*
+ * this struct describes the numbers to try to dial out
+ *---------------------------------------------------------------------------*/
+typedef struct {
+ char number[TELNO_MAX]; /* remote number to dial */
+ int flag; /* usage flag */
+#define RNF_IDLE 0
+#define RNF_SUCC 1 /* last dial was ok */
+} remote_number_t;
+
+/*---------------------------------------------------------------------------*
+ * this struct describes numbers allowed to dial in
+ *---------------------------------------------------------------------------*/
+typedef struct {
+ char number[TELNO_MAX]; /* calling party number */
+} incoming_number_t;
+
+/*---------------------------------------------------------------------------*
+ * this structure describes a prematurely aborted called-back dialout
+ *---------------------------------------------------------------------------*/
+typedef struct {
+ int cdid; /* call handle */
+ int controller; /* the controller used to dial out */
+ int channel; /* the channel assigned to the outgoing call */
+ /* XXX - timeout handling and error recovery? */
+} phantom_t;
+
+/*---------------------------------------------------------------------------*
+ * this struct describes one complete configuration entry
+ *---------------------------------------------------------------------------*/
+typedef struct cfg_entry {
+
+ /* ====== filled in at startup configuration, then static ===========*/
+
+ char name[32]; /* id for this entry */
+
+ int isdncontroller; /* controller to use 0 ... n */
+ int isdnchannel; /* channel to use */
+
+ int isdntxdelin; /* tx delay, incoming connections */
+ int isdntxdelout; /* tx delay, outgoing connections */
+
+ int usrdevicename; /* userland device to use */
+ int usrdeviceunit; /* userland unit to use */
+
+ int remote_numbers_count; /* number of remote numbers */
+#define MAXRNUMBERS 8 /* max remote numbers */
+
+ remote_number_t remote_numbers[MAXRNUMBERS]; /* remote numbers to dial */
+
+ int remote_numbers_handling; /* how to handle the remote dialing */
+#define RNH_NEXT 0 /* use next number after last successfull */
+#define RNH_LAST 1 /* use last successfull for next call */
+#define RNH_FIRST 2 /* always use first number for next call */
+
+ char local_phone_dialout[TELNO_MAX]; /* our number to tell remote*/
+ char local_phone_incoming[TELNO_MAX]; /* answer calls for this local number */
+
+#define MAX_INCOMING 8
+ int incoming_numbers_count; /* number of incoming allowed numbers */
+ incoming_number_t remote_phone_incoming[MAX_INCOMING]; /* answer calls from this remote machine */
+
+ int dialin_reaction; /* what to do with incoming calls */
+#define REACT_ACCEPT 0
+#define REACT_REJECT 1
+#define REACT_IGNORE 2
+#define REACT_ANSWER 3
+#define REACT_CALLBACK 4
+
+ int b1protocol; /* hdlc / raw */
+
+ int idle_time_in; /* max idle time incoming calls */
+ int idle_time_out; /* max idle time outgoing calls */
+
+ int unitlength; /* length of a charging unit */
+#define UNITLENGTH_DEFAULT 60 /* last resort unit length */
+
+ int earlyhangup; /* time in seconds to hangup */
+ /* before the next expected */
+ /* charging unit */
+#define EARLYHANGUP_DEFAULT 5
+
+ int ratetype; /* type of rate */
+#define NO_RATE (NRATES+1)
+#define INVALID_RATE (-1)
+
+ int unitlengthsrc; /* where we get the unit length from */
+#define ULSRC_NONE 0 /* nowhere specified */
+#define ULSRC_CMDL 1 /* specified on commandline */
+#define ULSRC_CMDLMIN 5 /* minimum value from cmdl */
+#define ULSRC_CMDLMAX 3600 /* minimum value from cmdl */
+#define ULSRC_CONF 2 /* get it from config file */
+#define ULSRC_RATE 3 /* get it dynamic from ratesfile*/
+#define ULSRC_DYN 4 /* dynamic calculated from AOCD */
+
+ char *answerprog; /* program to use for answering */
+ char *connectprog; /* program run after negotiation finished */
+ char *disconnectprog; /* program run after shutdown is complete */
+
+ int callbackwait; /* time to wait before calling back */
+#define CALLBACKWAIT_MIN 1
+
+ int calledbackwait; /* time to wait for remote callback */
+#define CALLEDBACKWAIT_MIN 2
+
+ int dialretries; /* no. of dial tries */
+#define DIALRETRIES_DEF 1
+
+ int recoverytime; /* time between 2 dial tries */
+#define RECOVERYTIME_MIN 1
+
+ int dialrandincr; /* use random dial time incr */
+
+ int usedown; /* set interface down yes/no */
+ int downtries; /* retries before i/f is set down */
+#define DOWN_TRIES_MIN 2
+#define DOWN_TRIES_MAX 20
+ int downtime; /* time i/f is down */
+#define DOWN_TIME_MIN 10 /* 10 seconds */
+#define DOWN_TIME_MAX 3600 /* 1 hour */
+
+ int dialouttype; /* type of outgoing connection */
+#define DIALOUT_NORMAL 0 /* normal dialout behaviour */
+#define DIALOUT_CALLEDBACK 1 /* remote is expected to callback */
+
+ int alert; /* alert time in sec if nonzero */
+#define MINALERT 5 /* 5 secs min */
+#define MAXALERT (3*60) /* 3 minutes max */
+
+ int inout; /* in/out, in-only or out-only */
+#define DIR_INOUT 0
+#define DIR_INONLY 1
+#define DIR_OUTONLY 2
+
+/*===========================================================================*/
+/*============ filled in after start, then dynamic ==========================*/
+/*===========================================================================*/
+
+ int cdid; /* cdid for call */
+#define CDID_RESERVED (-1)
+
+ int isdncontrollerused; /* the one we are using */
+ int isdnchannelused; /* the one we are using */
+
+ int fs_position; /* fullscreen position */
+
+ int state; /* state of connection */
+#define ST_IDLE 0 /* connection is idle / disconnected */
+
+ /* normal dial out to remote */
+#define ST_DIAL 1 /* dialing */
+#define ST_DIALRTMRCHD 2 /* wait for dial retry time reached */
+#define ST_DIALRETRY 3 /* last/first dialing failed, retry */
+
+ /* PCB: passive callback, i'm being called back */
+#define ST_PCB_DIAL 4 /* dialing, trigger a callback */
+#define ST_PCB_DIALFAIL 5 /* dialing failed triggering a callbk */
+#define ST_PCB_WAITCALL 6 /* waiting for callback from remote */
+
+ /* ACB: active callback, i'm calling back */
+#define ST_ACB_WAITDISC 7 /* got call, wait for disconnect */
+#define ST_ACB_WAITDIAL 8 /* wait until allowed to callback */
+#define ST_ACB_DIAL 9 /* callback to remote */
+#define ST_ACB_DIALFAIL 10 /* callback to remote failed */
+
+ /* normal non-dialling states */
+#define ST_ACCEPTED 11 /* remote accepted */
+#define ST_CONNECTED 12 /* connected with remote */
+#define ST_WAITDISCI 13 /* tx disc req, wait for disc ind */
+#define ST_DOWN 14 /* interface is down */
+#define ST_ALERT 15 /* interface is waiting for alert time*/
+
+ /* illegal and pseudo states */
+#define ST_ILL 16 /* illegal state */
+#define ST_SUSE 17 /* subroutine sets new state */
+
+#define N_STATES (ST_ILL+1) /* max number of states */
+
+ int disc_cause; /* cause from disconnect */
+
+ int local_disconnect; /* flag, who disconnected */
+#define DISCON_LOC 0
+#define DISCON_REM 1
+
+ int timerval; /* value for timer, 0 if inactive */
+ int timerremain; /* remaining time */
+
+ int hangup; /* flag, hangup connection asap */
+
+ char real_phone_incoming[TELNO_MAX]; /* real remote telno in case of wildcard */
+
+ int last_remote_number; /* index of last used dialout number*/
+
+ char remote_phone_dialout[TELNO_MAX]; /* used remote number to dial */
+
+ int direction; /* incoming or outgoing */
+#define DIR_IN 0
+#define DIR_OUT 1
+
+ int charge; /* charge in units */
+ int last_charge; /* last charge in units */
+
+ int inbytes; /* # of bytes from remote */
+ int iinbytes; /* # of bytes from remote on the line */
+ int inbps; /* bytes/sec from remote */
+ int outbytes; /* # of bytes to remote */
+ int ioutbytes; /* # of bytes to remote on the line */
+ int outbps; /* bytes/sec to remote */
+
+ time_t connect_time; /* time connection was established */
+
+ time_t aoc_last; /* last AOCD timestamp */
+ time_t aoc_now; /* current AOCD timestamp */
+ time_t aoc_diff; /* current unit length */
+ time_t aoc_lastdiff; /* last charge unit length */
+ int aoc_valid; /* flag: time diff is valid */
+#define AOC_INVALID 0 /* aoc_diff is NOT valid */
+#define AOC_VALID 1 /* aoc_diff is valid */
+
+ time_t last_dial_time; /* time of last dialing */
+ time_t last_release_time; /* time of last hangup */
+
+ int dial_count; /* number of dialout tries */
+ int randomtime; /* random() part of recoverytime*/
+#define RANDOM_MASK 0x04 /* bits used from randomtime */
+
+ int down_retry_count; /* retry cycle count for usedown*/
+ time_t went_down_time; /* time i/f went down */
+ phantom_t saved_call; /* outgoing call state if called
+ back too early */
+
+ int alert_time; /* count down of alert time */
+ char display[DISPLAY_MAX];
+} cfg_entry_t;
+
+/*---------------------------------------------------------------------------*
+ * this struct describes state of controller with 2 b channels
+ *---------------------------------------------------------------------------*/
+typedef struct isdn_ctrl_state {
+ int ctrl_type; /* type: active/passive */
+ int card_type; /* manufacturer (CARD_XXXX) */
+ int state; /* controller state */
+#define CTRL_DOWN 0 /* controller inoparable */
+#define CTRL_UP 1 /* controller may be used */
+ int stateb1; /* B-channel 1 */
+ int stateb2; /* B-channel 2 */
+#define CHAN_IDLE 0 /* channel is free for usage */
+#define CHAN_RUN 1 /* channel is occupied */
+ int freechans; /* number of unused channels */
+#define MAX_CHANCTRL 2 /* free channels per controller */
+ int tei; /* tei or -1 if invalid */
+} isdn_ctrl_state_t;
+
+/*---------------------------------------------------------------------------*
+ * this struct describes a logging regular expression
+ *---------------------------------------------------------------------------*/
+struct rarr {
+ int re_flg; /* valid entry flag */
+ char *re_expr; /* plain text expression */
+ regex_t re; /* compiled expression */
+ char *re_prog; /* the program to be executed */
+};
+
+#ifdef I4B_EXTERNAL_MONITOR
+/* for each rights entry we keep one of this structures around: */
+struct monitor_rights {
+ char name[FILENAME_MAX]; /* net/host spec or filename */
+ int rights; /* bitmask of allowed acces rights */
+ u_int32_t net; /* net/host address (host byte order!) */
+ u_int32_t mask; /* bitmask 1 = network, 0 = host (host byte order!) */
+ int local; /* zero if remote access via tcp/ip */
+};
+#endif
+
+/*---------------------------------------------------------------------------*
+ * global variables, storage allocation
+ *---------------------------------------------------------------------------*/
+#ifdef MAIN
+
+int isdnfd; /* file handle, /dev/i4b */
+
+char *configfile = CONFIG_FILE_DEF; /* configuration filename */
+int config_error_flag = 0; /* error counter */
+
+#ifdef DEBUG
+int do_debug = 0; /* debug mode flag */
+int debug_flags = 0; /* debug options */
+int debug_noscreen = 0; /* not on fullscreen */
+#endif
+
+int do_bell = 0; /* bell on connect/disconnect */
+
+int do_fork = 1; /* run as daemon/foreground */
+
+int do_ttytype = 0; /* got new terminal type */
+char *ttype = ""; /* termcap entry name string */
+
+int do_rdev = 0; /* redirect output */
+char *rdev = ""; /* new device string */
+
+int do_print = 0; /* config file printout */
+
+int got_unitlen = 0; /* flag, got length of a unit */
+time_t unit_length; /* length of a unit */
+
+cfg_entry_t cfg_entry_tab[CFG_ENTRY_MAX]; /* configuration table */
+isdn_ctrl_state_t isdn_ctrl_tab[ISDN_CTRL_MAX]; /* controller states table */
+
+int ncontroller = 0; /* # of controllers available */
+int nentries = 0; /* # of entries in config tab */
+
+int uselogfile = 0; /* flag, use a logfile */
+char logfile[MAXPATHLEN] = LOG_FILE_DEF; /* log filename */
+FILE *logfp = NULL; /* log file pointer */
+int logfacility = LOG_LOCAL0; /* the syslog facility used */
+int nregex = 0; /* number of reg expr */
+struct rarr rarr[MAX_RE]; /* regexpr & progs table */
+
+char ratesfile[MAXPATHLEN] = RATES_FILE_DEF; /* rates filename */
+char *rate_error = NULL; /* errorcase: error string */
+int got_rate = 0; /* flag, ratesfile found */
+struct rates *rates[NRATES][NDAYS]; /* the rates structure */
+
+int useacctfile = 0; /* flag, write accounting */
+char acctfile[MAXPATHLEN] = ACCT_FILE_DEF; /* accounting filename */
+FILE *acctfp = NULL; /* accounting file pointer */
+int acct_all = 1; /* account all connections */
+
+int aliasing = 0; /* enable alias processing */
+char aliasfile[MAXPATHLEN] = ALIASFILE; /* alias file location */
+
+int do_fullscreen = 0; /* fullscreen log */
+int curses_ready = 0; /* curses initialized */
+
+#ifdef USE_CURSES
+WINDOW *upper_w; /* curses upper window pointer */
+WINDOW *mid_w; /* curses mid window pointer */
+WINDOW *lower_w; /* curses lower window pointer */
+#endif
+
+int rt_prio = RTPRIO_NOTUSED; /* realtime priority */
+
+/* monitor via network */
+
+int do_monitor = 0;
+int inhibit_monitor = 0;
+#ifdef I4B_EXTERNAL_MONITOR
+int monitorport = DEF_MONPORT;
+#else
+int monitorport = -1;
+#endif
+int accepted = 0;
+
+int isdntime = 0; /* flag, log time from exchange */
+
+#else /* !MAIN */
+
+int isdnfd;
+
+char *configfile;
+int config_error_flag;
+
+#ifdef DEBUG
+int do_debug;
+int debug_flags;
+int debug_noscreen;
+#endif
+
+int do_bell;
+
+int do_fork;
+
+int do_ttytype;
+char *ttype;
+
+int do_rdev;
+char *rdev;
+
+int do_print;
+
+int got_unitlen;
+time_t unit_length;
+
+cfg_entry_t cfg_entry_tab[CFG_ENTRY_MAX]; /* configuration table */
+isdn_ctrl_state_t isdn_ctrl_tab[ISDN_CTRL_MAX]; /* controller states table */
+
+int ncontroller;
+int nentries;
+
+int uselogfile;
+char logfile[MAXPATHLEN];
+int logfacility;
+int nregex;
+struct rarr rarr[MAX_RE];
+
+char ratesfile[MAXPATHLEN];
+char *rate_error;
+int got_rate;
+struct rates *rates[NRATES][NDAYS];
+
+int useacctfile;
+char acctfile[MAXPATHLEN];
+FILE *acctfp;
+int acct_all;
+
+int aliasing;
+char aliasfile[MAXPATHLEN];
+
+int do_fullscreen;
+int curses_ready;
+
+#ifdef USE_CURSES
+WINDOW *upper_w;
+WINDOW *mid_w;
+WINDOW *lower_w;
+#endif
+
+int rt_prio;
+
+int do_monitor;
+int inhibit_monitor;
+int monitorport;
+int accepted;
+
+int isdntime;
+
+#endif /* MAIN */
+
+char * bdrivername ( int drivertype );
+void cfg_setval ( int keyword );
+void check_and_kill ( cfg_entry_t *cep );
+void check_pid ( void );
+void close_allactive ( void );
+void configure ( char *filename, int reread );
+void daemonize ( void );
+void dialresponse(cfg_entry_t *cep, int dstat);
+void display_acct ( cfg_entry_t *cep );
+void display_bell ( void );
+void display_ccharge ( cfg_entry_t *cep, int units );
+void display_chans ( void );
+void display_charge ( cfg_entry_t *cep );
+void display_connect ( cfg_entry_t *cep );
+void display_disconnect ( cfg_entry_t *cep );
+void display_l12stat(int controller, int layer, int state);
+void display_tei(int controller, int tei);
+void display_updown ( cfg_entry_t *cep, int updown );
+void hangup_channel ( int channel );
+void do_exit ( int exitval );
+void do_menu ( void );
+int exec_answer ( cfg_entry_t *cep );
+int exec_connect_prog ( cfg_entry_t *cep, const char *prog, int link_down );
+pid_t exec_prog ( char *prog, char **arglist );
+cfg_entry_t * find_by_device_for_dialout ( int drivertype, int driverunit );
+cfg_entry_t * find_matching_entry_incoming ( msg_connect_ind_t *mp );
+cfg_entry_t * find_active_entry_by_driver ( int drivertype, int driverunit );
+void finish_log ( void );
+char * getlogdatetime ( void );
+int get_cdid ( void );
+cfg_entry_t * get_cep_by_cc ( int ctrlr, int chan );
+cfg_entry_t * get_cep_by_driver ( int drivertype, int driverunit );
+cfg_entry_t * get_cep_by_cdid ( int cdid );
+int get_current_rate ( cfg_entry_t *cep, int logit );
+void handle_charge ( cfg_entry_t *cep );
+void handle_recovery ( void );
+void if_up(cfg_entry_t *cep);
+void if_down(cfg_entry_t *cep);
+void init_controller ( void );
+void init_log ( void );
+void init_screen ( void );
+void log ( int what, const char *fmt, ... );
+int main ( int argc, char **argv );
+void msg_accounting ( msg_accounting_ind_t *mp );
+void msg_alert_ind ( msg_alert_ind_t *mp );
+void msg_charging_ind ( msg_charging_ind_t *mp );
+void msg_connect_active_ind ( msg_connect_active_ind_t *mp );
+void msg_connect_ind ( msg_connect_ind_t *mp );
+void msg_pdeact_ind(msg_pdeact_ind_t *md);
+void msg_negcomplete_ind(msg_negcomplete_ind_t *ind);
+void msg_ifstatechg_ind(msg_ifstatechg_ind_t *ind);
+void msg_drvrdisc_req(msg_drvrdisc_req_t *mp);
+void msg_dialout ( msg_dialout_ind_t *mp );
+void msg_disconnect_ind ( msg_disconnect_ind_t *mp );
+void msg_idle_timeout_ind ( msg_idle_timeout_ind_t *mp );
+void msg_l12stat_ind(msg_l12stat_ind_t *ml);
+void msg_teiasg_ind(msg_teiasg_ind_t *mt);
+void msg_proceeding_ind ( msg_proceeding_ind_t *mp );
+const char * name_of_controller(int ctrl_type, int card_type);
+void next_state ( cfg_entry_t *cep, int event );
+char * print_i4b_cause( cause_t code );
+char * printstate ( cfg_entry_t *cep );
+int readrates ( char *filename );
+int ret_channel_state(int controller, int channel);
+void reopenfiles ( int dummy );
+void rereadconfig ( int dummy );
+void select_first_dialno ( cfg_entry_t *cep );
+void select_next_dialno ( cfg_entry_t *cep );
+void select_this_dialno ( cfg_entry_t *cep );
+int sendm_alert_req ( cfg_entry_t *cep );
+int sendm_connect_req ( cfg_entry_t *cep );
+int sendm_connect_resp ( cfg_entry_t *cep, int cdid, int response, int cause );
+int sendm_disconnect_req ( cfg_entry_t *cep, int cause );
+int set_channel_busy(int controller, int channel);
+int set_channel_idle(int controller, int channel);
+int setup_dialout(cfg_entry_t *cep);
+void sigchild_handler ( int sig );
+void start_timer ( cfg_entry_t *cep, int seconds );
+void stop_timer ( cfg_entry_t *cep );
+void unitlen_chkupd( cfg_entry_t *cep );
+void write_pid ( void );
+void yyerror ( const char *msg );
+
+/* montior server module */
+void monitor_init();
+void monitor_exit();
+void monitor_clear_rights();
+void monitor_fixup_rights();
+int monitor_start_rights(const char *clientspec);
+void monitor_add_rights(int rights);
+
+/* possible return codes from monitor_start_rights: */
+#define I4BMAR_OK 0 /* rights added successfully */
+#define I4BMAR_LENGTH 1 /* local socket name to long */
+#define I4BMAR_DUP 2 /* entry already exists */
+#define I4BMAR_CIDR 3 /* cidr netmask is invalid */
+#define I4BMAR_NOIP 4 /* host/net could not be resolved */
+
+int monitor_create_local_socket();
+
+#ifndef I4B_NOTCPIP_MONITOR
+int monitor_create_remote_socket(int portno);
+#endif
+
+void monitor_prepselect(fd_set *selset, int *max_fd);
+void monitor_handle_input(fd_set *selset);
+void monitor_handle_connect(int sockfd, int is_local);
+void monitor_evnt_charge(cfg_entry_t *cep, int units, int estimated);
+void monitor_evnt_connect(cfg_entry_t *cep);
+void monitor_evnt_disconnect(cfg_entry_t *cep);
+void monitor_evnt_updown(cfg_entry_t *cep, int up);
+void monitor_evnt_log(int prio, const char * what, const char * msg);
+
+/* controller.c */
+
+int init_controller_state(int controller, int ctrl_type, int card_type, int tei);
+int set_controller_state(int controller, int state);
+int get_controller_state(int controller);
+int decr_free_channels(int controller);
+int incr_free_channels(int controller);
+int get_free_channels(int controller);
+int set_channel_busy(int controller, int channel);
+int set_channel_idle(int controller, int channel);
+int ret_channel_state(int controller, int channel);
+
+/* alias.c */
+
+void init_alias(char *filename);
+void free_aliases(void);
+char *get_alias(char *number);
+
+#endif /* _ISDND_H_ */
diff --git a/usr.sbin/i4b/isdnd/isdnd.rates.5 b/usr.sbin/i4b/isdnd/isdnd.rates.5
new file mode 100644
index 0000000..450cd5e
--- /dev/null
+++ b/usr.sbin/i4b/isdnd/isdnd.rates.5
@@ -0,0 +1,115 @@
+.\"
+.\" Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id: isdnd.rates.5,v 1.6 1998/12/05 18:03:21 hm Exp $
+.\"
+.\" last edit-date: [Sat Dec 5 18:09:57 1998]
+.\"
+.Dd September 11, 1998
+.Dt isdnd.rates 5
+.Sh NAME
+.Nm isdnd.rates
+.Nd isdn4bsd ISDN management daemon rates description file
+.Sh DESCRIPTION
+The file
+.Pa isdnd.rates
+contains descriptions how long charging units last at a given time of day,
+day of week and the distance to the destination. If this file is available,
+this information may be used by the
+.Xr isdnd 8
+ISDN connection management daemon to calculate the short hold time for a
+connection.
+.Pp
+The format of a rate entry line is a follows:
+.Pp
+The first field, the
+.Pq Fa rate-code
+defines a collection of rates (for each day of the week) which can be
+referenced in the
+.Xr isdnd 8
+configuration file
+.Xr isdnd.rc 5 .
+This field must start with the identifier
+.Dq ra
+followed by a digit in the range of zero to four.
+.Pp
+
+The second field, the
+.Pq Fa day-number
+selects the day of week for which this entry defines the rates, where 0 stands
+for Sunday, 1 for Monday and so on until the digit 6 which stands for Saturday.
+.Pp
+
+The rest of the line consists of one or more space separated fields which have
+the following syntax:
+.Bd -filled -offset indent
+start_hour.start_minutes-end_hour.end_minutes:charge_unit_length
+.Ed
+.Pp
+Start_hour and start_minutes define the begin of a time section and end_hour
+and end_minutes define the end. Charge_unit_length define the length of a
+charging unit in the previously defined time section. No spaces or tabs are
+allowed inside this field. The hour and minutes specifications MUST have
+exactly 2 digits, in case just one digit is needed, a leading 0 must be used.
+.Pp
+For example,
+.Bd -filled -offset indent
+14.00-18.00:90
+.Ed
+.Pp
+defines, that between 2:00 PM and 6:00 PM the length of one charging unit
+lasts 90 seconds.
+.Pp
+
+.Sh FILES
+.Bl -tag -width /etc/isdn/isdnd.rates -compact
+.It Pa /etc/isdn/isdnd.rates
+The default rates specification file for the
+.Nm isdnd
+ISDN daemon.
+
+.Sh EXAMPLES
+The line:
+.Bd -literal
+ra0 0 00.00-05.00:240 05.00-21.00:150 21.00-24.00:240
+.Ed
+.Pp
+defines the unit lengths for a Sunday.
+
+.Sh SEE ALSO
+.Xr isdnd 8 ,
+.Xr isdnd.rc 5
+
+.Sh AUTHOR
+The rates subsystem for the
+.Xr isdnd 8
+daemon to which
+.Nm
+belongs was designed and written by Gary Jennejohn.
+.Pp
+The
+.Xr isdnd 8
+daemon and this manual page were written by Hellmuth Michaelis.
+He can be reached at hm@kts.org or hm@hcs.de.
+
diff --git a/usr.sbin/i4b/isdnd/isdnd.rc.5 b/usr.sbin/i4b/isdnd/isdnd.rc.5
new file mode 100644
index 0000000..03d1a3a
--- /dev/null
+++ b/usr.sbin/i4b/isdnd/isdnd.rc.5
@@ -0,0 +1,642 @@
+.\"
+.\" Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id: isdnd.rc.5,v 1.27 1998/12/05 18:03:23 hm Exp $
+.\"
+.\" last edit-date: [Sat Dec 5 18:10:08 1998]
+.\"
+.Dd October 27, 1998
+.Dt isdnd.rc 5
+.Sh NAME
+.Nm isdnd.rc
+.Nd isdn4bsd ISDN connection management daemon config file format
+.Sh DESCRIPTION
+The file
+.Pa /etc/isdn/isdnd.rc
+contains (if not otherwise specified on the command line) the runtime
+configuration for the
+.Xr isdnd 8
+ISDN connection management daemon which is part of the isdn4bsd package.
+.Pp
+The configuration file consists of keywords which start in column 1 followed by
+one or more spaces or tabs, an equal sign, one or more spaces or tabs
+and a keyword dependent parameter value.
+.Pp
+A line beginning with '#' is treated as a comment line.
+.Pp
+For keywords requiring the specification of a boolean value, the truth
+value can be either
+.Em yes
+or
+.Em on
+while the false value can be either
+.Em no
+or
+.Em off .
+.Pp
+The configuration file consists of one
+.Em system
+section and one or more
+.Em entry
+sections.
+In the
+.Em system
+section parameters regarding the daemon operation or parameters
+not associated with a single remote connection can be set.
+In the
+.Em entry
+section(s) parameters directly associated with a single remote
+connection can be set.
+.Pp
+The following keywords are recognized by
+.Nm isdnd :
+.Pp
+.Bl -tag -width system -compact
+
+.It Li system
+This keyword starts the system configuration section. It must not
+have a parameter and may be used only once. The keyword is mandatory.
+The following keywords are valid in the system configuration section:
+.Bl -tag -width useacctfile -compact
+
+.It Li acctall
+If this parameter is set to
+.Em on ,
+accounting information is written even if the local site was not charged
+or no charging information is available or is not subscribed. (optional)
+
+.It Li acctfile
+Specifies the name of the accounting file which is used when the keyword
+.Em useacctfile
+(see below) is set to
+.Em on .
+If this keyword is omitted the system default is used. (optional)
+
+.It Li aliasing
+If this parameter is set to
+.Em on ,
+alias processing of telephone-number to name is enabled (see also the
+.Em aliasfile
+keyword below). The default is off. (optional)
+
+.It Li aliasfile
+Specifies the name of the telephone number-to-name alias database file shared
+with the
+.Xr isdntel 1
+utility when alias processing is enabled via the
+.Em aliasing
+keyword. (optional)
+
+.It Li isdntime
+If this parameter is set to
+.Em on ,
+date/time information from the exchange (if provided) is written to the
+logfile. The default is off. (optional)
+
+.It Li monitor-allowed
+If this parameter is set to
+.Em on
+or
+.Em yes ,
+monitoring via a local or remote machine is enabled.
+This parameter is optional and is set to
+.Em off
+by default.
+
+.It Li monitor-port
+sets the TCP port number for remote monitoring.
+This integer parameter is optional and is set to port 451 by default.
+
+.It Li monitor
+This keyword specifies a local socket name or a host or network for remote
+monitoring. The
+.Em monitor
+specification may either be:
+.Pp
+.Bl -tag -width Ds -compact -offset
+.It Ar the name of a local (UNIX-domain) socket
+this MUST start with a "/", example: /var/run/isdn-monitor
+.It Ar a dotted-quad host specification
+example: 192.168.1.2
+.It Ar a dotted-quad network address with netmask
+example: 192.168.1.0/24
+.It Ar a resolvable host name
+example: localhost
+.It Ar a resolvable network name with netmask
+example: up-vision-net/24
+.El
+
+.It Li monitor-access
+This keyword specifies the access rights for a previously used
+.Em monitor
+keyword. The supported access rights are:
+.Pp
+.Bl -tag -width Ds -compact -offset
+.It Ar fullcmd
+.It Ar restrictedcmd
+.It Ar channelstate
+.It Ar logevents
+.It Ar callin
+.It Ar callout
+.El
+
+.It Li ratesfile
+Specifies the name of the ratesfile. If this keyword is omitted the system
+default is used. (optional)
+
+.It Li regexpr
+This keyword is used to specify regular expressions. It can be specified
+more than once up to a compile time dependent value (currently set to 5 by
+the MAX_RE definition in the source).
+.Pp
+All specified regular expressions are compared to the log strings at runtime
+and if a match is found, a program is run with the log text as a parameter
+(see also the keyword
+.Em regprog
+below).
+.Pp
+For an explanation how regular expressions are specified, please have a
+look at
+.Xr re_format 7
+and
+.Xr regex 3 .
+The
+.Em extended
+regular expression syntax is supported here.
+.Pp
+Hint: it might be necessary to properly quote the expression to avoid
+improper interpretation by the configuration file parser.
+(optional)
+
+.It Li regprog
+This keyword is used to specify the name of a program which is run in
+case a corresponding regular expression is matched by a logging string.
+.Nm Isdnd
+expects to find the program below the path
+.Pa /etc/isdn
+which is prepended to the string specified as a parameter to this keyword.
+(optional)
+
+.It Li rtprio
+Specifies the realtime priority
+.Nm isdnd
+runs at as an integer value in the range 0...31 with 0 being the highest
+priority. This keyword is optional; if not specified the process priority of
+.Nm isdnd
+is not touched in any way.
+( See also
+.Xr rtprio 1
+).
+This keyword is only available if
+.Nm
+was compiled with -DUSE_RTPRIO.
+
+.It Li useacctfile
+If this parameter is set to
+.Em on
+charging (if available) and accounting information is written to the
+accounting file. (optional)
+
+.El
+
+.It Li entry
+This keyword starts one configuration entry. It must not have a parameter.
+This keyword must be used at least once.
+The following keywords are valid in an entry section:
+.Bl -tag -width unitlengthsrc -compact
+
+.It Li answerprog
+This keyword is used to specify the name of a program which is run in
+case an incoming telephone connection specified
+.Em answer
+in its configuration entry. The default name is
+.Em answer .
+.Nm Isdnd
+expects to find this program beneath the path
+.Pa /etc/isdn
+which is prepended to the string specified as a parameter to this keyword.
+(optional)
+
+.It Li alert
+is used to specify a time in seconds to wait before accepting a call. This
+keyword is only usable for incoming telephone calls (dialin-reaction = answer).
+It is used to have a chance to accept an incoming call on the phone before
+the answering machine starts to run. The minimum value for the alert parameter
+is 5 seconds and the maximum parameter allowed is 180 seconds.
+(optional)
+
+.It Li b1protocol
+The B channel layer 1 protocol used for this connection. The keyword is mandatory.
+The currently configurable values are:
+.Pp
+.Bl -tag -width Ds -compact -offset
+.It Ar hdlc
+HDLC framing.
+.It Ar raw
+No framing at all (used for telephony).
+.El
+
+.It Li callbackwait
+The time in seconds to wait between hanging up the call from a remote site
+and calling back the remote site. (optional)
+
+.It Li calledbackwait
+The time in seconds to wait for a remote site calling back the local site
+after a call from the local site to the remote site has been made. (optional)
+
+.It Li dialin-reaction
+Used to specify what to do when an incoming connection request is received.
+The keyword is mandatory.
+The currently supported parameters are:
+.Pp
+.Bl -tag -width calledback -compact -offset
+.It Ar accept
+Accept an incoming call.
+.It Ar reject
+Reject an incoming call.
+.It Ar ignore
+Ignore an incoming call.
+.It Ar answer
+Start telephone answering for an incoming voice call.
+.It Ar callback
+When a remote site calls, hangup and call back the remote site.
+.El
+
+.It Li dialout-type
+This keyword ist used to configure what type of dialout mode is used.
+The keyword is mandatory.
+The currently supported parameters are:
+.Pp
+.Bl -tag -width Ds -compact -offset
+.It Ar normal
+Normal behavior, call the remote site which is supposed to accept the call.
+.It Ar calledback
+Callback behavior, call the remote side which rejects the call and calls
+us back.
+.El
+
+.It Li dialrandincr
+When dialing or re-dialing and this parameter is set to
+.Em on ,
+the dial retry time is added with a random value (currently 0...3 seconds)
+to minimize the chance of two sites dialing synchronously so each gets a busy
+each time it dials because the other side is also dialing.
+
+.It Li dialretries
+The number of dialing retries before giving up. (optional)
+
+.It Li direction
+This keyword is used to configure if incoming and outgoing, incoming-only or
+outgoing only connections are possible.
+The keyword is optional, the default is
+.Em inout .
+.Pp
+The currently supported parameters are:
+.Pp
+.Bl -tag -width Ds -compact -offset
+.It Ar inout
+Normal behavior, connection establishment is possible from remote and local.
+.It Ar in
+Only incoming connections are possible.
+.It Ar out
+Only outgoing connections are possible.
+.El
+
+.It Li downtries
+is used to configure the number of unsuccessful tries (= retry cycles!) before
+the interface is disabled (for
+.Em downtime
+seconds).
+(see also the keyword
+.Em usedown
+further up). This keyword is optional.
+
+.It Li downtime
+is used to configure the time in seconds an interface is disabled
+after the configured number of
+.Em downtries .
+(see also the keyword
+.Em usedown
+further up).
+This keyword is optional and is set to 60 seconds by default.
+
+.It Li earlyhangup
+A (safety) time in seconds which specifies the time to hangup before an
+expected next charging unit will occur. (optional)
+
+.It Li idletime-outgoing
+The time in seconds an outgoing connection must be idle before hanging up.
+(optional)
+
+.It Li idletime-incoming
+The time in seconds an incoming connection must be idle before hanging up.
+(optional)
+
+.It Li isdncontroller
+The ISDN controller number to be used for connections for this entry.
+(mandatory)
+
+.It Li isdnchannel
+The ISDN controller channel number to be used for connections for this entry.
+In case a channel is explicitly selected here, the SETUP message will request
+this channel but mark the request as
+.Em preferred
+(the indicated channel is preferred) instead of exclusive (only the indicated
+channel is acceptable). Thus the exchange is still free to select another
+than the requested channel!
+(mandatory)
+
+.It Li isdntxdel-incoming
+A delay value suitable for the
+.Em timeout()
+kernel subroutine to delay the transmittion of the first packet after a
+successfull connection is made by this value for
+.Em incoming
+ISDN connections. The specification unit is 1/100 second. A zero (0) disables
+this feature and is the default value. This feature is implemented (and makes
+sense only) for the
+.Xr i4bipr 4
+IP over raw HDLC ISDN driver. (optional)
+
+.It Li isdntxdel-outgoing
+A delay value suitable for the
+.Em timeout()
+kernel subroutine to delay the transmittion of the first packet after a
+successfull connection is made by this value for
+.Em outgoing
+ISDN connections. The specification unit is 1/100 second. A zero (0) disables
+this feature and is the default value. This feature is implemented (and makes
+sense only) for the
+.Xr i4bipr 4
+IP over raw HDLC ISDN driver. (optional)
+
+.It Li local-phone-dialout
+The local telephone number used when the local site dials out. When dialing
+out to a remote site, the number specified here is put into the
+.Em "Calling Party Number Information Element" .
+.Pp
+This keyword is mandatory for the
+.em
+ipr
+userland interfaces.
+
+.It Li local-phone-incoming
+The local telephone number used for verifying the destination of incoming
+calls. When a remote site dials in, this number is used to verify that it
+is the local site which the remote site wants to connect to. It is compared
+with the
+.Em "Called Party Number Information Element"
+got from the telephone exchange.
+.Pp
+This keyword is mandatory for the ipr interfaces.
+
+.It Li name
+Defines a symbolic name for this configuration entry. It's purpose is to
+use this name in the full-screen display for easy identification of a link
+to a remote site and for accounting purposes. (mandatory)
+
+.It Li ratetype
+The rate entry used from the rates file. (optional)
+.br
+For example, ratetype=0 selects lines beginning "ra0" in /etc/isdn/isdnd.rates;
+(typically ra0 lines are a set of tables for local call rates on different
+days of the week & times per day).
+
+.It Li recoverytime
+The time in seconds to wait between dial retries. (optional)
+
+.It Li remdial-handling
+is used to specify the dialout behavior in case more than one outgoing
+number is specified.
+The currently supported parameters are:
+.Pp
+.Bl -tag -width Ds -compact -offset
+.It Ar first
+For every new (non-retry) call setup, start with the first number.
+.It Ar last
+For every new (non-retry) call setup, start with the last number with
+which a successful connection was made.
+.It Ar next
+For every new (non-retry) call setup, start with the next number which
+follows the last one used.
+.El
+
+.It Li remote-phone-dialout
+The remote telephone number used when the local site dials out. When dialing
+out to a remote site, the number specified here is put into the
+.Em "Called Party Number Information Element" .
+.Pp
+This keyword is mandatory for the
+.em
+ipr
+interfaces. It may be specified more than once to try to dial to several
+numbers until one succeeds.
+
+.It Li remote-phone-incoming
+The remote telephone number used to verify an incoming call. When a remote site
+dials in, this number is used to verify that it is the correct remote site
+which is herewith authorized to connect into the local system. This parameter
+is compared against the
+.Em "Calling Party Number Information Element"
+got from the telephone exchange.
+.Pp
+This keyword is mandatory for the ipr interfaces.
+.Pp
+This keyword may have a wildcard parameter '*' to permit anyone dialing in.
+
+.It Li unitlength
+The length of a charging unit in seconds. This is used in conjunction with
+the idletime to decide when to hangup a connection. (optional)
+
+.It Li unitlengthsrc
+This keyword is used to specify from which source
+.Xr isdnd 8
+takes the unitlength for shorthold mode. The currently configurable values are:
+.Pp
+.Bl -tag -width Ds -compact -offset
+.It Ar none
+Then unitlength is not specified anywhere.
+.It Ar cmdl
+Use the unitlength specified on the commandline.
+.It Ar conf
+Use the unitlength specified in the configuration file with the keyword
+.Em unitlength .
+.It Ar rate
+Use the unitlength from the ratesfile specified in the configuration
+file with the keyword
+.Em ratetype .
+.It Ar aocd
+Use a dynamically calculated unitlength in case AOCD is subscribed on
+the ISDN line. (AOCD is an acronym for ``Advice Of Charge During the call''
+which is a service provided by the telecommunications (ie phone) provider,
+to indicate billable units).
+.El
+
+.It Li usrdevicename
+Specifies the userland interface which is used for interfacing ISDN B channel
+data to the userland. The keyword is mandatory.
+This keyword accepts the following parameters:
+.Pp
+.Bl -tag -width Ds -compact -offset
+.It Ar ipr
+This parameter configures a raw HDLC IP over ISDN interface.
+.It Ar isp
+This parameter configures a synchronous PPP over ISDN interface.
+.It Ar rbch
+This specifies a Raw B CHannel access interface.
+.It Ar tel
+ISDN telephony.
+.El
+
+.It Li usrdeviceunit
+Specifies the unit number for the with the
+.em
+usrdevicename
+specified device.
+
+.It Li usedown
+is used to enable the use of the keywords
+.Em downtries
+and
+.Em downtime
+in the entries section(s). It is used in the
+.Nm isdnd
+daemon to dynamically enable and disable the IP interfaces to avoid excessive
+dialing activities in case of transient failures (such as busy lines).
+This parameter is optional and is set to
+.Em off
+by default.
+
+.It Li connectprog
+specifies a program run everytime after a connection is established and
+address negotiation is complete (i.e.: the connection is useable).
+.Nm Isdnd
+expects to find the program below the path
+.Pa /etc/isdn
+which is prepended to the string specified as a parameter to this keyword.
+(optional)
+
+.It Li disconnectprog
+specifies a program run everytime after a connection was shut down.
+.Nm Isdnd
+expects to find the program below the path
+.Pa /etc/isdn
+which is prepended to the string specified as a parameter to this keyword.
+(optional)
+
+.El
+.El
+
+.Sh IDLETIME CALCULATION AND SHORTHOLD MODE
+.Bl -tag -width incoming calls -compact
+.It Li incoming calls
+It is assumed that the calling side knows most about charging structures and
+such and as a consequence only the keyword
+.Em idletime-incoming
+has a function for incoming calls.
+.Pp
+For incoming calls the line is constantly monitored, and in case there was
+not traffic taking place for the time in seconds specified by
+.Em idletime-incoming
+the call is closed.
+.Pp
+Typically,
+.Em idletime-incoming
+is used as a last resort and is therefore set much higher than a charging
+unit time: typical values are one to five minutes.
+
+.It Li outgoing calls
+Outgoing call disconnect time can be setup in one of two ways:
+
+.Bl -tag -width shorthold mode -compact
+.It Li simple mode
+For simple mode, the selected
+.Em unitlength
+must be 0 (zero) and
+.Em idletime-outgoing
+greater zero.
+.Pp
+The outgoing traffic is constantly monitored, and in case there was
+not traffic taking place for the time in seconds specified by
+.Em idletime-outgoing
+the call is closed.
+.Pp
+Typical values in simple mode are 10 to 30 seconds.
+
+.It Li shorthold mode
+For shorthold mode, the selected
+.Em unitlength
+and
+.Em idletime-outgoing
+must be greater than 0 (zero);
+.Em earlyhangup must be >= 0 (zero).
+
+.Bd -literal
+
+|<unchecked-window>|<checkwindow>|<safetywindow>|
+| | | |
++------------------+-------------+--------------+
+| | | |
+| |<-idle-time->|<earlyhangup->|
+|<--------------unitlength--------------------->|
+
+.Ed
+
+During the unchecked window which is (unitlength - (idle-time+earlyhangup))
+in length, no idle check is done. After the unchecked window has ended,
+the line is checked for idle-time length if no traffic takes place. In case
+there was traffic detected in the check-window, the same procedure is restarted
+at the beginning of the next unit. In case no traffic was detected during
+the check-window, the line is closed at the end of the check window.
+.Pp
+Notice:
+.Em unitlength
+must (!) be greater than the sum of
+.Em idletime-outgoing
+and
+.Em earlyhangup !
+
+.El
+.El
+
+.Pp
+
+.Sh FILES
+.Bl -tag -width /etc/isdn/isdnd.rc -compact
+.It Pa /etc/isdn/isdnd.rc
+The default configuration file for the
+.Nm isdnd
+ISDN daemon.
+
+.Sh SEE ALSO
+.Xr isdnd 8
+.Xr isdnmonitor 8
+.Xr regex 3
+.Xr re_format 7
+
+.Sh AUTHOR
+The
+.Xr isdnd 8
+daemon and this manual page were written by Hellmuth Michaelis.
+He can be reached at hm@kts.org.
diff --git a/usr.sbin/i4b/isdnd/log.c b/usr.sbin/i4b/isdnd/log.c
new file mode 100644
index 0000000..4c1ffb6
--- /dev/null
+++ b/usr.sbin/i4b/isdnd/log.c
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * i4b daemon - logging routines
+ * -----------------------------
+ *
+ * $Id: log.c,v 1.14 1998/12/05 18:03:24 hm Exp $
+ *
+ * last edit-date: [Sat Dec 5 18:10:22 1998]
+ *
+ *---------------------------------------------------------------------------*/
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <regex.h>
+
+#include <machine/i4b_ioctl.h>
+
+#include "isdnd.h"
+
+#define LOGBUFLEN 256
+
+extern int do_monitor;
+extern int accepted;
+extern FILE *logfp;
+
+static void check_reg(char *logstring);
+
+struct logtab {
+ char *text;
+ int pri;
+};
+
+/*---------------------------------------------------------------------------*
+ * table for converting internal log levels into syslog levels
+ *---------------------------------------------------------------------------*/
+static struct logtab logtab[] = {
+ {"ERR", LOG_ERR}, /* error conditions */
+ {"WRN", LOG_WARNING}, /* warning conditions, nonfatal */
+ {"DMN", LOG_NOTICE}, /* normal but significant condition, daemon*/
+ {"CHD", LOG_INFO}, /* informational, call handling */
+ {"DBG", LOG_DEBUG} /* debug messages */
+};
+
+/*---------------------------------------------------------------------------*
+ * initialize logging
+ *---------------------------------------------------------------------------*/
+void
+init_log(void)
+{
+ int i;
+
+ if(uselogfile)
+ {
+ if((logfp = fopen(logfile, "a")) == NULL)
+ {
+ fprintf(stderr, "ERROR, cannot open logfile %s: %s\n",
+ logfile, strerror(errno));
+ exit(1);
+ }
+
+ /* set unbuffered operation */
+
+ setvbuf(logfp, (char *)NULL, _IONBF, 0);
+ }
+ else
+ {
+#if DEBUG
+ if(do_debug && do_fork == 0 && do_fullscreen == 0)
+ (void)openlog("isdnd",
+ LOG_PID|LOG_CONS|LOG_NDELAY|LOG_PERROR,
+ logfacility);
+ else
+#endif
+ (void)openlog("isdnd", LOG_PID|LOG_CONS|LOG_NDELAY,
+ logfacility);
+ }
+
+ /* initialize the regexp array */
+
+ for(i = 0; i < MAX_RE; i++)
+ {
+ char *p;
+ char buf[64];
+
+ sprintf(buf, "%s%d", REGPROG_DEF, i);
+
+ rarr[i].re_flg = 0;
+
+ if((p = malloc(strlen(buf) + 1)) == NULL)
+ {
+ log(LL_DBG, "init_log: malloc failed: %s", strerror(errno));
+ do_exit(1);
+ }
+
+ strcpy(p, buf);
+
+ rarr[i].re_prog = p;
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * finish logging
+ *---------------------------------------------------------------------------*/
+void
+finish_log(void)
+{
+ if(uselogfile)
+ {
+ fflush(logfp);
+ fclose(logfp);
+ }
+ else
+ {
+ (void)closelog();
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * place entry into logfile
+ *---------------------------------------------------------------------------*/
+void
+log(int what, const char *fmt, ...)
+{
+ char buffer[LOGBUFLEN];
+ register char *dp;
+ va_list ap;
+
+ va_start(ap, fmt);
+ vsnprintf(buffer, LOGBUFLEN-1, fmt, ap);
+ va_end(ap);
+
+ dp = getlogdatetime(); /* get time string ptr */
+
+#ifdef USE_CURSES
+
+ /* put log on screen ? */
+
+ if((do_fullscreen && curses_ready) &&
+ ((!debug_noscreen) || (debug_noscreen && (what != LL_DBG))))
+ {
+ wprintw(lower_w, "%s %s %-.*s\n", dp, logtab[what].text,
+ COLS-((strlen(dp))+(strlen(logtab[what].text))+2), buffer);
+ wrefresh(lower_w);
+ }
+#endif
+
+#ifdef I4B_EXTERNAL_MONITOR
+ monitor_evnt_log(logtab[what].pri, logtab[what].text, buffer);
+#endif
+
+ if(uselogfile)
+ {
+ fprintf(logfp, "%s %s %s\n", dp, logtab[what].text, buffer);
+ }
+ else
+ {
+ register char *s = buffer;
+
+ /* strip leading spaces from syslog output */
+
+ while(*s && (*s == ' '))
+ s++;
+
+ syslog(logtab[what].pri, "%s %s", logtab[what].text, s);
+ }
+
+
+#if DEBUG
+ if(what != LL_DBG) /* don't check debug logs, endless loop !!! */
+#endif
+ check_reg(buffer);
+}
+
+/*---------------------------------------------------------------------------*
+ * return ptr to static area containing date/time
+ *---------------------------------------------------------------------------*/
+char *
+getlogdatetime()
+{
+ static char logdatetime[41];
+ time_t tim;
+ register struct tm *tp;
+
+ tim = time(NULL);
+ tp = localtime(&tim);
+ strftime(logdatetime,40,I4B_TIME_FORMAT,tp);
+ return(logdatetime);
+}
+
+/*---------------------------------------------------------------------------*
+ * check for a match in the regexp array
+ *---------------------------------------------------------------------------*/
+static void
+check_reg(char *logstring)
+{
+ register int i;
+
+ for(i = 0; i < MAX_RE; i++)
+ {
+ if(rarr[i].re_flg && (!regexec(&(rarr[i].re), logstring, (size_t) 0, NULL, 0)))
+ {
+ char* argv[3];
+ argv[0] = rarr[i].re_prog;
+ argv[1] = logstring;
+ argv[2] = NULL;
+
+ exec_prog(rarr[i].re_prog, argv);
+ break;
+ }
+ }
+}
+
+/* EOF */
diff --git a/usr.sbin/i4b/isdnd/main.c b/usr.sbin/i4b/isdnd/main.c
new file mode 100644
index 0000000..9d16717
--- /dev/null
+++ b/usr.sbin/i4b/isdnd/main.c
@@ -0,0 +1,707 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * i4b daemon - main program entry
+ * -------------------------------
+ *
+ * $Id: main.c,v 1.29 1998/12/05 18:03:26 hm Exp $
+ *
+ * last edit-date: [Sat Dec 5 18:10:38 1998]
+ *
+ *---------------------------------------------------------------------------*/
+
+#ifdef I4B_EXTERNAL_MONITOR
+#include "monitor.h"
+#endif
+
+#define MAIN
+#include "isdnd.h"
+#undef MAIN
+
+#ifdef I4B_EXTERNAL_MONITOR
+
+#ifdef I4B_NOTCPIP_MONITOR
+/* monitor via local socket */
+static void mloop(int sockfd);
+#else /* I4B_NOTCPIP_MONITOR */
+/* monitor via local and tcp/ip socket */
+static void mloop(int localsock, int remotesock);
+#endif /* I4B_NOTCPIP_MONITOR */
+
+#else /* I4B_EXTERNAL_MONITOR */
+/* no monitoring at all */
+static void mloop();
+#endif /* I4B_EXTERNAL_MONITOR */
+
+#ifdef USE_CURSES
+static void kbdrdhdl(void);
+#endif
+
+static void isdnrdhdl(void);
+static void usage(void);
+
+#define MSG_BUF_SIZ 1024 /* message buffer size */
+
+/*---------------------------------------------------------------------------*
+ * usage display and exit
+ *---------------------------------------------------------------------------*/
+static void
+usage(void)
+{
+ fprintf(stderr, "\n");
+ fprintf(stderr, "isdnd - i4b ISDN manager daemon, version %02d.%02d.%d, %s %s\n", VERSION, REL, STEP, __DATE__, __TIME__);
+#ifdef DEBUG
+ fprintf(stderr, " usage: isdnd [-b] [-c file] [-d level] [-F]\n");
+#else
+ fprintf(stderr, " usage: isdnd [-b] [-c file] [-F]\n");
+#endif
+ fprintf(stderr, " [-f [-r dev] [-t termtype]] [-u time]\n");
+ fprintf(stderr, " [-l] [-L file] [-s facility] [-m]\n");
+ fprintf(stderr, " -b audible bell in fullscreen mode at connect/disconnect\n");
+ fprintf(stderr, " -c <filename> configuration file name (def: %s)\n", CONFIG_FILE_DEF);
+#ifdef DEBUG
+ fprintf(stderr, " -d <level> set debug flag bits:\n");
+ fprintf(stderr, " general = 0x%04x, rates = 0x%04x, timing = 0x%04x\n", DL_MSG, DL_RATES, DL_TIME);
+ fprintf(stderr, " state = 0x%04x, retry = 0x%04x, dial = 0x%04x\n", DL_STATE, DL_RCVRY, DL_DIAL);
+ fprintf(stderr, " process = 0x%04x, kernio = 0x%04x ctrlstat = 0x%04x\n", DL_PROC, DL_DRVR, DL_CNST);
+ fprintf(stderr, " -dn no debug output on fullscreen display\n");
+#endif
+ fprintf(stderr, " -f fullscreen status display\n");
+ fprintf(stderr, " -F do not become a daemon process\n");
+ fprintf(stderr, " -l use a logfile instead of syslog\n");
+ fprintf(stderr, " -L <file> use file instead of %s for logging\n", LOG_FILE_DEF);
+ fprintf(stderr, " -P pretty print real config to stdout and exit\n");
+ fprintf(stderr, " -r <device> redirect output to other device (for -f)\n");
+ fprintf(stderr, " -s <facility> use facility instead of %d for syslog logging\n", LOG_LOCAL0 >> 3);
+ fprintf(stderr, " -t <termtype> terminal type of redirected screen (for -f)\n");
+ fprintf(stderr, " -u <time> length of a charging unit in seconds\n");
+ fprintf(stderr, " -m inhibit network/local monitoring\n");
+ fprintf(stderr, "\n");
+ exit(1);
+}
+
+/*---------------------------------------------------------------------------*
+ * program entry
+ *---------------------------------------------------------------------------*/
+int
+main(int argc, char **argv)
+{
+ int i;
+ msg_vr_req_t mvr;
+
+#ifdef I4B_EXTERNAL_MONITOR
+ int sockfd = -1; /* local monitor socket */
+#ifndef I4B_NOTCPIP_MONITOR
+ int remotesockfd = -1; /* tcp/ip monitor socket */
+#endif
+#endif
+
+ while ((i = getopt(argc, argv, "bmc:d:fFlL:Pr:s:t:u:?")) != EOF)
+ {
+ switch (i)
+ {
+ case 'b':
+ do_bell = 1;
+ break;
+
+ case 'm':
+ inhibit_monitor = 1;
+ break;
+
+ case 'c':
+ configfile = optarg;
+ break;
+
+#ifdef DEBUG
+ case 'd':
+ if(*optarg == 'n')
+ debug_noscreen = 1;
+ else if((sscanf(optarg, "%i", &debug_flags)) == 1)
+ do_debug = 1;
+ else
+ usage();
+ break;
+#endif
+
+ case 'f':
+ do_fullscreen = 1;
+ do_fork = 0;
+#ifndef USE_CURSES
+ fprintf(stderr, "Sorry, no fullscreen mode available - daemon compiled without USE_CURSES\n");
+ exit(1);
+#endif
+ break;
+
+ case 'F':
+ do_fork = 0;
+ break;
+
+ case 'l':
+ uselogfile = 1;
+ break;
+
+ case 'L':
+ strcpy(logfile, optarg);
+ break;
+
+ case 'P':
+ do_print = 1;
+ break;
+
+ case 'r':
+ rdev = optarg;
+ do_rdev = 1;
+ break;
+
+ case 's':
+ if(isdigit(*optarg))
+ {
+ int facility;
+ logfacility = strtoul(optarg, NULL, 10);
+ facility = logfacility << 3;
+
+ if((facility < LOG_KERN) ||
+ (facility > LOG_FTP && facility < LOG_LOCAL0) ||
+ (facility > LOG_LOCAL7))
+ {
+ fprintf(stderr, "Error, option -s has invalid logging facility %d", logfacility);
+ usage();
+ }
+ logfacility = facility;
+ }
+ else
+ {
+ fprintf(stderr, "Error: option -s requires a numeric argument!\n");
+ usage();
+ }
+ break;
+
+ case 't':
+ ttype = optarg;
+ do_ttytype = 1;
+ break;
+
+ case 'u':
+ if(isdigit(*optarg))
+ {
+ unit_length = strtoul(optarg, NULL, 10);
+ if(unit_length < ULSRC_CMDLMIN)
+ unit_length = ULSRC_CMDLMIN;
+ else if(unit_length > ULSRC_CMDLMAX)
+ unit_length = ULSRC_CMDLMAX;
+ got_unitlen = 1;
+ }
+ else
+ {
+ fprintf(stderr, "Error: option -T requires a numeric argument!\n");
+ usage();
+ }
+ break;
+
+ case '?':
+ default:
+ usage();
+ break;
+ }
+ }
+#ifdef DEBUG
+ if(!do_debug)
+ debug_noscreen = 0;
+#endif
+
+ if(!do_print)
+ {
+ umask(UMASK); /* set our umask ... */
+
+ init_log(); /* initialize the logging subsystem */
+ }
+
+ check_pid(); /* check if we are already running */
+
+ if(!do_print)
+ {
+ if(do_fork || (do_fullscreen && do_rdev)) /* daemon mode ? */
+ daemonize();
+
+ write_pid(); /* write our pid to file */
+
+ /* set signal handler(s) */
+
+ signal(SIGCHLD, sigchild_handler); /* process handling */
+ signal(SIGHUP, rereadconfig); /* reread configuration */
+ signal(SIGUSR1, reopenfiles); /* reopen acct/log files*/
+ signal(SIGPIPE, SIG_IGN); /* handled manually */
+ signal(SIGINT, do_exit); /* clean up on SIGINT */
+ signal(SIGTERM, do_exit); /* clean up on SIGTERM */
+ signal(SIGQUIT, do_exit); /* clean up on SIGQUIT */
+ }
+
+ /* open isdn device */
+
+ if((isdnfd = open(I4BDEVICE, O_RDWR)) < 0)
+ {
+ log(LL_ERR, "main: cannot open %s: %s", I4BDEVICE, strerror(errno));
+ exit(1);
+ }
+
+ /* check kernel and userland have same version/release numbers */
+
+ if((ioctl(isdnfd, I4B_VR_REQ, &mvr)) < 0)
+ {
+ log(LL_ERR, "main: ioctl I4B_VR_REQ failed: %s", strerror(errno));
+ do_exit(1);
+ }
+
+ if(mvr.version != VERSION)
+ {
+ log(LL_ERR, "main: version mismatch, kernel %d, daemon %d", mvr.version, VERSION);
+ do_exit(1);
+ }
+
+ if(mvr.release != REL)
+ {
+ log(LL_ERR, "main: release mismatch, kernel %d, daemon %d", mvr.release, REL);
+ do_exit(1);
+ }
+
+ if(mvr.step != STEP)
+ {
+ log(LL_ERR, "main: step mismatch, kernel %d, daemon %d", mvr.step, STEP);
+ do_exit(1);
+ }
+
+ /* init controller state array */
+
+ init_controller();
+
+ /* read runtime configuration file and configure ourselves */
+
+ configure(configfile, 0);
+
+ if(config_error_flag)
+ {
+ log(LL_ERR, "there were %d error(s) in the configuration file, terminating!", config_error_flag);
+ exit(1);
+ }
+
+ /* handle the rates stuff */
+
+ if((i = readrates(ratesfile)) == ERROR)
+ {
+ if(rate_error != NULL)
+ log(LL_ERR, "%s", rate_error);
+ exit(1);
+ }
+
+ if(i == GOOD)
+ {
+ got_rate = 1; /* flag, ratesfile read and ok */
+ DBGL(DL_MSG, (log(LL_DBG, "ratesfile %s read successfully", ratesfile)));
+ }
+ else
+ {
+ if(rate_error != NULL)
+ log(LL_WRN, "%s", rate_error);
+ }
+
+ /* if writing accounting info, open file, set unbuffered */
+
+ if(useacctfile)
+ {
+ if((acctfp = fopen(acctfile, "a")) == NULL)
+ {
+ log(LL_ERR, "ERROR, can't open acctfile %s for writing, terminating!", acctfile);
+ exit(1);
+ }
+ setvbuf(acctfp, (char *)NULL, _IONBF, 0);
+ }
+
+ /* initialize alias processing */
+
+ if(aliasing)
+ init_alias(aliasfile);
+
+ /* init remote monitoring */
+
+#ifdef I4B_EXTERNAL_MONITOR
+ if(do_monitor)
+ {
+ monitor_init();
+ sockfd = monitor_create_local_socket();
+#ifndef I4B_NOTCPIP_MONITOR
+ remotesockfd = monitor_create_remote_socket(monitorport);
+#endif
+ }
+#endif
+
+ /* in case fullscreendisplay, initialize */
+
+#ifdef USE_CURSES
+ if(do_fullscreen)
+ {
+ init_screen();
+ }
+#endif
+
+ /* init realtime priority */
+
+#ifdef USE_RTPRIO
+ if(rt_prio != RTPRIO_NOTUSED)
+ {
+ struct rtprio rtp;
+
+ rtp.type = RTP_PRIO_REALTIME;
+ rtp.prio = rt_prio;
+
+ if((rtprio(RTP_SET, getpid(), &rtp)) == -1)
+ {
+ log(LL_ERR, "rtprio failed: %s", strerror(errno));
+ do_exit(1);
+ }
+ }
+#endif
+
+ srandom(580403); /* init random number gen */
+
+ mloop( /* enter loop of no return .. */
+#ifdef I4B_EXTERNAL_MONITOR
+ sockfd
+#ifndef I4B_NOTCPIP_MONITOR
+ , remotesockfd
+#endif
+#endif
+ );
+ do_exit(0);
+ return(0);
+}
+
+/*---------------------------------------------------------------------------*
+ * program exit
+ *---------------------------------------------------------------------------*/
+void
+do_exit(int exitval)
+{
+ close_allactive();
+
+ unlink(PIDFILE);
+
+ log(LL_DMN, "daemon terminating, exitval = %d", exitval);
+
+#ifdef USE_CURSES
+ if(do_fullscreen)
+ endwin();
+#endif
+
+#ifdef I4B_EXTERNAL_MONITOR
+ monitor_exit();
+#endif
+
+ exit(exitval);
+}
+
+/*---------------------------------------------------------------------------*
+ * main loop
+ *---------------------------------------------------------------------------*/
+static void
+mloop(
+#ifdef I4B_EXTERNAL_MONITOR
+ int localmonitor
+#ifndef I4B_NOTCPIP_MONITOR
+ , int remotemonitor
+#endif
+#endif
+)
+{
+ fd_set set;
+ struct timeval timeout;
+ int ret;
+ int high_selfd;
+
+ /* go into loop */
+
+ log(LL_DMN, "daemon started (pid = %d)", getpid());
+
+ for(;;)
+ {
+ FD_ZERO(&set);
+
+#ifdef USE_CURSES
+ if(do_fullscreen)
+ FD_SET(fileno(stdin), &set);
+#endif
+
+ FD_SET(isdnfd, &set);
+
+ high_selfd = isdnfd;
+
+#ifdef I4B_EXTERNAL_MONITOR
+ if(do_monitor)
+ {
+ if (localmonitor != -1) {
+ /* always watch for new connections */
+ FD_SET(localmonitor, &set);
+ if(localmonitor > high_selfd)
+ high_selfd = localmonitor;
+ }
+#ifndef I4B_NOTCPIP_MONITOR
+ if (remotemonitor != -1) {
+ FD_SET(remotemonitor, &set);
+ if(remotemonitor > high_selfd)
+ high_selfd = remotemonitor;
+ }
+#endif
+
+ /* if there are client connections, let monitor module
+ * enter them into the fdset */
+ if(accepted)
+ {
+ monitor_prepselect(&set, &high_selfd);
+ }
+ }
+#endif
+
+ timeout.tv_sec = 1;
+ timeout.tv_usec = 0;
+
+ ret = select(high_selfd + 1, &set, NULL, NULL, &timeout);
+
+ if(ret > 0)
+ {
+ if(FD_ISSET(isdnfd, &set))
+ isdnrdhdl();
+
+#ifdef USE_CURSES
+ if(FD_ISSET(fileno(stdin), &set))
+ kbdrdhdl();
+#endif
+
+#ifdef I4B_EXTERNAL_MONITOR
+ if(do_monitor)
+ {
+ if(localmonitor != -1 && FD_ISSET(localmonitor, &set))
+ monitor_handle_connect(localmonitor, 1);
+
+#ifndef I4B_NOTCPIP_MONITOR
+ if(remotemonitor != -1 && FD_ISSET(remotemonitor, &set))
+ monitor_handle_connect(remotemonitor, 0);
+#endif
+ if(accepted)
+ monitor_handle_input(&set);
+ }
+#endif
+ }
+ else if(ret == -1)
+ {
+ if(errno != EINTR)
+ log(LL_WRN, "ERROR, select error on isdn device, errno = %d!", errno);
+ }
+
+ /* handle timeout and recovery */
+
+ handle_recovery();
+ }
+}
+
+#ifdef USE_CURSES
+/*---------------------------------------------------------------------------*
+ * data from keyboard available, read and process it
+ *---------------------------------------------------------------------------*/
+static void
+kbdrdhdl(void)
+{
+ int ch = getch();
+
+ switch(ch)
+ {
+ case 0x0c: /* control L */
+ wrefresh(curscr);
+ break;
+
+ case '\n':
+ case '\r':
+ do_menu();
+ break;
+ }
+}
+#endif
+
+/*---------------------------------------------------------------------------*
+ * data from /dev/isdn available, read and process them
+ *---------------------------------------------------------------------------*/
+static void
+isdnrdhdl(void)
+{
+ static unsigned char msg_rd_buf[MSG_BUF_SIZ];
+ msg_hdr_t *hp = (msg_hdr_t *)&msg_rd_buf[0];
+
+ register int len;
+
+ if((len = read(isdnfd, msg_rd_buf, MSG_BUF_SIZ)) > 0)
+ {
+ switch(hp->type)
+ {
+ case MSG_CONNECT_IND:
+ msg_connect_ind((msg_connect_ind_t *)msg_rd_buf);
+ break;
+
+ case MSG_CONNECT_ACTIVE_IND:
+ msg_connect_active_ind((msg_connect_active_ind_t *)msg_rd_buf);
+ break;
+
+ case MSG_DISCONNECT_IND:
+ msg_disconnect_ind((msg_disconnect_ind_t *)msg_rd_buf);
+ break;
+
+ case MSG_DIALOUT_IND:
+ msg_dialout((msg_dialout_ind_t *)msg_rd_buf);
+ break;
+
+ case MSG_ACCT_IND:
+ msg_accounting((msg_accounting_ind_t *)msg_rd_buf);
+ break;
+
+ case MSG_IDLE_TIMEOUT_IND:
+ msg_idle_timeout_ind((msg_idle_timeout_ind_t *)msg_rd_buf);
+ break;
+
+ case MSG_CHARGING_IND:
+ msg_charging_ind((msg_charging_ind_t *)msg_rd_buf);
+ break;
+
+ case MSG_PROCEEDING_IND:
+ msg_proceeding_ind((msg_proceeding_ind_t *)msg_rd_buf);
+ break;
+
+ case MSG_ALERT_IND:
+ msg_alert_ind((msg_alert_ind_t *)msg_rd_buf);
+ break;
+
+ case MSG_DRVRDISC_REQ:
+ msg_drvrdisc_req((msg_drvrdisc_req_t *)msg_rd_buf);
+ break;
+
+ case MSG_L12STAT_IND:
+ msg_l12stat_ind((msg_l12stat_ind_t *)msg_rd_buf);
+ break;
+
+ case MSG_TEIASG_IND:
+ msg_teiasg_ind((msg_teiasg_ind_t *)msg_rd_buf);
+ break;
+
+ case MSG_PDEACT_IND:
+ msg_pdeact_ind((msg_pdeact_ind_t *)msg_rd_buf);
+ break;
+
+ case MSG_NEGCOMP_IND:
+ msg_negcomplete_ind((msg_negcomplete_ind_t *)msg_rd_buf);
+ break;
+
+ case MSG_IFSTATE_CHANGED_IND:
+ msg_ifstatechg_ind((msg_ifstatechg_ind_t *)msg_rd_buf);
+ break;
+
+ default:
+ log(LL_WRN, "ERROR, unknown message received from /dev/isdn (0x%x)", msg_rd_buf[0]);
+ break;
+ }
+ }
+ else
+ {
+ log(LL_WRN, "ERROR, read error on isdn device, errno = %d, length = %d", errno, len);
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * re-read the config file on SIGHUP or menu command
+ *---------------------------------------------------------------------------*/
+void
+rereadconfig(int dummy)
+{
+ extern int entrycount;
+
+ log(LL_DMN, "re-reading configuration file");
+
+ close_allactive();
+
+ entrycount = -1;
+ nentries = 0;
+
+ /* read runtime configuration file and configure ourselves */
+
+ configure(configfile, 1);
+
+ if(config_error_flag)
+ {
+ log(LL_ERR, "there were %d error(s) in the configuration file, terminating!", config_error_flag);
+ unlink(PIDFILE);
+ exit(1);
+ }
+
+ if(aliasing)
+ {
+ /* reread alias database */
+ free_aliases();
+ init_alias(aliasfile);
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * re-open the log/acct files on SIGUSR1
+ *---------------------------------------------------------------------------*/
+void
+reopenfiles(int dummy)
+{
+ if(useacctfile)
+ {
+ fflush(acctfp);
+ fclose(acctfp);
+
+ if((acctfp = fopen(acctfile, "a")) == NULL)
+ {
+ log(LL_ERR, "ERROR, can't open acctfile %s for writing, terminating!", acctfile);
+ exit(1);
+ }
+ setvbuf(acctfp, (char *)NULL, _IONBF, 0);
+ }
+
+ if(uselogfile)
+ {
+ finish_log();
+
+ if((logfp = fopen(logfile, "a")) == NULL)
+ {
+ fprintf(stderr, "ERROR, cannot open logfile %s: %s\n",
+ logfile, strerror(errno));
+ exit(1);
+ }
+
+ /* set unbuffered operation */
+
+ setvbuf(logfp, (char *)NULL, _IONBF, 0);
+ }
+}
+
+/* EOF */
diff --git a/usr.sbin/i4b/isdnd/monitor.c b/usr.sbin/i4b/isdnd/monitor.c
new file mode 100644
index 0000000..884df13
--- /dev/null
+++ b/usr.sbin/i4b/isdnd/monitor.c
@@ -0,0 +1,811 @@
+/*
+ * Copyright (c) 1998 Martin Husemann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 4. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software and/or documentation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * i4b daemon - network monitor server module
+ * ------------------------------------------
+ *
+ * $Id: monitor.c,v 1.6 1998/08/10 13:55:24 hm Exp $
+ *
+ * last edit-date: [Fri Jul 17 18:07:00 1998]
+ *
+ * -mh created
+ *
+ *---------------------------------------------------------------------------*/
+
+#include "isdnd.h"
+
+#ifndef I4B_EXTERNAL_MONITOR
+/* dummy version of routines needed by config file parser
+ * (config files should be valid with and without external montioring
+ * support compiled into the daemon) */
+void monitor_clear_rights()
+{ }
+int monitor_start_rights(const char *clientspec)
+{ return I4BMAR_OK; }
+void monitor_add_rights(int rights_mask)
+{ }
+void monitor_fixup_rights()
+{ }
+#else
+
+#include "monitor.h"
+#include "vararray.h"
+#include <sys/socket.h>
+#include <sys/un.h>
+#ifndef I4B_NOTCPIP_MONITOR
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#endif
+
+VARA_DECL(struct monitor_rights) rights = VARA_INITIALIZER;
+#define INITIAL_RIGHTS_ALLOC 10 /* most users will have one or two entries */
+
+static int local_rights = -1; /* index of entry for local socket, -1 if none */
+
+/* for each active monitor connection we have one of this: */
+struct monitor_connection {
+ int sock; /* socket for this connection */
+ int rights; /* active rights for this connection */
+ int events; /* bitmask of events client is interested in */
+};
+static VARA_DECL(struct monitor_connection) connections = VARA_INITIALIZER;
+#define INITIAL_CONNECTIONS_ALLOC 30 /* high guess */
+
+/* derive channel number from config pointer */
+#define CHNO(cfgp) (((cfgp)->isdncontrollerused*2) + (cfgp)->isdnchannelused)
+
+/* local prototypes */
+static int cmp_rights(const void *a, const void *b);
+static int monitor_command(int con_index, int fd, int rights);
+static void cmd_dump_rights(int fd, int rights, BYTE *cmd);
+static void cmd_dump_mcons(int fd, int rights, BYTE *cmd);
+static void cmd_reread_cfg(int fd, int rights, BYTE *cmd);
+static void cmd_hangup(int fd, int rights, BYTE *cmd);
+static void monitor_broadcast(int mask, const BYTE *pkt, size_t bytes);
+static int anybody(int mask);
+
+/*
+ * Due to the way we structure config files, the rights for an external
+ * monitor might be stated in multiple steps. First a call to
+ * monitor_start_rights opens an entry. Further (optional) calls to
+ * montior_add_rights assemble additional rights for this "current"
+ * entry. When closing the sys-file section of the config file, the
+ * "current" entry becomes invalid.
+ */
+static int cur_add_entry = -1;
+
+/*
+ * Initialize the monitor server module. This affects only active
+ * connections, the access rights are not modified here!
+ */
+void monitor_init()
+{
+ accepted = 0;
+ VARA_EMPTY(connections);
+}
+
+/*
+ * Prepare for exit
+ */
+void monitor_exit()
+{
+ int i;
+
+ /* Close all open connections. */
+ VARA_FOREACH(connections, i)
+ close(VARA_AT(connections, i).sock);
+
+ /* Remove their descriptions */
+ VARA_EMPTY(connections);
+}
+
+/*
+ * Initialize access rights. No active connections are affected!
+ */
+void monitor_clear_rights()
+{
+ VARA_EMPTY(rights);
+ cur_add_entry = -1;
+}
+
+/*
+ * Add an entry to the access lists. The clientspec either is
+ * the name of the local socket or a host- or networkname or
+ * numeric ip/host-bit-len spec.
+ */
+int monitor_start_rights(const char *clientspec)
+{
+ int i;
+ struct monitor_rights r;
+
+ /* initialize the new rights entry */
+ memset(&r, 0, sizeof r);
+
+ /* check clientspec */
+ if (*clientspec == '/') {
+ struct sockaddr_un sa;
+
+ /* this is a local socket spec, check if we already have one */
+ if (VARA_VALID(rights, local_rights))
+ return I4BMAR_DUP;
+ /* does it fit in a local socket address? */
+ if (strlen(clientspec) > sizeof sa.sun_path)
+ return I4BMAR_LENGTH;
+ r.local = 1;
+ strcpy(r.name, clientspec);
+#ifndef I4B_NOTCPIP_MONITOR
+ } else {
+ /* remote entry, parse host/net and cidr */
+ char hostname[FILENAME_MAX];
+ char *p;
+ p = strchr(clientspec, '/');
+ if (!p) {
+ struct hostent *host;
+ u_int32_t hn;
+ /* must be a host spec */
+ r.mask = ~0;
+ host = gethostbyname(clientspec);
+ if (!host)
+ return I4BMAR_NOIP;
+ memcpy(&hn, host->h_addr_list[0], sizeof hn);
+ r.net = (u_int32_t)ntohl(hn);
+ } else if (p[1]) {
+ /* must be net/cidr spec */
+ int l;
+ struct netent *net;
+ u_int32_t s = ~0U;
+ int num = strtol(p+1, NULL, 10);
+ if (num < 0 || num > 32)
+ return I4BMAR_CIDR;
+ s >>= num;
+ s ^= ~0U;
+ l = p - clientspec;
+ if (l >= sizeof hostname)
+ return I4BMAR_LENGTH;
+ strncpy(hostname, clientspec, l);
+ hostname[l] = '\0';
+ net = getnetbyname(hostname);
+ if (net == NULL)
+ r.net = (u_int32_t)inet_network(hostname);
+ else
+ r.net = (u_int32_t)net->n_net;
+ r.mask = s;
+ r.net &= s;
+ } else
+ return I4BMAR_CIDR;
+
+ /* check for duplicate entry */
+ VARA_FOREACH(rights, i)
+ if (VARA_AT(rights, i).mask == r.mask &&
+ VARA_AT(rights, i).net == r.net &&
+ VARA_AT(rights, i).local == r.local)
+ return I4BMAR_DUP;
+#endif
+ }
+ r.rights = 0;
+
+ /* entry ok, add it to the collection */
+ cur_add_entry = i = VARA_NUM(rights);
+ VARA_ADD_AT(rights, i, struct monitor_rights, INITIAL_RIGHTS_ALLOC);
+ memcpy(&VARA_AT(rights, i), &r, sizeof r);
+ if (r.local)
+ local_rights = i;
+
+ log(LL_DBG, "system: monitor = %s", clientspec);
+
+ return I4BMAR_OK;
+}
+
+/*
+ * Add rights to the currently constructed entry - if any.
+ */
+void monitor_add_rights(int rights_mask)
+{
+ if (cur_add_entry < 0) return; /* noone under construction */
+
+ VARA_AT(rights, cur_add_entry).rights |= rights_mask;
+
+ log(LL_DBG, "system: monitor-access = 0x%x", rights_mask);
+}
+
+/*
+ * All rights have been added now. Sort the to get most specific
+ * host/net masks first, so we can travel the list and use the first
+ * match for actual rights.
+ */
+void monitor_fixup_rights()
+{
+ int i;
+
+ /* no more rights may be added to the current entry */
+ cur_add_entry = -1;
+
+ /* sort the rights array */
+ qsort(VARA_PTR(rights), VARA_NUM(rights), sizeof(struct monitor_rights), cmp_rights);
+
+ /* now the local entry may have moved, update its index */
+ if (VARA_VALID(rights, local_rights)) {
+ local_rights = -1;
+ VARA_FOREACH(rights, i) {
+ if (VARA_AT(rights, i).local) {
+ local_rights = i;
+ break;
+ }
+ }
+ }
+}
+
+/* comparator for rights */
+static int cmp_rights(const void *a, const void *b)
+{
+ u_int32_t mask;
+ struct monitor_rights const * pa = (struct monitor_rights const*)a;
+ struct monitor_rights const * pb = (struct monitor_rights const*)b;
+
+ /* local sorts first */
+ if (pa->local)
+ return -1;
+
+ /* which is the less specific netmask? */
+ mask = pa->mask;
+ if ((pb->mask & mask) == 0)
+ mask = pb->mask;
+ /* are the entries disjunct? */
+ if ((pa->net & mask) != (pb->net & mask)) {
+ /* simply compare net part of address */
+ return ((pa->net & mask) < (pb->net & mask)) ? -1 : 1;
+ }
+ /* One entry is part of the others net. We already now "mask" is
+ * the netmask of the less specific (i.e. greater) one */
+ return (pa->mask == mask) ? 1 : -1;
+}
+
+#ifndef I4B_NOTCPIP_MONITOR
+/*
+ * Check if access rights for a remote socket are specified and
+ * create this socket. Return -1 otherwise.
+ */
+int monitor_create_remote_socket(int portno)
+{
+ struct sockaddr_in sa;
+ int val;
+ int remotesockfd = socket(AF_INET, SOCK_STREAM, 0);
+ if (remotesockfd == -1) {
+ log(LL_ERR, "could not create remote monitor socket, errno = %d", errno);
+ exit(1);
+ }
+ val = 1;
+ if (setsockopt(remotesockfd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof val)) {
+ log(LL_ERR, "could not setsockopt, errno = %d", errno);
+ exit(1);
+ }
+ memset(&sa, 0, sizeof sa);
+ sa.sin_len = sizeof sa;
+ sa.sin_family = AF_INET;
+ sa.sin_port = htons(portno);
+ sa.sin_addr.s_addr = htonl(INADDR_ANY);
+ if (bind(remotesockfd, (struct sockaddr *)&sa, sizeof sa) == -1) {
+ log(LL_ERR, "could not bind remote monitor socket to port %d, errno = %d", portno, errno);
+ exit(1);
+ }
+ if (listen(remotesockfd, 0)) {
+ log(LL_ERR, "could not listen on monitor socket, errno = %d", errno);
+ exit(1);
+ }
+
+ return remotesockfd;
+}
+#endif
+
+/*
+ * Check if access rights for a local socket are specified and
+ * create this socket. Return -1 otherwise.
+ */
+int monitor_create_local_socket()
+{
+ int s;
+ struct sockaddr_un sa;
+
+ /* check for a local entry */
+ if (!VARA_VALID(rights, local_rights))
+ return -1;
+
+ /* create and setup socket */
+ s = socket(AF_LOCAL, SOCK_STREAM, 0);
+ if (s == -1) {
+ log(LL_ERR, "could not create local monitor socket, errno = %d", errno);
+ exit(1);
+ }
+ unlink(VARA_AT(rights, local_rights).name);
+ memset(&sa, 0, sizeof sa);
+ sa.sun_len = sizeof sa;
+ sa.sun_family = AF_LOCAL;
+ strcpy(sa.sun_path, VARA_AT(rights, local_rights).name);
+ if (bind(s, (struct sockaddr *)&sa, sizeof sa)) {
+ log(LL_ERR, "could not bind local monitor socket [%s], errno = %d", VARA_AT(rights, local_rights).name, errno);
+ exit(1);
+ }
+ if (listen(s, 0)) {
+ log(LL_ERR, "could not listen on local monitor socket, errno = %d", errno);
+ exit(1);
+ }
+
+ return s;
+}
+
+/*
+ * Prepare a fd_set for a select call. Add all our local
+ * filedescriptors to the set, increment max_fd if appropriate.
+ */
+void monitor_prepselect(fd_set *selset, int *max_fd)
+{
+ int i;
+
+ VARA_FOREACH(connections, i) {
+ int fd = VARA_AT(connections, i).sock;
+ if (fd > *max_fd)
+ *max_fd = fd;
+ FD_SET(fd, selset);
+ }
+}
+
+/*
+ * Check if the result from a select call indicates something
+ * to do for us.
+ */
+void monitor_handle_input(fd_set *selset)
+{
+ int i;
+
+ VARA_FOREACH(connections, i) {
+ int fd = VARA_AT(connections, i).sock;
+ if (FD_ISSET(fd, selset)) {
+ /* handle command from this client */
+ if (monitor_command(i, fd, VARA_AT(connections, i).rights) != 0) {
+ /* broken or closed connection */
+ log(LL_DBG, "monitor connection #%d closed", i);
+ VARA_REMOVEAT(connections, i);
+ i--;
+ }
+ }
+ }
+
+ /* all connections gone? */
+ if (VARA_NUM(connections) == 0)
+ accepted = 0;
+}
+
+/*
+ * Try new incoming connection on the given socket.
+ * Setup client descriptor and send initial data.
+ */
+void monitor_handle_connect(int sockfd, int is_local)
+{
+ struct monitor_connection *con;
+#ifndef I4B_NOTCPIP_MONITOR
+ struct sockaddr_in ia;
+ u_int32_t ha = 0;
+#endif
+ struct sockaddr_un ua;
+ BYTE idata[I4B_MON_IDATA_SIZE];
+ int fd = -1, s, i, r_mask;
+ char source[FILENAME_MAX];
+
+ /* accept the connection */
+ if (is_local) {
+ s = sizeof ua;
+ fd = accept(sockfd, (struct sockaddr *)&ua, &s);
+ strcpy(source, "local connection");
+#ifndef I4B_NOTCPIP_MONITOR
+ } else {
+ s = sizeof ia;
+ fd = accept(sockfd, (struct sockaddr *)&ia, &s);
+ snprintf(source, sizeof source, "tcp/ip connection from %s\n",
+ inet_ntoa(ia.sin_addr));
+ memcpy(&ha, &ia.sin_addr.s_addr, sizeof ha);
+ ha = ntohl(ha);
+#endif
+ }
+
+ /* check the access rights of this connection */
+ r_mask = 0;
+ VARA_FOREACH(rights, i) {
+ struct monitor_rights *r = &VARA_AT(rights, i);
+ if (r->local) {
+ if (is_local) {
+ r_mask = r->rights;
+ break;
+ }
+#ifndef I4B_NOTCPIP_MONITOR
+ } else {
+ if ((ha & r->mask) == r->net) {
+ r_mask = r->rights;
+ break;
+ }
+#endif
+ }
+ }
+
+ if (r_mask == 0) {
+ /* no rights - go away */
+ log(LL_DBG, "monitor access denied: %s", source);
+ close(fd);
+ return;
+ }
+
+ accepted = 1;
+ i = VARA_NUM(connections);
+ VARA_ADD_AT(connections, i, struct monitor_connection, INITIAL_CONNECTIONS_ALLOC);
+ con = &VARA_AT(connections, i);
+ memset(con, 0, sizeof *con);
+ con->sock = fd;
+ con->rights = r_mask;
+ log(LL_DBG, "monitor access granted, rights = %x, #%d, %s",
+ r_mask, i, source);
+
+ /* send initial data */
+ I4B_PREP_CMD(idata, I4B_MON_IDATA_CODE);
+ I4B_PUT_2B(idata, I4B_MON_IDATA_VERSMAJOR, MPROT_VERSION);
+ I4B_PUT_2B(idata, I4B_MON_IDATA_VERSMINOR, MPROT_REL);
+ I4B_PUT_2B(idata, I4B_MON_IDATA_NUMCTRL, ncontroller);
+ I4B_PUT_4B(idata, I4B_MON_IDATA_CLACCESS, r_mask);
+ write(fd, idata, sizeof idata);
+
+ for (i = 0; i < ncontroller; i++) {
+ BYTE ictrl[I4B_MON_ICTRL_SIZE];
+ I4B_PREP_CMD(ictrl, I4B_MON_ICTRL_CODE);
+ I4B_PUT_STR(ictrl, I4B_MON_ICTRL_NAME, name_of_controller(isdn_ctrl_tab[i].ctrl_type, isdn_ctrl_tab[i].card_type));
+ I4B_PUT_2B(ictrl, I4B_MON_ICTRL_BUSID, 0);
+ I4B_PUT_4B(ictrl, I4B_MON_ICTRL_FLAGS, 0);
+ I4B_PUT_4B(ictrl, I4B_MON_ICTRL_NCHAN, 2);
+ write(fd, ictrl, sizeof ictrl);
+ }
+}
+
+/* dump all monitor rights */
+static void cmd_dump_rights(int fd, int r_mask, BYTE *cmd)
+{
+ int i;
+ BYTE drini[I4B_MON_DRINI_SIZE];
+ BYTE dr[I4B_MON_DR_SIZE];
+
+ I4B_PREP_EVNT(drini, I4B_MON_DRINI_CODE);
+ I4B_PUT_2B(drini, I4B_MON_DRINI_COUNT, VARA_NUM(rights));
+ write(fd, drini, sizeof drini);
+
+ VARA_FOREACH(rights, i) {
+ I4B_PREP_EVNT(dr, I4B_MON_DR_CODE);
+ I4B_PUT_4B(dr, I4B_MON_DR_RIGHTS, VARA_AT(rights, i).rights);
+ I4B_PUT_4B(dr, I4B_MON_DR_NET, VARA_AT(rights, i).net);
+ I4B_PUT_4B(dr, I4B_MON_DR_MASK, VARA_AT(rights, i).mask);
+ I4B_PUT_1B(dr, I4B_MON_DR_LOCAL, VARA_AT(rights, i).local);
+ write(fd, dr, sizeof dr);
+ }
+}
+
+/* rescan config file */
+static void cmd_reread_cfg(int fd, int rights, BYTE *cmd)
+{
+ rereadconfig(42);
+}
+
+/* drop one connection */
+static void cmd_hangup(int fd, int rights, BYTE *cmd)
+{
+ int channel = I4B_GET_4B(cmd, I4B_MON_HANGUP_CHANNEL);
+ hangup_channel(channel);
+}
+
+/* dump all active monitor connections */
+static void cmd_dump_mcons(int fd, int rights, BYTE *cmd)
+{
+ int i;
+ BYTE dcini[I4B_MON_DCINI_SIZE];
+
+ I4B_PREP_EVNT(dcini, I4B_MON_DCINI_CODE);
+ I4B_PUT_2B(dcini, I4B_MON_DCINI_COUNT, VARA_NUM(connections));
+ write(fd, dcini, sizeof dcini);
+
+ VARA_FOREACH(connections, i) {
+#ifndef I4B_NOTCPIP_MONITOR
+ int namelen;
+ struct sockaddr_in name;
+#endif
+ BYTE dc[I4B_MON_DC_SIZE];
+
+ I4B_PREP_EVNT(dc, I4B_MON_DC_CODE);
+ I4B_PUT_4B(dc, I4B_MON_DC_RIGHTS, VARA_AT(connections, i).rights);
+#ifndef I4B_NOTCPIP_MONITOR
+ namelen = sizeof name;
+ if (getpeername(VARA_AT(connections, i).sock, (struct sockaddr*)&name, &namelen) == 0)
+ memcpy(dc+I4B_MON_DC_WHO, &name.sin_addr, sizeof name.sin_addr);
+#endif
+ write(fd, dc, sizeof dc);
+ }
+}
+
+/*
+ * Handle a command from the given socket. The client
+ * has rights as specified in the rights parameter.
+ * Return non-zero if connection is closed.
+ */
+static int monitor_command(int con_index, int fd, int rights)
+{
+ char cmd[I4B_MAX_MON_CLIENT_CMD];
+ u_int code;
+ /* command dispatch table */
+ typedef void (*cmd_func_t)(int fd, int rights, BYTE *cmd);
+ static struct {
+ cmd_func_t call; /* function to execute */
+ u_int rights; /* necessary rights */
+ } cmd_tab[] =
+ {
+ /* 0 */ { NULL, 0 },
+ /* 1 */ { cmd_dump_rights, I4B_CA_COMMAND_FULL },
+ /* 2 */ { cmd_dump_mcons, I4B_CA_COMMAND_FULL },
+ /* 3 */ { cmd_reread_cfg, I4B_CA_COMMAND_FULL },
+ /* 4 */ { cmd_hangup, I4B_CA_COMMAND_FULL },
+ };
+#define NUMCMD (sizeof cmd_tab / sizeof cmd_tab[0])
+
+ u_long u;
+ int bytes;
+
+ /* Network transfer may deliver two or more packets concatenated.
+ * Peek at the header and read only one event at a time... */
+ ioctl(fd, FIONREAD, &u);
+ if (u < I4B_MON_CMD_HDR) {
+ if (u == 0) {
+ /* socket closed by peer */
+ close(fd);
+ return 1;
+ }
+ return 0; /* not enough data there yet */
+ }
+ bytes = recv(fd, cmd, I4B_MON_CMD_HDR, MSG_PEEK);
+ if (bytes < I4B_MON_CMD_HDR)
+ return 0; /* errh? something must be wrong... */
+ bytes = I4B_GET_2B(cmd, I4B_MON_CMD_LEN);
+ if (bytes >= sizeof cmd) {
+ close(fd);
+ log(LL_ERR, "garbage on monitor connection #%d, closing it", con_index);
+ return 1;
+ }
+ /* now we know the size, it fits, so lets read it! */
+ if (read(fd, cmd, bytes) <= 0) {
+ close(fd);
+ return 1;
+ }
+
+ /* decode command */
+ code = I4B_GET_2B(cmd, I4B_MON_CMD);
+
+ /* special case: may modify our connection descriptor, is
+ * beyound all rights checks */
+ if (code == I4B_MON_CCMD_SETMASK) {
+ /*
+ u_int major = I4B_GET_2B(cmd, I4B_MON_ICLIENT_VERMAJOR);
+ u_int minor = I4B_GET_2B(cmd, I4B_MON_ICLIENT_VERMINOR);
+ */
+ int events = I4B_GET_4B(cmd, I4B_MON_ICLIENT_EVENTS);
+ VARA_AT(connections, con_index).events = events & rights;
+ return 0;
+ }
+
+ if (code < 0 || code >= NUMCMD) {
+ log(LL_ERR, "illegal command from client #%d: code = %d\n",
+ con_index, code);
+ return 0;
+ }
+ if (cmd_tab[code].call == NULL)
+ return 0;
+ if ((cmd_tab[code].rights & rights) == cmd_tab[code].rights)
+ cmd_tab[code].call(fd, rights, cmd);
+
+ return 0;
+}
+
+/*
+ * Check if somebody would receive an event with this mask.
+ * We are lazy and try to avoid assembling unneccesary packets.
+ * Return 0 if no one interested, nonzero otherwise.
+ */
+static int anybody(int mask)
+{
+ int i;
+
+ VARA_FOREACH(connections, i)
+ if ((VARA_AT(connections, i).events & mask) == mask)
+ return 1;
+
+ return 0;
+}
+
+/*
+ * Send an event to every connection interested in this kind of
+ * event
+ */
+static void monitor_broadcast(int mask, const BYTE *pkt, size_t bytes)
+{
+ int i;
+
+ VARA_FOREACH(connections, i) {
+ if ((VARA_AT(connections, i).events & mask) == mask) {
+ int fd = VARA_AT(connections, i).sock;
+ write(fd, pkt, bytes);
+ }
+ }
+}
+
+/*
+ * Post a logfile event
+ */
+void monitor_evnt_log(int prio, const char * what, const char * msg)
+{
+ BYTE evnt[I4B_MON_LOGEVNT_SIZE];
+ time_t now;
+
+ if (!anybody(I4B_CA_EVNT_I4B)) return;
+
+ time(&now);
+ I4B_PREP_EVNT(evnt, I4B_MON_LOGEVNT_CODE);
+ I4B_PUT_4B(evnt, I4B_MON_LOGEVNT_TSTAMP, (long)now);
+ I4B_PUT_4B(evnt, I4B_MON_LOGEVNT_PRIO, prio);
+ I4B_PUT_STR(evnt, I4B_MON_LOGEVNT_WHAT, what);
+ I4B_PUT_STR(evnt, I4B_MON_LOGEVNT_MSG, msg);
+
+ monitor_broadcast(I4B_CA_EVNT_I4B, evnt, sizeof evnt);
+}
+
+/*
+ * Post a charging event on the connection described
+ * by the given config entry.
+ */
+void monitor_evnt_charge(cfg_entry_t *cep, int units, int estimate)
+{
+ int chno = CHNO(cep);
+ int mask = (cep->direction == DIR_IN) ? I4B_CA_EVNT_CALLIN : I4B_CA_EVNT_CALLOUT;
+ time_t now;
+ BYTE evnt[I4B_MON_CHRG_SIZE];
+
+ if (!anybody(mask)) return;
+
+ time(&now);
+ I4B_PREP_EVNT(evnt, I4B_MON_CHRG_CODE);
+ I4B_PUT_4B(evnt, I4B_MON_CHRG_TSTAMP, (long)now);
+ I4B_PUT_4B(evnt, I4B_MON_CHRG_CHANNEL, chno);
+ I4B_PUT_4B(evnt, I4B_MON_CHRG_UNITS, units);
+ I4B_PUT_4B(evnt, I4B_MON_CHRG_ESTIMATED, estimate ? 1 : 0);
+
+ monitor_broadcast(mask, evnt, sizeof evnt);
+}
+
+/*
+ * Post a connection event
+ */
+void monitor_evnt_connect(cfg_entry_t *cep)
+{
+ BYTE evnt[I4B_MON_CONNECT_SIZE];
+ char devname[I4B_MAX_MON_STRING];
+ int chno = CHNO(cep);
+ int mask = (cep->direction == DIR_IN) ? I4B_CA_EVNT_CALLIN : I4B_CA_EVNT_CALLOUT;
+ time_t now;
+
+ if (!anybody(mask)) return;
+
+ time(&now);
+ snprintf(devname, sizeof devname, "%s%d", bdrivername(cep->usrdevicename), cep->usrdeviceunit);
+ I4B_PREP_EVNT(evnt, I4B_MON_CONNECT_CODE);
+ I4B_PUT_4B(evnt, I4B_MON_CONNECT_TSTAMP, (long)now);
+ I4B_PUT_4B(evnt, I4B_MON_CONNECT_DIR, cep->direction == DIR_OUT ? 1 : 0);
+ I4B_PUT_4B(evnt, I4B_MON_CONNECT_CHANNEL, chno);
+ I4B_PUT_STR(evnt, I4B_MON_CONNECT_CFGNAME, cep->name);
+ I4B_PUT_STR(evnt, I4B_MON_CONNECT_DEVNAME, devname);
+ I4B_PUT_STR(evnt, I4B_MON_CONNECT_REMPHONE, cep->real_phone_incoming);
+ I4B_PUT_STR(evnt, I4B_MON_CONNECT_LOCPHONE, cep->remote_phone_dialout);
+
+ monitor_broadcast(mask, evnt, sizeof evnt);
+}
+
+/*
+ * Post a disconnect event
+ */
+void monitor_evnt_disconnect(cfg_entry_t *cep)
+{
+ BYTE evnt[I4B_MON_DISCONNECT_SIZE];
+ int chno = CHNO(cep);
+ int mask = (cep->direction == DIR_IN) ? I4B_CA_EVNT_CALLIN : I4B_CA_EVNT_CALLOUT;
+ time_t now;
+
+ if (!anybody(mask)) return;
+
+ time(&now);
+ I4B_PREP_EVNT(evnt, I4B_MON_DISCONNECT_CODE);
+ I4B_PUT_4B(evnt, I4B_MON_DISCONNECT_TSTAMP, (long)now);
+ I4B_PUT_4B(evnt, I4B_MON_DISCONNECT_CHANNEL, chno);
+
+ monitor_broadcast(mask, evnt, sizeof evnt);
+}
+
+/*
+ * Post an up/down event
+ */
+void monitor_evnt_updown(cfg_entry_t *cep, int up)
+{
+ BYTE evnt[I4B_MON_UPDOWN_SIZE];
+ int chno = CHNO(cep);
+ int mask = (cep->direction == DIR_IN) ? I4B_CA_EVNT_CALLIN : I4B_CA_EVNT_CALLOUT;
+ time_t now;
+
+ if (!anybody(mask)) return;
+
+ time(&now);
+ I4B_PREP_EVNT(evnt, I4B_MON_UPDOWN_CODE);
+ I4B_PUT_4B(evnt, I4B_MON_UPDOWN_TSTAMP, (long)now);
+ I4B_PUT_4B(evnt, I4B_MON_UPDOWN_CHANNEL, chno);
+ I4B_PUT_4B(evnt, I4B_MON_UPDOWN_ISUP, up);
+
+ monitor_broadcast(mask, evnt, sizeof evnt);
+}
+
+void hangup_channel(int channel)
+{
+ int i;
+ cfg_entry_t * cep = NULL;
+
+ for (i = 0; i < ncontroller; i++)
+ {
+ if(isdn_ctrl_tab[i].state != CTRL_UP)
+ continue;
+ if(isdn_ctrl_tab[i].stateb1 != CHAN_IDLE)
+ {
+ cep = get_cep_by_cc(i, 0);
+ if (cep != NULL && CHNO(cep) == channel)
+ goto found;
+ }
+ if(isdn_ctrl_tab[i].stateb2 != CHAN_IDLE)
+ {
+ cep = get_cep_by_cc(i, 1);
+ if (cep != NULL && CHNO(cep) == channel)
+ goto found;
+ }
+ }
+ /* not found */
+ return;
+
+found:
+ cep->hangup = 1;
+ return;
+}
+
+#endif /* I4B_EXTERNAL_MONITOR */
diff --git a/usr.sbin/i4b/isdnd/msghdl.c b/usr.sbin/i4b/isdnd/msghdl.c
new file mode 100644
index 0000000..61ac0ed
--- /dev/null
+++ b/usr.sbin/i4b/isdnd/msghdl.c
@@ -0,0 +1,983 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * i4b daemon - message from kernel handling routines
+ * --------------------------------------------------
+ *
+ * $Id: msghdl.c,v 1.54 1998/12/19 09:03:16 hm Exp $
+ *
+ * last edit-date: [Sat Dec 19 09:57:16 1998]
+ *
+ *---------------------------------------------------------------------------*/
+
+#include "isdnd.h"
+
+/*---------------------------------------------------------------------------*
+ * handle incoming CONNECT_IND (=SETUP) message
+ *---------------------------------------------------------------------------*/
+void
+msg_connect_ind(msg_connect_ind_t *mp)
+{
+ cfg_entry_t *cep;
+ char *src_tela = "ERROR-src_tela";
+ char *dst_tela = "ERROR-dst_tela";
+
+#define SRC (aliasing == 0 ? mp->src_telno : src_tela)
+#define DST (aliasing == 0 ? mp->dst_telno : dst_tela)
+
+ if((cep = find_matching_entry_incoming(mp)) == NULL)
+ {
+ /* log message generated in find_matching_entry_incoming() */
+ sendm_connect_resp(NULL, mp->header.cdid, SETUP_RESP_DNTCRE, 0);
+ return;
+ }
+
+ if(cep->cdid != CDID_UNUSED && cep->cdid != CDID_RESERVED)
+ {
+ /*
+ * This is an incoming call on a number we just dialed out.
+ * Stop our dial-out and accept the incoming call.
+ */
+ if(cep->saved_call.cdid != CDID_UNUSED &&
+ cep->saved_call.cdid != CDID_RESERVED)
+ {
+ int cdid;
+
+ /* disconnect old, not new */
+
+ cdid = cep->cdid;
+ cep->cdid = cep->saved_call.cdid;
+ sendm_disconnect_req(cep, (CAUSET_I4B << 8) | CAUSE_I4B_NORMAL);
+ cep->cdid = cdid;
+
+ /*
+ * Shortcut the state machine and mark this
+ * entry as free
+ */
+/* XXX */ cep->state = ST_IDLE; /* this is an invalid */
+ /* transition, */
+ /* so no next_state() */
+ /* we have to wait here for an incoming */
+ /* disconnect message !!! (-hm) */
+ }
+ }
+
+ if(aliasing)
+ {
+ src_tela = get_alias(mp->src_telno);
+ dst_tela = get_alias(mp->dst_telno);
+ }
+
+ if(cep->inout == DIR_OUTONLY)
+ {
+ log(LL_CHD, "%05d %s incoming call from %s to %s not allowed by configuration!",
+ mp->header.cdid, cep->name, SRC, DST);
+ sendm_connect_resp(NULL, mp->header.cdid, SETUP_RESP_DNTCRE, 0);
+ return;
+ }
+
+ cep->charge = 0;
+ cep->last_charge = 0;
+
+ switch(cep->dialin_reaction)
+ {
+ case REACT_ACCEPT:
+ log(LL_CHD, "%05d %s accepting: incoming call from %s to %s",
+ mp->header.cdid, cep->name, SRC, DST);
+ decr_free_channels(mp->controller);
+ next_state(cep, EV_MCI);
+ break;
+
+ case REACT_REJECT:
+ log(LL_CHD, "%05d %s rejecting: incoming call from %s to %s",
+ mp->header.cdid, cep->name, SRC, DST);
+ sendm_connect_resp(cep, mp->header.cdid, SETUP_RESP_REJECT,
+ (CAUSET_I4B << 8) | CAUSE_I4B_REJECT);
+ cep->cdid = CDID_UNUSED;
+ break;
+
+ case REACT_IGNORE:
+ log(LL_CHD, "%05d %s ignoring: incoming call from %s to %s",
+ mp->header.cdid, cep->name, SRC, DST);
+ sendm_connect_resp(NULL, mp->header.cdid, SETUP_RESP_DNTCRE, 0);
+ break;
+
+ case REACT_ANSWER:
+ decr_free_channels(mp->controller);
+ if(cep->alert)
+ {
+ if(mp->display)
+ {
+ log(LL_CHD, "%05d %s alerting: incoming call from %s to %s (%s)",
+ mp->header.cdid, cep->name, SRC, DST, mp->display);
+ }
+ else
+ {
+ log(LL_CHD, "%05d %s alerting: incoming call from %s to %s",
+ mp->header.cdid, cep->name, SRC, DST);
+ }
+ next_state(cep, EV_ALRT);
+ }
+ else
+ {
+ if(mp->display)
+ {
+ log(LL_CHD, "%05d %s answering: incoming call from %s to %s (%s)",
+ mp->header.cdid, cep->name, SRC, DST, mp->display);
+ }
+ else
+ {
+ log(LL_CHD, "%05d %s answering: incoming call from %s to %s",
+ mp->header.cdid, cep->name, SRC, DST);
+ }
+ next_state(cep, EV_MCI);
+ }
+ break;
+
+ case REACT_CALLBACK:
+#ifdef NOTDEF
+/*XXX reserve channel ??? */ decr_free_channels(mp->controller);
+#endif
+ if(cep->cdid == CDID_RESERVED)
+ {
+ log(LL_CHD, "%05d %s reserved: incoming call from %s to %s",
+ mp->header.cdid, cep->name, SRC, DST);
+ sendm_connect_resp(cep, mp->header.cdid, SETUP_RESP_REJECT,
+ (CAUSET_I4B << 8) | CAUSE_I4B_NORMAL);
+ /* no state change */
+ }
+ else
+ {
+ log(LL_CHD, "%05d %s callback: incoming call from %s to %s",
+ mp->header.cdid, cep->name, SRC, DST);
+ sendm_connect_resp(cep, mp->header.cdid, SETUP_RESP_REJECT,
+ (CAUSET_I4B << 8) | CAUSE_I4B_NORMAL);
+ cep->last_release_time = time(NULL);
+ cep->cdid = CDID_RESERVED;
+ next_state(cep, EV_CBRQ);
+ }
+ break;
+
+ default:
+ log(LL_WRN, "msg_connect_ind: unknown response type, tx SETUP_RESP_DNTCRE");
+ sendm_connect_resp(NULL, mp->header.cdid, SETUP_RESP_DNTCRE, 0);
+ break;
+ }
+#undef SRC
+#undef DST
+}
+
+/*---------------------------------------------------------------------------*
+ * handle incoming CONNECT_ACTIVE_IND message
+ *---------------------------------------------------------------------------*/
+void
+msg_connect_active_ind(msg_connect_active_ind_t *mp)
+{
+ cfg_entry_t *cep;
+
+ if((cep = get_cep_by_cdid(mp->header.cdid)) == NULL)
+ {
+ log(LL_WRN, "msg_connect_active_ind: cdid not found!");
+ return;
+ }
+
+ cep->isdncontrollerused = mp->controller;
+ cep->isdnchannelused = mp->channel;
+
+ cep->aoc_now = cep->connect_time = time(NULL);
+ cep->aoc_last = 0;
+ cep->aoc_diff = 0;
+ cep->aoc_valid = AOC_INVALID;
+
+ cep->local_disconnect = DISCON_REM;
+
+ cep->inbytes = INVALID;
+ cep->outbytes = INVALID;
+ cep->hangup = 0;
+
+ /* set the B-channel to active */
+
+ if((set_channel_busy(cep->isdncontrollerused, cep->isdnchannelused)) == ERROR)
+ log(LL_ERR, "msg_connect_active_ind: set_channel_busy failed!");
+
+ if(cep->direction == DIR_OUT)
+ {
+ log(LL_CHD, "%05d %s outgoing call active (ctl %d, ch %d)",
+ cep->cdid, cep->name,
+ cep->isdncontrollerused, cep->isdnchannelused);
+ }
+ else
+ {
+ log(LL_CHD, "%05d %s incoming call active (ctl %d, ch %d)",
+ cep->cdid, cep->name,
+ cep->isdncontrollerused, cep->isdnchannelused);
+ }
+
+#ifdef USE_CURSES
+ if(do_fullscreen)
+ display_connect(cep);
+#endif
+#ifdef I4B_EXTERNAL_MONITOR
+ if(do_monitor && accepted)
+ monitor_evnt_connect(cep);
+#endif
+
+ if(isdntime && (mp->datetime[0] != '\0'))
+ {
+ log(LL_DMN, "date/time from exchange = %s", mp->datetime);
+ }
+
+ next_state(cep, EV_MCAI);
+}
+
+/*---------------------------------------------------------------------------*
+ * handle incoming PROCEEDING_IND message
+ *---------------------------------------------------------------------------*/
+void
+msg_proceeding_ind(msg_proceeding_ind_t *mp)
+{
+ cfg_entry_t *cep;
+
+ if((cep = get_cep_by_cdid(mp->header.cdid)) == NULL)
+ {
+ log(LL_WRN, "msg_proceeding_ind: cdid not found!");
+ return;
+ }
+
+ cep->isdncontrollerused = mp->controller;
+ cep->isdnchannelused = mp->channel;
+
+ /* set the B-channels active */
+
+ if((set_channel_busy(cep->isdncontrollerused, cep->isdnchannelused)) == ERROR)
+ log(LL_ERR, "msg_proceeding_ind: set_channel_busy failed!");
+
+ log(LL_CHD, "%05d %s outgoing call proceeding (ctl %d, ch %d)",
+ cep->cdid, cep->name,
+ cep->isdncontrollerused, cep->isdnchannelused);
+}
+
+/*---------------------------------------------------------------------------*
+ * handle incoming ALERT_IND message
+ *---------------------------------------------------------------------------*/
+void
+msg_alert_ind(msg_alert_ind_t *mp)
+{
+ cfg_entry_t *cep;
+
+ if((cep = get_cep_by_cdid(mp->header.cdid)) == NULL)
+ {
+ log(LL_WRN, "msg_alert_ind: cdid not found!");
+ return;
+ }
+#ifdef NOTDEF
+ log(LL_CHD, "%05d %s incoming alert", cep->cdid, cep->name);
+#endif
+}
+
+/*---------------------------------------------------------------------------*
+ * handle incoming L12STAT_IND message
+ *---------------------------------------------------------------------------*/
+void
+msg_l12stat_ind(msg_l12stat_ind_t *ml)
+{
+#ifdef USE_CURSES
+ if(do_fullscreen)
+ display_l12stat(ml->controller, ml->layer, ml->state);
+#endif
+
+ DBGL(DL_CNST, (log(LL_DBG, "msg_l12stat_ind: unit %d, layer %d, state %d",
+ ml->controller, ml->layer, ml->state)));
+}
+
+/*---------------------------------------------------------------------------*
+ * handle incoming TEIASG_IND message
+ *---------------------------------------------------------------------------*/
+void
+msg_teiasg_ind(msg_teiasg_ind_t *mt)
+{
+#ifdef USE_CURSES
+ if(do_fullscreen)
+ display_tei(mt->controller, mt->tei);
+#endif
+
+ DBGL(DL_CNST, (log(LL_DBG, "msg_teiasg_ind: unit %d, tei = %d",
+ mt->controller, mt->tei)));
+}
+
+/*---------------------------------------------------------------------------*
+ * handle incoming L12STAT_IND message
+ *---------------------------------------------------------------------------*/
+void
+msg_pdeact_ind(msg_pdeact_ind_t *md)
+{
+ int i;
+ int ctrl = md->controller;
+ cfg_entry_t *cep;
+
+#ifdef USE_CURSES
+ if(do_fullscreen)
+ {
+ display_l12stat(ctrl, LAYER_ONE, LAYER_IDLE);
+ display_l12stat(ctrl, LAYER_TWO, LAYER_IDLE);
+ display_tei(ctrl, -1);
+ }
+#endif
+
+ DBGL(DL_CNST, (log(LL_DBG, "msg_pdeact_ind: unit %d, persistent deactivation", ctrl)));
+
+ for(i=0; i < nentries; i++)
+ {
+ if((cfg_entry_tab[i].cdid != CDID_UNUSED) &&
+ (cfg_entry_tab[i].isdncontrollerused == ctrl))
+ {
+ cep = &cfg_entry_tab[i];
+
+ if(cep->cdid == CDID_RESERVED)
+ {
+ cep->cdid = CDID_UNUSED;
+ continue;
+ }
+
+ cep->cdid = CDID_UNUSED;
+
+ cep->last_release_time = time(NULL);
+
+ SET_CAUSE_TYPE(cep->disc_cause, CAUSET_I4B);
+ SET_CAUSE_VAL(cep->disc_cause, CAUSE_I4B_L1ERROR);
+
+ if(cep->direction == DIR_OUT)
+ {
+ log(LL_CHD, "%05d %s outgoing call disconnected (local)",
+ cep->cdid, cep->name);
+ }
+ else
+ {
+ log(LL_CHD, "%05d %s incoming call disconnected (local)",
+ cep->cdid, cep->name);
+ }
+
+ log(LL_CHD, "%05d %s cause %s",
+ cep->cdid, cep->name, print_i4b_cause(cep->disc_cause));
+
+#ifdef USE_CURSES
+ if(do_fullscreen && (cep->connect_time > 0))
+ display_disconnect(cep);
+#endif
+
+#ifdef I4B_EXTERNAL_MONITOR
+ if(do_monitor && accepted)
+ monitor_evnt_disconnect(cep);
+#endif
+ if(cep->disconnectprog)
+ exec_connect_prog(cep, cep->disconnectprog, 1);
+
+ if(cep->connect_time > 0)
+ {
+ if(cep->direction == DIR_OUT)
+ {
+ log(LL_CHD, "%05d %s charging: %d units, %d seconds",
+ cep->cdid, cep->name, cep->charge,
+ (int)difftime(time(NULL), cep->connect_time));
+ }
+ else
+ {
+ log(LL_CHD, "%05d %s connected %d seconds",
+ cep->cdid, cep->name,
+ (int)difftime(time(NULL), cep->connect_time));
+ }
+
+ if((cep->inbytes != INVALID) && (cep->outbytes != INVALID))
+ {
+ if((cep->ioutbytes != cep->outbytes) ||
+ (cep->iinbytes != cep->inbytes))
+ {
+ log(LL_CHD, "%05d %s accounting: in %d, out %d (in %d, out %d)",
+ cep->cdid, cep->name,
+ cep->inbytes, cep->outbytes,
+ cep->iinbytes, cep->ioutbytes);
+ }
+ else
+ {
+ log(LL_CHD, "%05d %s accounting: in %d, out %d",
+ cep->cdid, cep->name,
+ cep->inbytes, cep->outbytes);
+ }
+ }
+ }
+
+ if(useacctfile && (cep->connect_time > 0))
+ {
+ int con_secs;
+ char logdatetime[41];
+ struct tm *tp;
+
+ con_secs = difftime(time(NULL), cep->connect_time);
+
+ tp = localtime(&cep->connect_time);
+
+ strftime(logdatetime,40,I4B_TIME_FORMAT,tp);
+
+ if(cep->inbytes != INVALID && cep->outbytes != INVALID)
+ {
+ fprintf(acctfp, "%s - %s %s %d (%d) (%d/%d)\n",
+ logdatetime, getlogdatetime(),
+ cep->name, cep->charge, con_secs,
+ cep->inbytes, cep->outbytes);
+ }
+ else
+ {
+ fprintf(acctfp, "%s - %s %s %d (%d)\n",
+ logdatetime, getlogdatetime(),
+ cep->name, cep->charge, con_secs);
+ }
+ }
+
+ /* set the B-channel inactive */
+
+ if((set_channel_idle(cep->isdncontrollerused, cep->isdnchannelused)) == ERROR)
+ log(LL_ERR, "msg_pdeact_ind: set_channel_idle failed!");
+
+ incr_free_channels(cep->isdncontrollerused);
+
+ cep->connect_time = 0;
+ }
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * handle incoming NEGCOMP_IND message
+ *---------------------------------------------------------------------------*/
+void
+msg_negcomplete_ind(msg_negcomplete_ind_t *mp)
+{
+ cfg_entry_t *cep;
+
+ if((cep = get_cep_by_cdid(mp->header.cdid)) == NULL)
+ {
+ log(LL_WRN, "msg_negcomp_ind: cdid not found");
+ return;
+ }
+
+ if(cep->connectprog)
+ exec_connect_prog(cep, cep->connectprog, 0);
+}
+
+/*---------------------------------------------------------------------------*
+ * handle incoming IFSTATE_CHANGED indication
+ *---------------------------------------------------------------------------*/
+void
+msg_ifstatechg_ind(msg_ifstatechg_ind_t *mp)
+{
+ cfg_entry_t *cep;
+ char *device;
+
+ if((cep = get_cep_by_cdid(mp->header.cdid)) == NULL)
+ {
+ log(LL_WRN, "msg_negcomp_ind: cdid not found");
+ return;
+ }
+
+ device = bdrivername(cep->usrdevicename);
+ log(LL_DBG, "%s%d: switched to state %d\n", device, cep->usrdeviceunit, mp->state);
+}
+
+/*---------------------------------------------------------------------------*
+ * handle incoming DISCONNECT_IND message
+ *---------------------------------------------------------------------------*/
+void
+msg_disconnect_ind(msg_disconnect_ind_t *mp)
+{
+ cfg_entry_t *cep;
+
+ if((cep = get_cep_by_cdid(mp->header.cdid)) == NULL)
+ {
+ log(LL_WRN, "msg_disconnect_ind: cdid not found");
+ return;
+ }
+
+ /* is this an aborted out-call prematurely called back? */
+ if (cep->saved_call.cdid == mp->header.cdid)
+ {
+ DBGL(DL_CNST, (log(LL_DBG, "aborted outcall %05d disconnected",
+ mp->header.cdid)));
+ cep->saved_call.cdid = CDID_UNUSED;
+
+ if((set_channel_idle(cep->saved_call.controller, cep->saved_call.channel)) == ERROR)
+ log(LL_ERR, "msg_disconnect_ind: set_channel_idle failed!");
+
+ incr_free_channels(cep->saved_call.controller);
+ return;
+ }
+
+ cep->last_release_time = time(NULL);
+ cep->disc_cause = mp->cause;
+
+ if(cep->direction == DIR_OUT)
+ {
+ log(LL_CHD, "%05d %s outgoing call disconnected %s",
+ cep->cdid, cep->name,
+ cep->local_disconnect == DISCON_LOC ?
+ "(local)" : "(remote)");
+ }
+ else
+ {
+ log(LL_CHD, "%05d %s incoming call disconnected %s",
+ cep->cdid, cep->name,
+ cep->local_disconnect == DISCON_LOC ?
+ "(local)" : "(remote)");
+ }
+
+ log(LL_CHD, "%05d %s cause %s",
+ cep->cdid, cep->name, print_i4b_cause(mp->cause));
+
+#ifdef USE_CURSES
+ if(do_fullscreen && (cep->connect_time > 0))
+ display_disconnect(cep);
+#endif
+
+#ifdef I4B_EXTERNAL_MONITOR
+ if(do_monitor && accepted)
+ monitor_evnt_disconnect(cep);
+#endif
+
+ if(cep->disconnectprog)
+ exec_connect_prog(cep, cep->disconnectprog, 1);
+
+ if(cep->connect_time > 0)
+ {
+ if(cep->direction == DIR_OUT)
+ {
+ log(LL_CHD, "%05d %s charging: %d units, %d seconds",
+ cep->cdid, cep->name, cep->charge,
+ (int)difftime(time(NULL), cep->connect_time));
+ }
+ else
+ {
+ log(LL_CHD, "%05d %s connected %d seconds",
+ cep->cdid, cep->name,
+ (int)difftime(time(NULL), cep->connect_time));
+ }
+
+ if((cep->inbytes != INVALID) && (cep->outbytes != INVALID))
+ {
+ if((cep->ioutbytes != cep->outbytes) ||
+ (cep->iinbytes != cep->inbytes))
+ {
+ log(LL_CHD, "%05d %s accounting: in %d, out %d (in %d, out %d)",
+ cep->cdid, cep->name,
+ cep->inbytes, cep->outbytes,
+ cep->iinbytes, cep->ioutbytes);
+ }
+ else
+ {
+ log(LL_CHD, "%05d %s accounting: in %d, out %d",
+ cep->cdid, cep->name,
+ cep->inbytes, cep->outbytes);
+ }
+ }
+ }
+
+ if(useacctfile && (cep->connect_time > 0))
+ {
+ int con_secs;
+ char logdatetime[41];
+ struct tm *tp;
+
+ con_secs = difftime(time(NULL), cep->connect_time);
+
+ tp = localtime(&cep->connect_time);
+
+ strftime(logdatetime,40,I4B_TIME_FORMAT,tp);
+
+ if(cep->inbytes != INVALID && cep->outbytes != INVALID)
+ {
+ fprintf(acctfp, "%s - %s %s %d (%d) (%d/%d)\n",
+ logdatetime, getlogdatetime(),
+ cep->name, cep->charge, con_secs,
+ cep->inbytes, cep->outbytes);
+ }
+ else
+ {
+ fprintf(acctfp, "%s - %s %s %d (%d)\n",
+ logdatetime, getlogdatetime(),
+ cep->name, cep->charge, con_secs);
+ }
+ }
+
+ /* set the B-channel inactive */
+
+ if((set_channel_idle(cep->isdncontrollerused, cep->isdnchannelused)) == ERROR)
+ log(LL_ERR, "msg_disconnect_ind: set_channel_idle failed!");
+
+ incr_free_channels(cep->isdncontrollerused);
+
+ cep->connect_time = 0;
+
+ next_state(cep, EV_MDI);
+}
+
+/*---------------------------------------------------------------------------*
+ * handle incoming DIALOUT message
+ *---------------------------------------------------------------------------*/
+void
+msg_dialout(msg_dialout_ind_t *mp)
+{
+ cfg_entry_t *cep;
+
+ DBGL(DL_DRVR, (log(LL_DBG, "msg_dialout: dial req from %s, unit %d", bdrivername(mp->driver), mp->driver_unit)));
+
+ if((cep = find_by_device_for_dialout(mp->driver, mp->driver_unit)) == NULL)
+ {
+ DBGL(DL_DRVR, (log(LL_DBG, "msg_dialout: config entry reserved or no match")));
+ return;
+ }
+
+ if(cep->inout == DIR_INONLY)
+ {
+ dialresponse(cep, DSTAT_INONLY);
+ return;
+ }
+
+ if((cep->cdid = get_cdid()) == 0)
+ {
+ DBGL(DL_DRVR, (log(LL_DBG, "msg_dialout: get_cdid() returned 0!")));
+ return;
+ }
+
+ cep->charge = 0;
+ cep->last_charge = 0;
+
+ next_state(cep, EV_MDO);
+}
+
+/*---------------------------------------------------------------------------*
+ * handle incoming DRVRDISC_REQ message
+ *---------------------------------------------------------------------------*/
+void
+msg_drvrdisc_req(msg_drvrdisc_req_t *mp)
+{
+ cfg_entry_t *cep;
+
+ DBGL(DL_DRVR, (log(LL_DBG, "msg_drvrdisc_req: req from %s, unit %d", bdrivername(mp->driver), mp->driver_unit)));
+
+ if((cep = get_cep_by_driver(mp->driver, mp->driver_unit)) == NULL)
+ {
+ DBGL(DL_DRVR, (log(LL_DBG, "msg_drvrdisc_req: config entry not found")));
+ return;
+ }
+ next_state(cep, EV_DRQ);
+}
+
+/*---------------------------------------------------------------------------*
+ * handle incoming ACCOUNTING message
+ *---------------------------------------------------------------------------*/
+void
+msg_accounting(msg_accounting_ind_t *mp)
+{
+ cfg_entry_t *cep;
+
+ if((cep = find_active_entry_by_driver(mp->driver, mp->driver_unit)) == NULL)
+ {
+ log(LL_WRN, "msg_accounting: no config entry found!");
+ return;
+ }
+
+ cep->inbytes = mp->inbytes;
+ cep->iinbytes = mp->iinbytes;
+ cep->outbytes = mp->outbytes;
+ cep->ioutbytes = mp->ioutbytes;
+ cep->inbps = mp->inbps;
+ cep->outbps = mp->outbps;
+
+ if(mp->accttype == ACCT_DURING)
+ {
+#ifdef USE_CURSES
+ if(do_fullscreen)
+ display_acct(cep);
+#endif
+#ifdef NOTDEF
+ else
+ DBGL(DL_DRVR, (log(LL_DBG, "msg_accounting: %s%d, ioutb=%d, iinb=%d, outb=%d, inb=%d, outbps=%d, inbps=%d",
+ bdrivername(mp->driver), mp->driver_unit,
+ mp->ioutbytes, mp->iinbytes,
+ mp->outbytes, mp->inbytes,
+ mp->outbps, mp->inbps)));
+#endif
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * handle incoming CHARGING message
+ *---------------------------------------------------------------------------*/
+void
+msg_charging_ind(msg_charging_ind_t *mp)
+{
+ static char *cttab[] = {
+ "invalid",
+ "AOCD",
+ "AOCE",
+ "estimated" };
+
+ cfg_entry_t *cep;
+
+ if((cep = get_cep_by_cdid(mp->header.cdid)) == NULL)
+ {
+ log(LL_WRN, "msg_charging_ind: cdid not found");
+ return;
+ }
+
+ if(mp->units_type < CHARGE_INVALID || mp->units_type > CHARGE_CALC)
+ {
+ log(LL_ERR, "msg_charging: units_type %d out of range!", mp->units_type);
+ do_exit(1);
+ }
+
+ DBGL(DL_DRVR, (log(LL_DBG, "msg_charging: %d unit(s) (%s)",
+ mp->units, cttab[mp->units_type])));
+
+ switch(mp->units_type)
+ {
+ case CHARGE_AOCD:
+ cep->charge = mp->units;
+
+ if((cep->unitlengthsrc == ULSRC_DYN) &&
+ (cep->charge != cep->last_charge))
+ {
+ cep->last_charge = cep->charge;
+ handle_charge(cep);
+ }
+ break;
+
+ case CHARGE_AOCE:
+ cep->charge = mp->units;
+ break;
+
+ case CHARGE_CALC:
+ cep->charge = mp->units;
+#ifdef USE_CURSES
+ if(do_fullscreen)
+ display_ccharge(cep, mp->units);
+#endif
+#ifdef I4B_EXTERNAL_MONITOR
+ if(do_monitor && accepted)
+ monitor_evnt_charge(cep, mp->units, 1);
+#endif
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * handle incoming IDLE_TIMEOUT_IND message
+ *---------------------------------------------------------------------------*/
+void
+msg_idle_timeout_ind(msg_idle_timeout_ind_t *mp)
+{
+ cfg_entry_t *cep;
+
+ if((cep = get_cep_by_cdid(mp->header.cdid)) == NULL)
+ {
+ log(LL_WRN, "msg_idle_timeout_ind: cdid not found!");
+ return;
+ }
+
+ cep->local_disconnect = DISCON_LOC;
+
+ DBGL(DL_DRVR, (log(LL_DBG, "msg_idle_timeout_ind: idletimeout, kernel sent disconnect!")));
+
+ check_and_kill(cep);
+}
+
+/*---------------------------------------------------------------------------*
+ * get a cdid from kernel
+ *---------------------------------------------------------------------------*/
+int
+get_cdid(void)
+{
+ msg_cdid_req_t mcr;
+
+ mcr.cdid = 0;
+
+ if((ioctl(isdnfd, I4B_CDID_REQ, &mcr)) < 0)
+ {
+ log(LL_ERR, "get_cdid: ioctl I4B_CDID_REQ failed: %s", strerror(errno));
+ do_exit(1);
+ }
+
+ return(mcr.cdid);
+}
+
+/*---------------------------------------------------------------------------*
+ * send message "connect request" to kernel
+ *---------------------------------------------------------------------------*/
+int
+sendm_connect_req(cfg_entry_t *cep)
+{
+ msg_connect_req_t mcr;
+ int ret;
+
+ cep->local_disconnect = DISCON_REM;
+
+ cep->unitlength = get_current_rate(cep, 1);
+
+ mcr.cdid = cep->cdid;
+
+ mcr.controller = cep->isdncontrollerused;
+ mcr.channel = cep->isdnchannelused;
+ mcr.txdelay = cep->isdntxdelout;
+
+ mcr.bprot = cep->b1protocol;
+
+ mcr.driver = cep->usrdevicename;
+ mcr.driver_unit = cep->usrdeviceunit;
+
+ mcr.unitlen_time = cep->unitlength;
+ mcr.idle_time = cep->idle_time_out;
+ mcr.earlyhup_time = cep->earlyhangup;
+
+ if(cep->unitlengthsrc == ULSRC_DYN)
+ mcr.unitlen_method = ULEN_METHOD_DYNAMIC;
+ else
+ mcr.unitlen_method = ULEN_METHOD_STATIC;
+
+ strcpy(mcr.dst_telno, cep->remote_phone_dialout);
+ strcpy(mcr.src_telno, cep->local_phone_dialout);
+
+ cep->last_dial_time = time(NULL);
+ cep->direction = DIR_OUT;
+
+ DBGL(DL_CNST, (log(LL_DBG, "sendm_connect_req: ctrl = %d, chan = %d", cep->isdncontrollerused, cep->isdnchannelused)));
+
+ if((ret = ioctl(isdnfd, I4B_CONNECT_REQ, &mcr)) < 0)
+ {
+ log(LL_ERR, "sendm_connect_req: ioctl I4B_CONNECT_REQ failed: %s", strerror(errno));
+ do_exit(1);
+ }
+
+ decr_free_channels(cep->isdncontrollerused);
+
+ log(LL_CHD, "%05d %s dialing out from %s to %s",
+ cep->cdid,
+ cep->name,
+ aliasing ? get_alias(cep->local_phone_dialout) : cep->local_phone_dialout,
+ aliasing ? get_alias(cep->remote_phone_dialout) : cep->remote_phone_dialout);
+
+ return(ret);
+}
+
+/*---------------------------------------------------------------------------*
+ * send message "connect response" to kernel
+ *---------------------------------------------------------------------------*/
+int
+sendm_connect_resp(cfg_entry_t *cep, int cdid, int response, int cause)
+{
+ msg_connect_resp_t mcr;
+ int ret;
+
+ mcr.cdid = cdid;
+
+ mcr.response = response;
+
+ if(response == SETUP_RESP_REJECT)
+ {
+ mcr.cause = cause;
+ }
+ else if(response == SETUP_RESP_ACCEPT)
+ {
+ cep->direction = DIR_IN;
+
+ mcr.txdelay = cep->isdntxdelin;
+
+ mcr.bprot = cep->b1protocol;
+
+ mcr.driver = cep->usrdevicename;
+ mcr.driver_unit = cep->usrdeviceunit;
+
+ mcr.max_idle_time = cep->idle_time_in;
+ }
+
+ if((ret = ioctl(isdnfd, I4B_CONNECT_RESP, &mcr)) < 0)
+ {
+ log(LL_ERR, "sendm_connect_resp: ioctl I4B_CONNECT_RESP failed: %s", strerror(errno));
+ do_exit(1);
+ }
+
+ DBGL(DL_DRVR, (log(LL_DBG, "sendm_connect_resp: sent CONNECT_RESP")));
+
+ return(ret);
+}
+
+/*---------------------------------------------------------------------------*
+ * send message "disconnect request" to kernel
+ *---------------------------------------------------------------------------*/
+int
+sendm_disconnect_req(cfg_entry_t *cep, int cause)
+{
+ msg_discon_req_t mcr;
+ int ret;
+
+ mcr.cdid = cep->cdid;
+
+ mcr.cause = cause;
+
+ cep->local_disconnect = DISCON_LOC;
+
+ if((ret = ioctl(isdnfd, I4B_DISCONNECT_REQ, &mcr)) < 0)
+ {
+ log(LL_ERR, "sendm_disconnect_req: ioctl I4B_DISCONNECT_REQ failed: %s", strerror(errno));
+ do_exit(1);
+ }
+ else
+ {
+ DBGL(DL_DRVR, (log(LL_DBG, "sendm_disconnect_req: sent DISCONNECT_REQ")));
+ }
+ return(ret);
+}
+
+/*---------------------------------------------------------------------------*
+ * send message "alert request" to kernel
+ *---------------------------------------------------------------------------*/
+int
+sendm_alert_req(cfg_entry_t *cep)
+{
+ msg_alert_req_t mar;
+ int ret;
+
+ mar.cdid = cep->cdid;
+
+ if((ret = ioctl(isdnfd, I4B_ALERT_REQ, &mar)) < 0)
+ {
+ log(LL_ERR, "sendm_alert_req: ioctl I4B_ALERT_REQ failed: %s", strerror(errno));
+ do_exit(1);
+ }
+ else
+ {
+ DBGL(DL_DRVR, (log(LL_DBG, "sendm_alert_req: sent ALERT_REQ")));
+ }
+ return(ret);
+}
+
+/* EOF */
diff --git a/usr.sbin/i4b/isdnd/pathnames.h b/usr.sbin/i4b/isdnd/pathnames.h
new file mode 100644
index 0000000..75afec9
--- /dev/null
+++ b/usr.sbin/i4b/isdnd/pathnames.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * i4b daemon - location of files
+ * ------------------------------
+ *
+ * $Id: pathnames.h,v 1.5 1998/12/05 18:03:30 hm Exp $
+ *
+ * last edit-date: [Sat Dec 5 18:11:17 1998]
+ *
+ *---------------------------------------------------------------------------*/
+
+#ifndef _PATHNAMES_H_
+#define _PATHNAMES_H_
+
+#define I4BDEVICE "/dev/i4b"
+
+#define ETCPATH "/etc/isdn"
+#define CONFIG_FILE_DEF "/etc/isdn/isdnd.rc"
+#define RATES_FILE_DEF "/etc/isdn/isdnd.rates"
+
+#define LIBDIR "/usr/local/lib/isdn"
+
+#define LOG_FILE_DEF "/var/log/isdnd.log"
+#define ACCT_FILE_DEF "/var/log/isdnd.acct"
+
+#define PIDFILE "/var/run/isdnd.pid"
+
+#endif /* _PATHNAMES_H_ */
+
+/* EOF */
diff --git a/usr.sbin/i4b/isdnd/pcause.c b/usr.sbin/i4b/isdnd/pcause.c
new file mode 100644
index 0000000..c782f2c
--- /dev/null
+++ b/usr.sbin/i4b/isdnd/pcause.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * printing cause values
+ * ---------------------
+ *
+ * $Id: pcause.c,v 1.9 1998/12/05 18:03:31 hm Exp $
+ *
+ * last edit-date: [Sat Dec 5 18:11:31 1998]
+ *
+ *---------------------------------------------------------------------------*/
+
+#include "isdnd.h"
+
+static char *cause_i4b_tab[CAUSE_I4B_MAX+1];
+static char *cause_q850_tab[CAUSE_Q850_MAX];
+
+char *
+print_i4b_cause(cause_t code)
+{
+ static char error_message[128];
+
+ sprintf(error_message, "%d: ", GET_CAUSE_VAL(code));
+
+ switch(GET_CAUSE_TYPE(code))
+ {
+ case CAUSET_Q850:
+ strcat(error_message, cause_q850_tab[GET_CAUSE_VAL(code)]);
+ strcat(error_message, " (Q.850)");
+ break;
+
+ case CAUSET_I4B:
+ if((GET_CAUSE_VAL(code) < CAUSE_I4B_NORMAL) ||
+ (GET_CAUSE_VAL(code) >= CAUSE_I4B_MAX))
+ {
+ SET_CAUSE_VAL(code, CAUSE_I4B_MAX);
+ }
+ strcat(error_message, cause_i4b_tab[GET_CAUSE_VAL(code)]);
+ strcat(error_message, " (I4B)");
+ break;
+
+ default:
+ strcat(error_message, "ERROR: unknown cause type!");
+ break;
+ }
+ return(error_message);
+}
+
+static char *cause_i4b_tab[CAUSE_I4B_MAX+1] = {
+ "normal call clearing",
+ "user busy",
+ "channel not available",
+ "incompatible source or destination",
+ "call rejected",
+ "destination out of order",
+ "temporary failure",
+ "layer 1 error / persistent deactivation",
+ "ERROR, invalid I4B cause value!"
+};
+
+static char *cause_q850_tab[CAUSE_Q850_MAX] = {
+ "Normal D-channel shutdown",
+ "Unallocated (unassigned) number",
+ "No route to specified transit network (national use)",
+ "No route to destination",
+ "Send special information tone",
+ "Misdialled trunk prefix (national use)",
+ "Channel unacceptable",
+ "Call awarded and being delivered in an established channel",
+ "Preemption",
+ "Preemption - circuit reserved for reuse",
+
+/*10*/ "cause code 10: error, unassigned in Q.850 (03/93)",
+ "cause code 11: error, unassigned in Q.850 (03/93)",
+ "cause code 12: error, unassigned in Q.850 (03/93)",
+ "cause code 13: error, unassigned in Q.850 (03/93)",
+ "cause code 14: error, unassigned in Q.850 (03/93)",
+ "cause code 15: error, unassigned in Q.850 (03/93)",
+ "Normal call clearing",
+ "User busy",
+ "No user responding",
+ "No answer from user (user alerted)",
+
+/*20*/ "Subscriber absent",
+ "Call rejected",
+ "Number changed",
+ "cause code 23: error, unassigned in Q.850 (03/93)",
+ "cause code 24: error, unassigned in Q.850 (03/93)",
+ "cause code 25: error, unassigned in Q.850 (03/93)",
+ "Non-selected user clearing",
+ "Destination out of order",
+ "Invalid number format",
+ "Facility rejected",
+
+/*30*/ "Response to STATUS ENQUIRY",
+ "Normal, unspecified",
+ "cause code 32: error, unassigned in Q.850 (03/93)",
+ "cause code 33: error, unassigned in Q.850 (03/93)",
+ "No circuit / channel available",
+ "cause code 35: error, unassigned in Q.850 (03/93)",
+ "cause code 36: error, unassigned in Q.850 (03/93)",
+ "cause code 37: error, unassigned in Q.850 (03/93)",
+ "Network out of order",
+ "Permanent frame mode connection out of service",
+
+/*40*/ "Permanent frame mode connection operational",
+ "Temporary failure",
+ "Switching equipment congestion",
+ "Access information discarded",
+ "Requested circuit/channel not available",
+ "cause code 45: error, unassigned in Q.850 (03/93)",
+ "Precedence call blocked",
+ "Resources unavailable, unspecified",
+ "cause code 48: error, unassigned in Q.850 (03/93)",
+ "Quality of service unavailable",
+
+/*50*/ "Requested facility not subscribed",
+ "cause code 51: error, unassigned in Q.850 (03/93)",
+ "cause code 52: error, unassigned in Q.850 (03/93)",
+ "Outgoing calls barred within CUG",
+ "cause code 54: error, unassigned in Q.850 (03/93)",
+ "Incoming calls barred within CUG",
+ "cause code 56: error, unassigned in Q.850 (03/93)",
+ "Bearer capability not authorized",
+ "Bearer capability not presently available",
+ "cause code 59: error, unassigned in Q.850 (03/93)",
+
+/*60*/ "cause code 60: error, unassigned in Q.850 (03/93)",
+ "cause code 61: error, unassigned in Q.850 (03/93)",
+ "Inconsistenciy in designated outg. access info and subscriber class",
+ "Service or option not available, unspecified",
+ "cause code 64: error, unassigned in Q.850 (03/93)",
+ "Bearer capability not implemented",
+ "Channel type not implemented",
+ "cause code 67: error, unassigned in Q.850 (03/93)",
+ "cause code 68: error, unassigned in Q.850 (03/93)",
+ "Requested facility not implemented",
+
+/*70*/ "Only restricted digital information bearer capability is available",
+ "cause code 71: error, unassigned in Q.850 (03/93)",
+ "cause code 72: error, unassigned in Q.850 (03/93)",
+ "cause code 73: error, unassigned in Q.850 (03/93)",
+ "cause code 74: error, unassigned in Q.850 (03/93)",
+ "cause code 75: error, unassigned in Q.850 (03/93)",
+ "cause code 76: error, unassigned in Q.850 (03/93)",
+ "cause code 77: error, unassigned in Q.850 (03/93)",
+ "cause code 78: error, unassigned in Q.850 (03/93)",
+ "Service or option not implemented, unspecified",
+
+/*80*/ "cause code 80: error, unassigned in Q.850 (03/93)",
+ "Invalid call reference value",
+ "Identified channel does not exist",
+ "A suspended call exists, but this call identity does not",
+ "Call identity in use",
+ "No call suspended",
+ "Call having the requested call identity has been cleared",
+ "User not member of CUG",
+ "Incompatible destination",
+ "cause code 89: error, unassigned in Q.850 (03/93)",
+
+/*90*/ "Non-existent CUG",
+ "Invalid transit network selection",
+ "cause code 92: error, unassigned in Q.850 (03/93)",
+ "cause code 93: error, unassigned in Q.850 (03/93)",
+ "cause code 94: error, unassigned in Q.850 (03/93)",
+ "Invalid message, unspecified",
+ "Mandatory information element is missing",
+ "Message type non-existent or not implemented",
+ "Message not compatible with call state or message type non-existent or not implemented",
+ "Information element/parameter non-existent or not implemented",
+
+/*100*/ "Invalid information element contents",
+ "Message not compatible with call state",
+ "Recovery on timer expiry",
+ "Parameter non-existent or not implemented, passed on",
+ "cause code 104: error, unassigned in Q.850 (03/93)",
+ "cause code 105: error, unassigned in Q.850 (03/93)",
+ "cause code 106: error, unassigned in Q.850 (03/93)",
+ "cause code 107: error, unassigned in Q.850 (03/93)",
+ "cause code 108: error, unassigned in Q.850 (03/93)",
+ "cause code 109: error, unassigned in Q.850 (03/93)",
+
+/*110*/ "Message with unrecognized parameter, discarded",
+ "Protocol error, unspecified",
+ "cause code 112: error, unassigned in Q.850 (03/93)",
+ "cause code 113: error, unassigned in Q.850 (03/93)",
+ "cause code 114: error, unassigned in Q.850 (03/93)",
+ "cause code 115: error, unassigned in Q.850 (03/93)",
+ "cause code 116: error, unassigned in Q.850 (03/93)",
+ "cause code 117: error, unassigned in Q.850 (03/93)",
+ "cause code 118: error, unassigned in Q.850 (03/93)",
+ "cause code 119: error, unassigned in Q.850 (03/93)",
+
+/*120*/ "cause code 120: error, unassigned in Q.850 (03/93)",
+ "cause code 121: error, unassigned in Q.850 (03/93)",
+ "cause code 122: error, unassigned in Q.850 (03/93)",
+ "cause code 123: error, unassigned in Q.850 (03/93)",
+ "cause code 124: error, unassigned in Q.850 (03/93)",
+ "cause code 125: error, unassigned in Q.850 (03/93)",
+ "cause code 126: error, unassigned in Q.850 (03/93)",
+ "Interworking, unspecified"
+};
+
+/* EOF */
diff --git a/usr.sbin/i4b/isdnd/process.c b/usr.sbin/i4b/isdnd/process.c
new file mode 100644
index 0000000..47c9eda
--- /dev/null
+++ b/usr.sbin/i4b/isdnd/process.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * i4b daemon - process handling routines
+ * --------------------------------------
+ *
+ * $Id: process.c,v 1.6 1998/12/05 18:03:33 hm Exp $
+ *
+ * last edit-date: [Sat Dec 5 18:11:42 1998]
+ *
+ * -hm debugging processhandling
+ *
+ *---------------------------------------------------------------------------*/
+
+#include "isdnd.h"
+
+/*---------------------------------------------------------------------------*
+ * check if another instance of us is already running
+ *---------------------------------------------------------------------------*/
+void
+check_pid(void)
+{
+ FILE *fp;
+
+ /* check if another lock-file already exists */
+
+ if((fp = fopen(PIDFILE, "r")) != NULL)
+ {
+ /* lockfile found, check */
+
+ int oldpid;
+
+ /* read pid from file */
+
+ if((fscanf(fp, "%d", &oldpid)) != 1)
+ {
+ log(LL_ERR, "ERROR, reading pid from lockfile failed, terminating!");
+ exit(1);
+ }
+
+ /* check if process got from file is still alive */
+
+ if((kill(oldpid, 0)) != 0)
+ {
+ /* process does not exist */
+
+ /* close file */
+
+ fclose(fp);
+
+ DBGL(DL_PROC, (log(LL_DBG, "removing old lock-file %s", PIDFILE)));
+
+ /* remove file */
+
+ unlink(PIDFILE);
+ }
+ else
+ {
+ /* process is still alive */
+
+ log(LL_ERR, "ERROR, another daemon is already running, pid = %d, terminating!", oldpid);
+ exit(1);
+ }
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * establish and init process lock file
+ *---------------------------------------------------------------------------*/
+void
+write_pid(void)
+{
+ FILE *fp;
+
+ /* write my pid into lock-file */
+
+ if((fp = fopen(PIDFILE, "w")) == NULL)
+ {
+ log(LL_ERR, "ERROR, can't open lockfile for writing, terminating");
+ do_exit(1);
+ }
+
+ if((fprintf(fp, "%d", (int)getpid())) == EOF)
+ {
+ log(LL_ERR, "ERROR, can't write pid to lockfile, terminating");
+ do_exit(1);
+ }
+
+ fsync(fileno(fp));
+
+ fclose(fp);
+}
+
+/*---------------------------------------------------------------------------*
+ * become a daemon
+ *---------------------------------------------------------------------------*/
+void
+daemonize(void)
+{
+ int fd;
+
+ switch (fork())
+ {
+ case -1: /* error */
+ log(LL_ERR, "ERROR, daemonize/fork: %s", strerror(errno));
+ exit(1);
+ case 0: /* child */
+ break;
+ default: /* parent */
+ exit(0);
+ }
+
+ /* new session / no control tty */
+
+ if(setsid() == -1)
+ {
+ log(LL_ERR, "ERROR, setsid returns: %s", strerror(errno));
+ exit(1);
+ }
+
+ /* go away from mounted dir */
+
+ chdir("/");
+
+ /* move i/o to another device ? */
+
+ if(do_fullscreen && do_rdev)
+ {
+ char *tp;
+
+ if((fd = open(rdev, O_RDWR, 0)) != -1)
+ {
+ if(!isatty(fd))
+ {
+ log(LL_ERR, "ERROR, device %s is not a tty!", rdev);
+ exit(1);
+ }
+ if((dup2(fd, STDIN_FILENO)) == -1)
+ {
+ log(LL_ERR, "ERROR, dup2 stdin: %s", strerror(errno));
+ exit(1);
+ }
+ if((dup2(fd, STDOUT_FILENO)) == -1)
+ {
+ log(LL_ERR, "ERROR, dup2 stdout: %s", strerror(errno));
+ exit(1);
+ }
+ if((dup2(fd, STDERR_FILENO)) == -1)
+ {
+ log(LL_ERR, "ERROR, dup2 stderr: %s", strerror(errno));
+ exit(1);
+ }
+ }
+ else
+ {
+ log(LL_ERR, "ERROR, cannot open redirected device: %s", strerror(errno));
+ exit(1);
+ }
+
+ if(fd > 2)
+ {
+ if((close(fd)) == -1)
+ {
+ log(LL_ERR, "ERROR, close in daemonize: %s", strerror(errno));
+ exit(1);
+ }
+ }
+
+ /* curses output && fork NEEDS controlling tty */
+
+ if((ioctl(STDIN_FILENO, TIOCSCTTY, (char *)NULL)) < 0)
+ {
+ log(LL_ERR, "ERROR, cannot setup tty as controlling terminal: %s", strerror(errno));
+ exit(1);
+ }
+
+ /* in case there is no environment ... */
+
+ if(((tp = getenv("TERM")) == NULL) || (*tp == '\0'))
+ {
+ if(do_ttytype == 0)
+ {
+ log(LL_ERR, "ERROR, no environment variable TERM found and -t not specified!");
+ exit(1);
+ }
+
+ if((setenv("TERM", ttype, 1)) != 0)
+ {
+ log(LL_ERR, "ERROR, setenv TERM=%s failed: %s", ttype, strerror(errno));
+ exit(1);
+ }
+ }
+ }
+}
+
+/* EOF */
diff --git a/usr.sbin/i4b/isdnd/rates.c b/usr.sbin/i4b/isdnd/rates.c
new file mode 100644
index 0000000..c1b1163
--- /dev/null
+++ b/usr.sbin/i4b/isdnd/rates.c
@@ -0,0 +1,473 @@
+/*
+ * Copyright (c) 1997 Gary Jennejohn. All rights reserved.
+ *
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 4. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software and/or documentation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * i4b daemon - charging rates description file handling
+ * -----------------------------------------------------
+ *
+ * $Id: rates.c,v 1.7 1998/12/05 18:03:34 hm Exp $
+ *
+ * last edit-date: [Sat Dec 5 18:11:55 1998]
+ *
+ *---------------------------------------------------------------------------*/
+
+static char error[256];
+
+#ifdef PARSE_DEBUG_MAIN
+
+#include <stdio.h>
+
+#define MAIN
+
+#define ERROR (-1)
+
+int main()
+{
+ int ret;
+ ret = readrates("/etc/isdn/isdnd.rates");
+ if(ret == ERROR)
+ fprintf(stderr, "readrates returns [%d], [%s]\n", ret, error);
+ else
+ fprintf(stderr, "readrates returns [%d]\n", ret);
+ return(ret);
+}
+
+#endif
+
+#include "isdnd.h"
+
+static int getrate(cfg_entry_t *cep);
+
+/*---------------------------------------------------------------------------*
+ * parse rates file
+ *---------------------------------------------------------------------------*/
+int
+readrates(char *filename)
+{
+ char buffer[1024];
+ register char *bp;
+ struct rates *rt, *ort;
+ int rateindx;
+ int indx;
+ int line = 0;
+ FILE *fp;
+ int first;
+#if DEBUG
+ int i, j;
+#endif
+
+ indx = 0;
+ rt = ort = NULL;
+
+ if((fp = fopen(filename, "r")) == NULL)
+ {
+ sprintf(error, "error open %s: %s", filename, sys_errlist[errno]);
+ rate_error = error;
+ return(WARNING);
+ }
+
+ while((fgets(buffer, MAXPATHLEN, fp)) != NULL)
+ {
+ line++;
+
+/* comments */
+ if(buffer[0] == '#' || buffer[0] == ' ' ||
+ buffer[0] == '\t' || buffer[0] == '\n')
+ {
+ continue;
+ }
+
+ bp = &buffer[0];
+
+ /* rate type */
+
+ if (*bp == 'r' && *(bp+1) == 'a' && isdigit(*(bp+2)))
+ {
+ rateindx = *(bp+2) - '0';
+ bp += 3;
+
+ /* eat space delimiter */
+
+ while(isspace(*bp))
+ bp++;
+ }
+ else
+ {
+ sprintf(error, "rates: invalid rate type %c%c%c in line %d", *bp, *(bp+1), *(bp+2), line);
+ goto rate_error;
+ }
+ if (rateindx >= NRATES)
+ {
+ sprintf(error, "rates: invalid rate index %d in line %d", rateindx, line);
+ goto rate_error;
+ }
+
+ /* day */
+
+ if(isdigit(*bp) && *bp >= '0' && *bp <= '6')
+ {
+ indx = *bp - '0';
+
+ DBGL(DL_RATES, (log(LL_DBG, "rates: index = %d", indx)));
+ }
+ else
+ {
+ sprintf(error, "rates: invalid day digit %c in line %d", *bp, line);
+ goto rate_error;
+ }
+
+ if(rates[rateindx][indx] == NULL)
+ {
+ rt = (struct rates *)malloc(sizeof (struct rates));
+ if (rt == NULL)
+ {
+ sprintf(error, "rates: cannot malloc space for rate structure");
+ goto rate_error;
+ }
+ rt->next = NULL;
+ rates[rateindx][indx] = rt;
+ }
+
+ bp++;
+
+ /* eat space delimiter */
+
+ while(isspace(*bp))
+ bp++;
+
+ /* now loop to get the rates entries */
+
+ first = 1;
+
+ while(*bp && isdigit(*bp))
+ {
+ if(first)
+ {
+ first = 0;
+ }
+ else
+ {
+ ort = rt;
+
+ rt = (struct rates *)malloc(sizeof (struct rates));
+ if (rt == NULL)
+ {
+ sprintf(error, "rates: cannot malloc space2 for rate structure");
+ goto rate_error;
+ }
+ ort->next = rt;
+ rt->next = NULL;
+ }
+
+ /* start hour */
+
+ if(isdigit(*bp) && isdigit(*(bp+1)))
+ {
+ rt->start_hr = atoi(bp);
+ bp += 2;
+ }
+ else
+ {
+ sprintf(error, "rates: start_hr error in line %d", line);
+ goto rate_error;
+ }
+
+ /* point */
+
+ if(*bp == '.')
+ {
+ bp++;
+ }
+ else
+ {
+ sprintf(error, "rates: no '.' after start_hr in line %d", line);
+ goto rate_error;
+ }
+
+ /* start minute */
+
+ if(isdigit(*bp) && isdigit(*(bp+1)))
+ {
+ rt->start_min = atoi(bp);
+ bp += 2;
+ }
+ else
+ {
+ sprintf(error, "rates: start_min error in line %d", line);
+ goto rate_error;
+ }
+
+ /* minus */
+
+ if(*bp == '-')
+ {
+ bp++;
+ }
+ else
+ {
+ sprintf(error, "rates: no '-' after start_min in line %d", line);
+ goto rate_error;
+ }
+
+ /* end hour */
+
+ if(isdigit(*bp) && isdigit(*(bp+1)))
+ {
+ rt->end_hr = atoi(bp);
+ bp += 2;
+ }
+ else
+ {
+ sprintf(error, "rates: end_hr error in line %d", line);
+ goto rate_error;
+ }
+
+ /* point */
+
+ if(*bp == '.')
+ {
+ bp++;
+ }
+ else
+ {
+ sprintf(error, "rates: no '.' after end_hr in line %d", line);
+ goto rate_error;
+ }
+
+ /* end minute */
+
+ if(isdigit(*bp) && isdigit(*(bp+1)))
+ {
+ rt->end_min = atoi(bp);
+ bp += 2;
+ }
+ else
+ {
+ sprintf(error, "rates: end_min error in line %d", line);
+ goto rate_error;
+ }
+
+ /* colon */
+
+ if(*bp == ':')
+ {
+ bp++;
+ }
+ else
+ {
+ sprintf(error, "rates: no ':' after end_min in line %d", line);
+ goto rate_error;
+ }
+
+ /* time */
+
+ if(isdigit(*bp))
+ {
+ rt->rate = atoi(bp);
+ while(!isspace(*bp))
+ bp++;
+ }
+ else
+ {
+ sprintf(error, "rates: first rate digit error in line %d", line);
+ goto rate_error;
+ }
+
+ /* eat space delimiter */
+
+ while(isspace(*bp))
+ bp++;
+ }
+ }
+
+#if DEBUG
+ if(debug_flags & DL_RATES)
+ {
+ for (j = 0; j < NRATES; j++)
+ {
+ for (i = 0; i < NDAYS; i++)
+ {
+ if (rates [j][i] != NULL)
+ {
+ rt = rates [j][i];
+ for (; rt; rt = rt->next)
+ {
+ log(LL_DBG, "rates: index %d day %d = %d.%d-%d.%d:%d",
+ j, i, rt->start_hr, rt->start_min,
+ rt->end_hr,rt->end_min,rt->rate);
+ }
+ }
+ else
+ {
+ log(LL_DBG, "rates: NO entry for day %d !!\n", i);
+ }
+ }
+ }
+ }
+#endif
+ fclose(fp);
+ return(GOOD);
+
+rate_error:
+ fclose(fp);
+ rate_error = error;
+ return(ERROR);
+}
+
+#ifndef PARSE_DEBUG_MAIN
+
+/*---------------------------------------------------------------------------*
+ * get unit length time from configured source
+ *---------------------------------------------------------------------------*/
+int
+get_current_rate(cfg_entry_t *cep, int logit)
+{
+ int rt;
+
+ switch(cep->unitlengthsrc)
+ {
+ case ULSRC_CMDL: /* specified on commandline */
+ if(logit)
+ log(LL_CHD, "%05d %s rate %d sec/unit (cmdl)",
+ cep->cdid, cep->name, unit_length);
+ return(unit_length);
+ break;
+
+ case ULSRC_CONF: /* get it from config file */
+ if(logit)
+ log(LL_CHD, "%05d %s rate %d sec/unit (conf)",
+ cep->cdid, cep->name, cep->unitlength);
+ return(cep->unitlength);
+
+ case ULSRC_RATE: /* get it dynamic from ratesfile*/
+ if(!got_rate) /* got valid rates struct ?? */
+ {
+ if(logit)
+ log(LL_CHD, "%05d %s rate %d sec/unit (no ratefile)",
+ cep->cdid, cep->name, UNITLENGTH_DEFAULT);
+ return(UNITLENGTH_DEFAULT);
+ }
+ if((cep->ratetype >= NRATES) ||
+ (cep->ratetype == INVALID_RATE))
+ {
+ if(logit)
+ log(LL_CHD, "%05d %s rate %d sec/unit (rate out of range)",
+ cep->cdid, cep->name, UNITLENGTH_DEFAULT);
+ return(UNITLENGTH_DEFAULT);
+ }
+
+ if((rt = getrate(cep)) != -1)
+ {
+ if(logit)
+ log(LL_CHD, "%05d %s rate %d sec/unit (rate)",
+ cep->cdid, cep->name, rt);
+ return(rt);
+ }
+
+ if(logit)
+ log(LL_CHD, "%05d %s rate %d sec/unit (ratescan fail)",
+ cep->cdid, cep->name, UNITLENGTH_DEFAULT);
+
+ return(UNITLENGTH_DEFAULT);
+ break;
+
+ case ULSRC_DYN: /* dynamically calculated from AOC */
+ if((rt = getrate(cep)) != -1)
+ {
+ if(logit)
+ log(LL_CHD, "%05d %s rate %d sec/unit (aocd, rate)",
+ cep->cdid, cep->name, rt);
+ return(rt);
+ }
+ if(logit)
+ log(LL_CHD, "%05d %s rate %d sec/unit (aocd, default)",
+ cep->cdid, cep->name, UNITLENGTH_DEFAULT);
+
+ return(UNITLENGTH_DEFAULT);
+ break;
+
+ default:
+ if(logit)
+ log(LL_CHD, "%05d %s rate %d sec/unit (unitlen unknown)",
+ cep->cdid, cep->name, UNITLENGTH_DEFAULT);
+
+ return(UNITLENGTH_DEFAULT);
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * get the currently active rate
+ *---------------------------------------------------------------------------*/
+static int
+getrate(cfg_entry_t *cep)
+{
+ struct tm *ptr;
+ time_t now;
+ register struct rates *hd;
+
+ if((!got_rate) ||
+ (cep->ratetype >= NRATES) ||
+ (cep->ratetype == INVALID_RATE))
+ {
+ return(-1);
+ }
+
+ time(&now); /* get current time */
+
+ ptr = localtime(&now);
+
+ /* walk thru the rates for weekday until rate for current time found */
+
+ for (hd = rates[cep->ratetype][ptr->tm_wday]; hd; hd = hd->next)
+ {
+ /* current time within window ? */
+ if((hd->start_hr <= ptr->tm_hour) &&
+ (hd->end_hr > ptr->tm_hour))
+ {
+ DBGL(DL_RATES, (log(LL_DBG, "rate=%d sec/unit (day=%d, beg=%d, end=%d, current=%d)",
+ hd->rate,
+ ptr->tm_wday,
+ hd->start_hr,
+ hd->end_hr,
+ ptr->tm_hour)));
+
+ return (hd->rate);
+ }
+ }
+ return(-1);
+}
+
+#endif /* PARSE_DEBUG_MAIN */
+
+/* EOF */
diff --git a/usr.sbin/i4b/isdnd/rc_config.c b/usr.sbin/i4b/isdnd/rc_config.c
new file mode 100644
index 0000000..884edfa
--- /dev/null
+++ b/usr.sbin/i4b/isdnd/rc_config.c
@@ -0,0 +1,1140 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * i4b daemon - config file processing
+ * -----------------------------------
+ *
+ * $Id: rc_config.c,v 1.35 1998/12/16 13:39:47 hm Exp $
+ *
+ * last edit-date: [Mon Dec 14 13:41:41 1998]
+ *
+ *---------------------------------------------------------------------------*/
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include "isdnd.h"
+#include "y.tab.h"
+
+#include "monitor.h"
+#include "vararray.h"
+
+extern int entrycount;
+extern int lineno;
+extern char *yytext;
+
+extern FILE *yyin;
+extern int yyparse();
+
+static void set_config_defaults(void);
+static void check_config(void);
+static void print_config(void);
+
+static int nregexpr = 0;
+static int nregprog = 0;
+
+/*---------------------------------------------------------------------------*
+ * called from main to read and process config file
+ *---------------------------------------------------------------------------*/
+void
+configure(char *filename, int reread)
+{
+ extern void reset_scanner(FILE *inputfile);
+
+ set_config_defaults();
+
+ yyin = fopen(filename, "r");
+
+ if(reread)
+ {
+ reset_scanner(yyin);
+ }
+
+ if (yyin == NULL)
+ {
+ log(LL_ERR, "cannot fopen file [%s]", filename);
+ exit(1);
+ }
+
+ yyparse();
+
+ monitor_fixup_rights();
+
+ check_config(); /* validation and consistency check */
+
+ fclose(yyin);
+
+ if(do_print)
+ {
+ if(config_error_flag)
+ {
+ log(LL_ERR, "there were %d error(s) in the configuration file, terminating!", config_error_flag);
+ exit(1);
+ }
+ print_config();
+ do_exit(0);
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * yacc error routine
+ *---------------------------------------------------------------------------*/
+void
+yyerror(const char *msg)
+{
+ log(LL_ERR, "configuration error: %s at line %d, token \"%s\"", msg, lineno+1, yytext);
+ config_error_flag++;
+}
+
+/*---------------------------------------------------------------------------*
+ * fill all config entries with default values
+ *---------------------------------------------------------------------------*/
+static void
+set_config_defaults(void)
+{
+ cfg_entry_t *cep = &cfg_entry_tab[0]; /* ptr to config entry */
+ int i;
+
+ /* system section cleanup */
+
+ nregprog = nregexpr = 0;
+
+ rt_prio = RTPRIO_NOTUSED;
+
+ /* clean regular expression table */
+
+ for(i=0; i < MAX_RE; i++)
+ {
+ if(rarr[i].re_expr)
+ free(rarr[i].re_expr);
+ rarr[i].re_expr = NULL;
+
+ if(rarr[i].re_prog)
+ free(rarr[i].re_prog);
+ rarr[i].re_prog = NULL;
+
+ rarr[i].re_flg = 0;
+ }
+
+ /* entry section cleanup */
+
+ for(i=0; i < CFG_ENTRY_MAX; i++, cep++)
+ {
+ bzero(cep, sizeof(cfg_entry_t));
+
+ /* ====== filled in at startup configuration, then static */
+
+ sprintf(cep->name, "ENTRY%d", i);
+
+ cep->isdncontroller = INVALID;
+ cep->isdnchannel = CHAN_ANY;
+
+ cep->usrdevicename = INVALID;
+ cep->usrdeviceunit = INVALID;
+
+ cep->remote_numbers_handling = RNH_LAST;
+
+ cep->dialin_reaction = REACT_IGNORE;
+
+ cep->b1protocol = BPROT_NONE;
+
+ cep->unitlength = UNITLENGTH_DEFAULT;
+
+ cep->earlyhangup = EARLYHANGUP_DEFAULT;
+
+ cep->ratetype = INVALID_RATE;
+
+ cep->unitlengthsrc = ULSRC_NONE;
+
+ cep->answerprog = ANSWERPROG_DEF;
+
+ cep->callbackwait = CALLBACKWAIT_MIN;
+
+ cep->calledbackwait = CALLEDBACKWAIT_MIN;
+
+ cep->dialretries = DIALRETRIES_DEF;
+
+ cep->recoverytime = RECOVERYTIME_MIN;
+
+ cep->dialouttype = DIALOUT_NORMAL;
+
+ cep->inout = DIR_INOUT;
+
+ /* ======== filled in after start, then dynamic */
+
+ cep->cdid = CDID_UNUSED;
+
+ cep->state = ST_IDLE;
+
+ cep->aoc_valid = AOC_INVALID;
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * extract values from config and fill table
+ *---------------------------------------------------------------------------*/
+void
+cfg_setval(int keyword)
+{
+ int i;
+
+ switch(keyword)
+ {
+ case ACCTALL:
+ acct_all = yylval.booln;
+ log(LL_DBG, "system: acctall = %d", yylval.booln);
+ break;
+
+ case ACCTFILE:
+ strcpy(acctfile, yylval.str);
+ log(LL_DBG, "system: acctfile = %s", yylval.str);
+ break;
+
+ case ALERT:
+ if(yylval.num < MINALERT)
+ {
+ yylval.num = MINALERT;
+ log(LL_DBG, "entry %d: alert < %d, min = %d", entrycount, MINALERT, yylval.num);
+ }
+ else if(yylval.num > MAXALERT)
+ {
+ yylval.num = MAXALERT;
+ log(LL_DBG, "entry %d: alert > %d, min = %d", entrycount, MAXALERT, yylval.num);
+ }
+
+ log(LL_DBG, "entry %d: alert = %d", entrycount, yylval.num);
+ cfg_entry_tab[entrycount].alert = yylval.num;
+ break;
+
+ case ALIASING:
+ log(LL_DBG, "system: aliasing = %d", yylval.booln);
+ aliasing = yylval.booln;
+ break;
+
+ case ALIASFNAME:
+ strcpy(aliasfile, yylval.str);
+ log(LL_DBG, "system: aliasfile = %s", yylval.str);
+ break;
+
+ case ANSWERPROG:
+ if((cfg_entry_tab[entrycount].answerprog = malloc(strlen(yylval.str)+1)) == NULL)
+ {
+ log(LL_ERR, "entry %d: answerstring, malloc failed!", entrycount);
+ do_exit(1);
+ }
+ strcpy(cfg_entry_tab[entrycount].answerprog, yylval.str);
+ log(LL_DBG, "entry %d: answerprog = %s", entrycount, yylval.str);
+ break;
+
+ case B1PROTOCOL:
+ log(LL_DBG, "entry %d: b1protocol = %s", entrycount, yylval.str);
+ if(!(strcmp(yylval.str, "raw")))
+ cfg_entry_tab[entrycount].b1protocol = BPROT_NONE;
+ else if(!(strcmp(yylval.str, "hdlc")))
+ cfg_entry_tab[entrycount].b1protocol = BPROT_RHDLC;
+ else
+ {
+ log(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"b1protocol\" at line %d!", lineno);
+ config_error_flag++;
+ }
+ break;
+
+ case CALLBACKWAIT:
+ if(yylval.num < CALLBACKWAIT_MIN)
+ {
+ yylval.num = CALLBACKWAIT_MIN;
+ log(LL_DBG, "entry %d: callbackwait < %d, min = %d", entrycount, CALLBACKWAIT_MIN, yylval.num);
+ }
+
+ log(LL_DBG, "entry %d: callbackwait = %d", entrycount, yylval.num);
+ cfg_entry_tab[entrycount].callbackwait = yylval.num;
+ break;
+
+ case CALLEDBACKWAIT:
+ if(yylval.num < CALLEDBACKWAIT_MIN)
+ {
+ yylval.num = CALLEDBACKWAIT_MIN;
+ log(LL_DBG, "entry %d: calledbackwait < %d, min = %d", entrycount, CALLEDBACKWAIT_MIN, yylval.num);
+ }
+
+ log(LL_DBG, "entry %d: calledbackwait = %d", entrycount, yylval.num);
+ cfg_entry_tab[entrycount].calledbackwait = yylval.num;
+ break;
+
+ case CONNECTPROG:
+ if((cfg_entry_tab[entrycount].connectprog = malloc(strlen(yylval.str)+1)) == NULL)
+ {
+ log(LL_ERR, "entry %d: connectprog, malloc failed!", entrycount);
+ do_exit(1);
+ }
+ strcpy(cfg_entry_tab[entrycount].connectprog, yylval.str);
+ log(LL_DBG, "entry %d: connectprog = %s", entrycount, yylval.str);
+ break;
+
+ case DIALOUTTYPE:
+ log(LL_DBG, "entry %d: dialouttype = %s", entrycount, yylval.str);
+ if(!(strcmp(yylval.str, "normal")))
+ cfg_entry_tab[entrycount].dialouttype = DIALOUT_NORMAL;
+ else if(!(strcmp(yylval.str, "calledback")))
+ cfg_entry_tab[entrycount].dialouttype = DIALOUT_CALLEDBACK;
+ else
+ {
+ log(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"dialout-type\" at line %d!", lineno);
+ config_error_flag++;
+ }
+ break;
+
+ case DIALRETRIES:
+ log(LL_DBG, "entry %d: dialretries = %d", entrycount, yylval.num);
+ cfg_entry_tab[entrycount].dialretries = yylval.num;
+ break;
+
+ case DIALRANDINCR:
+ log(LL_DBG, "entry %d: dialrandincr = %d", entrycount, yylval.booln);
+ cfg_entry_tab[entrycount].dialrandincr = yylval.booln;
+ break;
+
+ case DIRECTION:
+ log(LL_DBG, "entry %d: direction = %s", entrycount, yylval.str);
+
+ if(!(strcmp(yylval.str, "inout")))
+ cfg_entry_tab[entrycount].inout = DIR_INOUT;
+ else if(!(strcmp(yylval.str, "in")))
+ cfg_entry_tab[entrycount].inout = DIR_INONLY;
+ else if(!(strcmp(yylval.str, "out")))
+ cfg_entry_tab[entrycount].inout = DIR_OUTONLY;
+ else
+ {
+ log(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"direction\" at line %d!", lineno);
+ config_error_flag++;
+ }
+ break;
+
+ case DISCONNECTPROG:
+ if((cfg_entry_tab[entrycount].disconnectprog = malloc(strlen(yylval.str)+1)) == NULL)
+ {
+ log(LL_ERR, "entry %d: disconnectprog, malloc failed!", entrycount);
+ do_exit(1);
+ }
+ strcpy(cfg_entry_tab[entrycount].disconnectprog, yylval.str);
+ log(LL_DBG, "entry %d: disconnectprog = %s", entrycount, yylval.str);
+ break;
+
+ case DOWNTRIES:
+ if(yylval.num > DOWN_TRIES_MAX)
+ yylval.num = DOWN_TRIES_MAX;
+ else if(yylval.num < DOWN_TRIES_MIN)
+ yylval.num = DOWN_TRIES_MIN;
+
+ log(LL_DBG, "entry %d: downtries = %d", entrycount, yylval.num);
+ cfg_entry_tab[entrycount].downtries = yylval.num;
+ break;
+
+ case DOWNTIME:
+ if(yylval.num > DOWN_TIME_MAX)
+ yylval.num = DOWN_TIME_MAX;
+ else if(yylval.num < DOWN_TIME_MIN)
+ yylval.num = DOWN_TIME_MIN;
+
+ log(LL_DBG, "entry %d: downtime = %d", entrycount, yylval.num);
+ cfg_entry_tab[entrycount].downtime = yylval.num;
+ break;
+
+ case EARLYHANGUP:
+ log(LL_DBG, "entry %d: earlyhangup = %d", entrycount, yylval.num);
+ cfg_entry_tab[entrycount].earlyhangup = yylval.num;
+ break;
+
+ case IDLETIME_IN:
+ log(LL_DBG, "entry %d: idle_time_in = %d", entrycount, yylval.num);
+ cfg_entry_tab[entrycount].idle_time_in = yylval.num;
+ break;
+
+ case IDLETIME_OUT:
+ log(LL_DBG, "entry %d: idle_time_out = %d", entrycount, yylval.num);
+ cfg_entry_tab[entrycount].idle_time_out = yylval.num;
+ break;
+
+ case ISDNCONTROLLER:
+ cfg_entry_tab[entrycount].isdncontroller = yylval.num;
+ log(LL_DBG, "entry %d: isdncontroller = %d", entrycount, yylval.num);
+ break;
+
+ case ISDNCHANNEL:
+ switch(yylval.num)
+ {
+ case 0:
+ case -1:
+ cfg_entry_tab[entrycount].isdnchannel = CHAN_ANY;
+ log(LL_DBG, "entry %d: isdnchannel = any", entrycount);
+ break;
+ case 1:
+ cfg_entry_tab[entrycount].isdnchannel = CHAN_B1;
+ log(LL_DBG, "entry %d: isdnchannel = one", entrycount);
+ break;
+ case 2:
+ cfg_entry_tab[entrycount].isdnchannel = CHAN_B2;
+ log(LL_DBG, "entry %d: isdnchannel = two", entrycount);
+ break;
+ default:
+ log(LL_DBG, "entry %d: isdnchannel value out of range", entrycount);
+ config_error_flag++;
+ break;
+ }
+ break;
+
+ case ISDNTIME:
+ log(LL_DBG, "system: isdntime = %d", yylval.booln);
+ isdntime = yylval.booln;
+ break;
+
+ case ISDNTXDELIN:
+ cfg_entry_tab[entrycount].isdntxdelin = yylval.num;
+ log(LL_DBG, "entry %d: isdntxdel-incoming = %d", entrycount, yylval.num);
+ break;
+
+ case ISDNTXDELOUT:
+ cfg_entry_tab[entrycount].isdntxdelout = yylval.num;
+ log(LL_DBG, "entry %d: isdntxdel-outgoing = %d", entrycount, yylval.num);
+ break;
+
+ case LOCAL_PHONE_DIALOUT:
+ log(LL_DBG, "entry %d: local_phone_dialout = %s", entrycount, yylval.str);
+ strcpy(cfg_entry_tab[entrycount].local_phone_dialout, yylval.str);
+ break;
+
+ case LOCAL_PHONE_INCOMING:
+ log(LL_DBG, "entry %d: local_phone_incoming = %s", entrycount, yylval.str);
+ strcpy(cfg_entry_tab[entrycount].local_phone_incoming, yylval.str);
+ break;
+
+ case MONITORPORT:
+ monitorport = yylval.num;
+ log(LL_DBG, "system: monitorport = %d", yylval.num);
+ break;
+
+ case MONITORSW:
+ if (yylval.booln && inhibit_monitor) {
+ do_monitor = 0;
+ log(LL_DBG, "system: monitor-enable overriden by command line flag");
+ } else {
+ do_monitor = yylval.booln;
+ log(LL_DBG, "system: monitor-enable = %d", yylval.booln);
+ }
+ break;
+
+ case NAME:
+ log(LL_DBG, "entry %d: name = %s", entrycount, yylval.str);
+ strcpy(cfg_entry_tab[entrycount].name, yylval.str);
+ break;
+
+ case REACTION:
+ log(LL_DBG, "entry %d: dialin_reaction = %s", entrycount, yylval.str);
+ if(!(strcmp(yylval.str, "accept")))
+ cfg_entry_tab[entrycount].dialin_reaction = REACT_ACCEPT;
+ else if(!(strcmp(yylval.str, "reject")))
+ cfg_entry_tab[entrycount].dialin_reaction = REACT_REJECT;
+ else if(!(strcmp(yylval.str, "ignore")))
+ cfg_entry_tab[entrycount].dialin_reaction = REACT_IGNORE;
+ else if(!(strcmp(yylval.str, "answer")))
+ cfg_entry_tab[entrycount].dialin_reaction = REACT_ANSWER;
+ else if(!(strcmp(yylval.str, "callback")))
+ cfg_entry_tab[entrycount].dialin_reaction = REACT_CALLBACK;
+ else
+ {
+ log(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"dialin_reaction\" at line %d!", lineno);
+ config_error_flag++;
+ }
+ break;
+
+ case REMOTE_PHONE_DIALOUT:
+ if(cfg_entry_tab[entrycount].remote_numbers_count >= MAXRNUMBERS)
+ {
+ log(LL_ERR, "ERROR parsing config file: too many remote numbers at line %d!", lineno);
+ config_error_flag++;
+ break;
+ }
+
+ log(LL_DBG, "entry %d: remote_phone_dialout #%d = %s",
+ entrycount, cfg_entry_tab[entrycount].remote_numbers_count, yylval.str);
+
+ strcpy(cfg_entry_tab[entrycount].remote_numbers[cfg_entry_tab[entrycount].remote_numbers_count].number, yylval.str);
+ cfg_entry_tab[entrycount].remote_numbers[cfg_entry_tab[entrycount].remote_numbers_count].flag = 0;
+
+ cfg_entry_tab[entrycount].remote_numbers_count++;
+
+ break;
+
+ case REMOTE_NUMBERS_HANDLING:
+ log(LL_DBG, "entry %d: remdial_handling = %s", entrycount, yylval.str);
+ if(!(strcmp(yylval.str, "next")))
+ cfg_entry_tab[entrycount].remote_numbers_handling = RNH_NEXT;
+ else if(!(strcmp(yylval.str, "last")))
+ cfg_entry_tab[entrycount].remote_numbers_handling = RNH_LAST;
+ else if(!(strcmp(yylval.str, "first")))
+ cfg_entry_tab[entrycount].remote_numbers_handling = RNH_FIRST;
+ else
+ {
+ log(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"remdial_handling\" at line %d!", lineno);
+ config_error_flag++;
+ }
+ break;
+
+ case REMOTE_PHONE_INCOMING:
+ {
+ int n;
+ n = cfg_entry_tab[entrycount].incoming_numbers_count;
+ if (n >= MAX_INCOMING)
+ {
+ log(LL_ERR, "ERROR parsing config file: too many \"remote_phone_incoming\" entries at line %d!", lineno);
+ config_error_flag++;
+ break;
+ }
+ log(LL_DBG, "entry %d: remote_phone_incoming #%d = %s", entrycount, n, yylval.str);
+ strcpy(cfg_entry_tab[entrycount].remote_phone_incoming[n].number, yylval.str);
+ cfg_entry_tab[entrycount].incoming_numbers_count++;
+ }
+ break;
+
+ case RATESFILE:
+ strcpy(ratesfile, yylval.str);
+ log(LL_DBG, "system: ratesfile = %s", yylval.str);
+ break;
+
+ case RATETYPE:
+ log(LL_DBG, "entry %d: ratetype = %d", entrycount, yylval.num);
+ cfg_entry_tab[entrycount].ratetype = yylval.num;
+ break;
+
+ case RECOVERYTIME:
+ if(yylval.num < RECOVERYTIME_MIN)
+ {
+ yylval.num = RECOVERYTIME_MIN;
+ log(LL_DBG, "entry %d: recoverytime < %d, min = %d", entrycount, RECOVERYTIME_MIN, yylval.num);
+ }
+
+ log(LL_DBG, "entry %d: recoverytime = %d", entrycount, yylval.num);
+ cfg_entry_tab[entrycount].recoverytime = yylval.num;
+ break;
+
+ case REGEXPR:
+ if(nregexpr >= MAX_RE)
+ {
+ log(LL_DBG, "system: regexpr #%d >= MAX_RE", nregexpr);
+ config_error_flag++;
+ break;
+ }
+
+ if((i = regcomp(&(rarr[nregexpr].re), yylval.str, REG_EXTENDED|REG_NOSUB)) != 0)
+ {
+ char buf[256];
+ regerror(i, &(rarr[nregexpr].re), buf, sizeof(buf));
+ log(LL_DBG, "system: regcomp error for %s: [%s]", yylval.str, buf);
+ config_error_flag++;
+ break;
+ }
+ else
+ {
+ if((rarr[nregexpr].re_expr = malloc(strlen(yylval.str)+1)) == NULL)
+ {
+ log(LL_DBG, "system: regexpr malloc error error for %s", yylval.str);
+ config_error_flag++;
+ break;
+ }
+ strcpy(rarr[nregexpr].re_expr, yylval.str);
+
+ log(LL_DBG, "system: regexpr %s stored into slot %d", yylval.str, nregexpr);
+
+ if(rarr[nregexpr].re_prog != NULL)
+ rarr[nregexpr].re_flg = 1;
+
+ nregexpr++;
+
+ }
+ break;
+
+ case REGPROG:
+ if(nregprog >= MAX_RE)
+ {
+ log(LL_DBG, "system: regprog #%d >= MAX_RE", nregprog);
+ config_error_flag++;
+ break;
+ }
+ if((rarr[nregprog].re_prog = malloc(strlen(yylval.str)+1)) == NULL)
+ {
+ log(LL_DBG, "system: regprog malloc error error for %s", yylval.str);
+ config_error_flag++;
+ break;
+ }
+ strcpy(rarr[nregprog].re_prog, yylval.str);
+
+ log(LL_DBG, "system: regprog %s stored into slot %d", yylval.str, nregprog);
+
+ if(rarr[nregprog].re_expr != NULL)
+ rarr[nregprog].re_flg = 1;
+
+ nregprog++;
+ break;
+
+ case RTPRIO:
+#ifdef USE_RTPRIO
+ rt_prio = yylval.num;
+ if(rt_prio < RTP_PRIO_MIN || rt_prio > RTP_PRIO_MAX)
+ {
+ config_error_flag++;
+ log(LL_DBG, "system: error, rtprio (%d) out of range!", yylval.num);
+ }
+ else
+ {
+ log(LL_DBG, "system: rtprio = %d", yylval.num);
+ }
+#else
+ rt_prio = RTPRIO_NOTUSED;
+#endif
+ break;
+
+ case UNITLENGTH:
+ log(LL_DBG, "entry %d: unitlength = %d", entrycount, yylval.num);
+ cfg_entry_tab[entrycount].unitlength = yylval.num;
+ break;
+
+ case UNITLENGTHSRC:
+ log(LL_DBG, "entry %d: unitlengthsrc = %s", entrycount, yylval.str);
+ if(!(strcmp(yylval.str, "none")))
+ cfg_entry_tab[entrycount].unitlengthsrc = ULSRC_NONE;
+ else if(!(strcmp(yylval.str, "cmdl")))
+ cfg_entry_tab[entrycount].unitlengthsrc = ULSRC_CMDL;
+ else if(!(strcmp(yylval.str, "conf")))
+ cfg_entry_tab[entrycount].unitlengthsrc = ULSRC_CONF;
+ else if(!(strcmp(yylval.str, "rate")))
+ cfg_entry_tab[entrycount].unitlengthsrc = ULSRC_RATE;
+ else if(!(strcmp(yylval.str, "aocd")))
+ cfg_entry_tab[entrycount].unitlengthsrc = ULSRC_DYN;
+ else
+ {
+ log(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"unitlengthsrc\" at line %d!", lineno);
+ config_error_flag++;
+ }
+ break;
+
+ case USRDEVICENAME:
+ log(LL_DBG, "entry %d: usrdevicename = %s", entrycount, yylval.str);
+ if(!strcmp(yylval.str, "rbch"))
+ cfg_entry_tab[entrycount].usrdevicename = BDRV_RBCH;
+ else if(!strcmp(yylval.str, "tel"))
+ cfg_entry_tab[entrycount].usrdevicename = BDRV_TEL;
+ else if(!strcmp(yylval.str, "ipr"))
+ cfg_entry_tab[entrycount].usrdevicename = BDRV_IPR;
+ else if(!strcmp(yylval.str, "isp"))
+ cfg_entry_tab[entrycount].usrdevicename = BDRV_ISPPP;
+ else
+ {
+ log(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"usrdevicename\" at line %d!", lineno);
+ config_error_flag++;
+ }
+ break;
+
+ case USRDEVICEUNIT:
+ log(LL_DBG, "entry %d: usrdeviceunit = %d", entrycount, yylval.num);
+ cfg_entry_tab[entrycount].usrdeviceunit = yylval.num;
+ break;
+
+ case USEACCTFILE:
+ useacctfile = yylval.booln;
+ log(LL_DBG, "system: useacctfile = %d", yylval.booln);
+ break;
+
+ case USEDOWN:
+ log(LL_DBG, "entry %d: usedown = %d", entrycount, yylval.booln);
+ cfg_entry_tab[entrycount].usedown = yylval.booln;
+ break;
+
+ default:
+ log(LL_ERR, "ERROR parsing config file: unknown keyword at line %d!", lineno);
+ config_error_flag++;
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * configuration validation and consistency check
+ *---------------------------------------------------------------------------*/
+static void
+check_config(void)
+{
+ cfg_entry_t *cep = &cfg_entry_tab[0]; /* ptr to config entry */
+ int i;
+ int error = 0;
+
+ /* regular expression table */
+
+ for(i=0; i < MAX_RE; i++)
+ {
+ if((rarr[i].re_expr != NULL) && (rarr[i].re_prog == NULL))
+ {
+ log(LL_ERR, "check_config: regular expression %d without program!", i);
+ error++;
+ }
+ if((rarr[i].re_prog != NULL) && (rarr[i].re_expr == NULL))
+ {
+ log(LL_ERR, "check_config: regular expression program %d without expression!", i);
+ error++;
+ }
+ }
+
+ /* entry sections */
+
+ for(i=0; i <= entrycount; i++, cep++)
+ {
+ /* isdn controller number */
+
+ if((cep->isdncontroller < 0) || (cep->isdncontroller > (ncontroller-1)))
+ {
+ log(LL_ERR, "check_config: isdncontroller out of range in entry %d!", i);
+ error++;
+ }
+
+ /* numbers used for dialout */
+
+ if((cep->inout != DIR_INONLY) && (cep->dialin_reaction != REACT_ANSWER))
+ {
+ if(cep->remote_numbers_count == 0)
+ {
+ log(LL_ERR, "check_config: remote-phone-dialout not set in entry %d!", i);
+ error++;
+ }
+ if(strlen(cep->local_phone_dialout) == 0)
+ {
+ log(LL_ERR, "check_config: local-phone-dialout not set in entry %d!", i);
+ error++;
+ }
+ }
+
+ /* numbers used for incoming calls */
+
+ if(cep->inout != DIR_OUTONLY)
+ {
+ if(strlen(cep->local_phone_incoming) == 0)
+ {
+ log(LL_ERR, "check_config: local-phone-incoming not set in entry %d!", i);
+ error++;
+ }
+ if(cep->incoming_numbers_count == 0)
+ {
+ log(LL_ERR, "check_config: remote-phone-incoming not set in entry %d!", i);
+ error++;
+ }
+ }
+
+ if((cep->dialin_reaction == REACT_ANSWER) && (cep->b1protocol != BPROT_NONE))
+ {
+ log(LL_ERR, "check_config: b1protocol not raw for telephony in entry %d!", i);
+ error++;
+ }
+ }
+ if(error)
+ {
+ log(LL_ERR, "check_config: %d error(s) in configuration file, exit!", error);
+ do_exit(1);
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * print the configuration
+ *---------------------------------------------------------------------------*/
+static void
+print_config(void)
+{
+#define PFILE stdout
+
+ cfg_entry_t *cep = &cfg_entry_tab[0]; /* ptr to config entry */
+ int i, j;
+ extern VARA_DECL(struct monitor_rights) rights;
+ time_t clock;
+ char mytime[64];
+
+ time(&clock);
+ strcpy(mytime, ctime(&clock));
+ mytime[strlen(mytime)-1] = '\0';
+
+ fprintf(PFILE, "#---------------------------------------------------------------------------\n");
+ fprintf(PFILE, "# system section (generated %s)\n", mytime);
+ fprintf(PFILE, "#---------------------------------------------------------------------------\n");
+ fprintf(PFILE, "system\n");
+ fprintf(PFILE, "useacctfile = %s\n", useacctfile ? "on\t\t\t\t# update accounting information file" : "off\t\t\t\t# don't update accounting information file");
+ fprintf(PFILE, "acctall = %s\n", acct_all ? "on\t\t\t\t# put all events into accounting file" : "off\t\t\t\t# put only charged events into accounting file");
+ fprintf(PFILE, "acctfile = %s\t\t# accounting information file\n", acctfile);
+ fprintf(PFILE, "ratesfile = %s\t\t# charging rates database file\n", ratesfile);
+
+#ifdef USE_RTPRIO
+ if(rt_prio == RTPRIO_NOTUSED)
+ fprintf(PFILE, "# rtprio is unused\n");
+ else
+ fprintf(PFILE, "rtprio = %d\t\t\t\t# isdnd runs at realtime priority\n", rt_prio);
+#endif
+
+ /* regular expression table */
+
+ for(i=0; i < MAX_RE; i++)
+ {
+ if(rarr[i].re_expr != NULL)
+ {
+ fprintf(PFILE, "regexpr = \"%s\"\t\t# scan logfile for this expression\n", rarr[i].re_expr);
+ }
+ if(rarr[i].re_prog != NULL)
+ {
+ fprintf(PFILE, "regprog = %s\t\t# program to run when expression is matched\n", rarr[i].re_prog);
+ }
+ }
+
+#ifdef I4B_EXTERNAL_MONITOR
+
+ fprintf(PFILE, "monitor-allowed = %s\n", do_monitor ? "on\t\t\t\t# remote isdnd monitoring allowed" : "off\t\t\t\t# remote isdnd monitoring disabled");
+ fprintf(PFILE, "monitor-port = %d\t\t\t\t# TCP/IP port number used for remote monitoring\n", monitorport);
+
+ if(VARA_NUM(rights))
+ {
+ char *s = "error\n";
+ char b[512];
+
+ VARA_FOREACH(rights, i)
+ {
+ if(VARA_AT(rights, i).local)
+ {
+ fprintf(PFILE, "monitor = \"%s\"\t\t# local socket name for monitoring\n", VARA_AT(rights, i).name);
+ }
+ else
+ {
+ struct in_addr ia;
+ ia.s_addr = ntohl(VARA_AT(rights, i).net);
+
+ switch(VARA_AT(rights, i).mask)
+ {
+ case 0xffffffff:
+ s = "32";
+ break;
+ case 0xfffffffe:
+ s = "31";
+ break;
+ case 0xfffffffc:
+ s = "30";
+ break;
+ case 0xfffffff8:
+ s = "29";
+ break;
+ case 0xfffffff0:
+ s = "28";
+ break;
+ case 0xffffffe0:
+ s = "27";
+ break;
+ case 0xffffffc0:
+ s = "26";
+ break;
+ case 0xffffff80:
+ s = "25";
+ break;
+ case 0xffffff00:
+ s = "24";
+ break;
+ case 0xfffffe00:
+ s = "23";
+ break;
+ case 0xfffffc00:
+ s = "22";
+ break;
+ case 0xfffff800:
+ s = "21";
+ break;
+ case 0xfffff000:
+ s = "20";
+ break;
+ case 0xffffe000:
+ s = "19";
+ break;
+ case 0xffffc000:
+ s = "18";
+ break;
+ case 0xffff8000:
+ s = "17";
+ break;
+ case 0xffff0000:
+ s = "16";
+ break;
+ case 0xfffe0000:
+ s = "15";
+ break;
+ case 0xfffc0000:
+ s = "14";
+ break;
+ case 0xfff80000:
+ s = "13";
+ break;
+ case 0xfff00000:
+ s = "12";
+ break;
+ case 0xffe00000:
+ s = "11";
+ break;
+ case 0xffc00000:
+ s = "10";
+ break;
+ case 0xff800000:
+ s = "9";
+ break;
+ case 0xff000000:
+ s = "8";
+ break;
+ case 0xfe000000:
+ s = "7";
+ break;
+ case 0xfc000000:
+ s = "6";
+ break;
+ case 0xf8000000:
+ s = "5";
+ break;
+ case 0xf0000000:
+ s = "4";
+ break;
+ case 0xe0000000:
+ s = "3";
+ break;
+ case 0xc0000000:
+ s = "2";
+ break;
+ case 0x80000000:
+ s = "1";
+ break;
+ case 0x00000000:
+ s = "0";
+ break;
+ }
+ fprintf(PFILE, "monitor = \"%s/%s\"\t\t# host (net/mask) allowed to connect for monitoring\n", inet_ntoa(ia), s);
+ }
+ b[0] = '\0';
+
+ if((VARA_AT(rights, i).rights) & I4B_CA_COMMAND_FULL)
+ strcat(b, "fullcmd,");
+ if((VARA_AT(rights, i).rights) & I4B_CA_COMMAND_RESTRICTED)
+ strcat(b, "restrictedcmd,");
+ if((VARA_AT(rights, i).rights) & I4B_CA_EVNT_CHANSTATE)
+ strcat(b, "channelstate,");
+ if((VARA_AT(rights, i).rights) & I4B_CA_EVNT_CALLIN)
+ strcat(b, "callin,");
+ if((VARA_AT(rights, i).rights) & I4B_CA_EVNT_CALLOUT)
+ strcat(b, "callout,");
+ if((VARA_AT(rights, i).rights) & I4B_CA_EVNT_I4B)
+ strcat(b, "logevents,");
+
+ if(b[strlen(b)-1] == ',')
+ b[strlen(b)-1] = '\0';
+
+ fprintf(PFILE, "monitor-access = %s\t\t# monitor access rights\n", b);
+ }
+ }
+
+#endif
+ /* entry sections */
+
+ for(i=0; i <= entrycount; i++, cep++)
+ {
+ fprintf(PFILE, "\n");
+ fprintf(PFILE, "#---------------------------------------------------------------------------\n");
+ fprintf(PFILE, "# entry section %d\n", i);
+ fprintf(PFILE, "#---------------------------------------------------------------------------\n");
+ fprintf(PFILE, "entry\n");
+
+ fprintf(PFILE, "name = %s\t\t# name for this entry section\n", cep->name);
+
+ fprintf(PFILE, "isdncontroller = %d\t\t# ISDN card number used for this entry\n", cep->isdncontroller);
+ fprintf(PFILE, "isdnchannel = ");
+ switch(cep->isdnchannel)
+ {
+ case CHAN_ANY:
+ fprintf(PFILE, "-1\t\t# any ISDN B-channel may be used\n");
+ break;
+ case CHAN_B1:
+ fprintf(PFILE, "1\t\t# only ISDN B-channel 1 may be used\n");
+ break;
+ case CHAN_B2:
+ fprintf(PFILE, "2\t\t# only ISDN B-channel 2 ay be used\n");
+ break;
+ }
+
+ fprintf(PFILE, "usrdevicename = %s\t\t# name of userland ISDN B-channel device\n", bdrivername(cep->usrdevicename));
+ fprintf(PFILE, "usrdeviceunit = %d\t\t# unit number of userland ISDN B-channel device\n", cep->usrdeviceunit);
+
+ fprintf(PFILE, "b1protocol = %s\n", cep->b1protocol ? "hdlc\t\t# B-channel layer 1 protocol is HDLC" : "raw\t\t# No B-channel layer 1 protocol used");
+
+ if(!(cep->usrdevicename == BDRV_TEL))
+ {
+ fprintf(PFILE, "direction = ");
+ switch(cep->inout)
+ {
+ case DIR_INONLY:
+ fprintf(PFILE, "in\t\t# only incoming connections allowed\n");
+ break;
+ case DIR_OUTONLY:
+ fprintf(PFILE, "out\t\t# only outgoing connections allowed\n");
+ break;
+ case DIR_INOUT:
+ fprintf(PFILE, "inout\t\t# incoming and outgoing connections allowed\n");
+ break;
+ }
+ }
+
+ if(!((cep->usrdevicename == BDRV_TEL) || (cep->inout == DIR_INONLY)))
+ {
+ if(cep->remote_numbers_count > 1)
+ {
+ for(j=0; j<cep->remote_numbers_count; j++)
+ fprintf(PFILE, "remote-phone-dialout = %s\t\t# telephone number %d for dialing out to remote\n", cep->remote_numbers[j].number, j+1);
+
+ fprintf(PFILE, "remdial-handling = ");
+
+ switch(cep->remote_numbers_handling)
+ {
+ case RNH_NEXT:
+ fprintf(PFILE, "next\t\t# use next number after last successfull for new dial\n");
+ break;
+ case RNH_LAST:
+ fprintf(PFILE, "last\t\t# use last successfull number for new dial\n");
+ break;
+ case RNH_FIRST:
+ fprintf(PFILE, "first\t\t# always start with first number for new dial\n");
+ break;
+ }
+ }
+ else
+ {
+ fprintf(PFILE, "remote-phone-dialout = %s\t\t# telephone number for dialing out to remote\n", cep->remote_numbers[0].number);
+ }
+
+ fprintf(PFILE, "local-phone-dialout = %s\t\t# show this number to remote when dialling out\n", cep->local_phone_dialout);
+ fprintf(PFILE, "dialout-type = %s\n", cep->dialouttype ? "calledback\t\t# i am called back by remote" : "normal\t\t# i am not called back by remote");
+ }
+
+ if(!(cep->inout == DIR_OUTONLY))
+ {
+ int n;
+
+ fprintf(PFILE, "local-phone-incoming = %s\t\t# incoming calls must match this (mine) telephone number\n", cep->local_phone_incoming);
+ for (n = 0; n < cep->incoming_numbers_count; n++)
+ fprintf(PFILE, "remote-phone-incoming = %s\t\t# this is a valid remote number to call me\n",
+ cep->remote_phone_incoming[n].number);
+
+ fprintf(PFILE, "dialin-reaction = ");
+ switch(cep->dialin_reaction)
+ {
+ case REACT_ACCEPT:
+ fprintf(PFILE, "accept\t\t# i accept a call from remote and connect\n");
+ break;
+ case REACT_REJECT:
+ fprintf(PFILE, "reject\t\t# i reject the call from remote\n");
+ break;
+ case REACT_IGNORE:
+ fprintf(PFILE, "ignore\t\t# i ignore the call from remote\n");
+ break;
+ case REACT_ANSWER:
+ fprintf(PFILE, "answer\t\t# i will start telephone answering when remote calls in\n");
+ break;
+ case REACT_CALLBACK:
+ fprintf(PFILE, "callback\t\t# when remote calls in, i will hangup and call back\n");
+ break;
+ }
+ }
+
+ if(!((cep->inout == DIR_INONLY) || (cep->usrdevicename == BDRV_TEL)))
+ fprintf(PFILE, "idletime-outgoing = %d\t\t# outgoing call idle timeout\n", cep->idle_time_out);
+
+ if(!(cep->inout == DIR_OUTONLY))
+ fprintf(PFILE, "idletime-incoming = %d\t\t# incoming call idle timeout\n", cep->idle_time_in);
+
+ if(!(cep->usrdevicename == BDRV_TEL))
+ {
+ fprintf(PFILE, "unitlengthsrc = ");
+ switch(cep->unitlengthsrc)
+ {
+ case ULSRC_NONE:
+ fprintf(PFILE, "none\t\t# no unit length specified, using default\n");
+ break;
+ case ULSRC_CMDL:
+ fprintf(PFILE, "cmdl\t\t# using unit length specified on commandline\n");
+ break;
+ case ULSRC_CONF:
+ fprintf(PFILE, "conf\t\t# using unitlength specified by unitlength-keyword\n");
+ fprintf(PFILE, "unitlength = %d\t\t# fixed unitlength\n", cep->unitlength);
+ break;
+ case ULSRC_RATE:
+ fprintf(PFILE, "rate\t\t# using unitlength specified in rate database\n");
+ fprintf(PFILE, "ratetype = %d\t\t# type of rate from rate database\n", cep->ratetype);
+ break;
+ case ULSRC_DYN:
+ fprintf(PFILE, "aocd\t\t# using dynamically calculated unitlength based on AOCD subscription\n");
+ fprintf(PFILE, "ratetype = %d\t\t# type of rate from rate database\n", cep->ratetype);
+ break;
+ }
+
+ fprintf(PFILE, "earlyhangup = %d\t\t# early hangup safety time\n", cep->earlyhangup);
+
+ }
+
+ if(cep->usrdevicename == BDRV_TEL)
+ {
+ fprintf(PFILE, "answerprog = %s\t\t# program used to answer incoming telephone calls\n", cep->answerprog);
+ fprintf(PFILE, "alert = %d\t\t# number of seconds to wait before accepting a call\n", cep->alert);
+ }
+
+ if(!(cep->usrdevicename == BDRV_TEL))
+ {
+ if(cep->dialin_reaction == REACT_CALLBACK)
+ fprintf(PFILE, "callbackwait = %d\t\t# i am waiting this time before calling back remote\n", cep->callbackwait);
+
+ if(cep->dialouttype == DIALOUT_CALLEDBACK)
+ fprintf(PFILE, "calledbackwait = %d\t\t# i am waiting this time for a call back from remote\n", cep->calledbackwait);
+
+ if(!(cep->inout == DIR_INONLY))
+ {
+ fprintf(PFILE, "dialretries = %d\t\t# number of dialing retries\n", cep->dialretries);
+ fprintf(PFILE, "recoverytime = %d\t\t# time to wait between dialling retries\n", cep->recoverytime);
+ fprintf(PFILE, "dialrandincr = %s\t\t# use random dialing time addon\n", cep->dialrandincr ? "on" : "off");
+
+ fprintf(PFILE, "usedown = %s\n", cep->usedown ? "on\t\t# ISDN device switched off on excessive dial failures" : "off\t\t# no device switchoff on excessive dial failures");
+ if(cep->usedown)
+ {
+ fprintf(PFILE, "downtries = %d\t\t# number of dialretries failures before switching off\n", cep->downtries);
+ fprintf(PFILE, "downtime = %d\t\t# time device is switched off\n", cep->downtime);
+ }
+ }
+ }
+ }
+ fprintf(PFILE, "\n");
+}
+
+/* EOF */
diff --git a/usr.sbin/i4b/isdnd/rc_parse.y b/usr.sbin/i4b/isdnd/rc_parse.y
new file mode 100644
index 0000000..6c1cf14
--- /dev/null
+++ b/usr.sbin/i4b/isdnd/rc_parse.y
@@ -0,0 +1,388 @@
+/*
+ * Copyright (c) 1997 Joerg Wunsch. All rights reserved.
+ *
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * i4b daemon - runtime configuration parser
+ * -----------------------------------------
+ *
+ * $Id: rc_parse.y,v 1.15 1998/12/05 18:03:38 hm Exp $
+ *
+ * last edit-date: [Sat Dec 5 18:12:26 1998]
+ *
+ *---------------------------------------------------------------------------*/
+
+%{
+
+/* #define YYDEBUG 1 */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include "monitor.h" /* monitor access rights bit definitions */
+#include "isdnd.h"
+
+#ifndef FALSE
+# define FALSE 0
+#endif
+
+#ifndef TRUE
+# define TRUE 1
+#endif
+
+extern void cfg_setval(int keyword);
+extern void reset_scanner(FILE *infile);
+extern void yyerror(const char *msg);
+extern int yylex();
+
+extern int lineno;
+extern char *yytext;
+extern int nentries;
+
+int saw_system = 0;
+int entrycount = -1;
+
+%}
+
+%token ACCTALL
+%token ACCTFILE
+%token ALERT
+%token ALIASING
+%token ALIASFNAME
+%token ANSWERPROG
+%token B1PROTOCOL
+%token CALLBACKWAIT
+%token CALLEDBACKWAIT
+%token CONNECTPROG
+%token DIALRETRIES
+%token DIALRANDINCR
+%token DIALOUTTYPE
+%token DIRECTION
+%token DISCONNECTPROG
+%token DOWNTRIES
+%token DOWNTIME
+%token EARLYHANGUP
+%token ENTRY
+%token IDLETIME_IN
+%token IDLETIME_OUT
+%token ISDNCONTROLLER
+%token ISDNCHANNEL
+%token ISDNTIME
+%token ISDNTXDELIN
+%token ISDNTXDELOUT
+%token LOCAL_PHONE_DIALOUT
+%token LOCAL_PHONE_INCOMING
+%token MONITORSW
+%token MONITORPORT
+%token MONITOR
+%token MONITORACCESS
+%token FULLCMD
+%token RESTRICTEDCMD
+%token CHANNELSTATE
+%token CALLIN
+%token CALLOUT
+%token LOGEVENTS
+%token NAME
+%token NO
+%token OFF
+%token ON
+%token RATESFILE
+%token RATETYPE
+%token REMOTE_NUMBERS_HANDLING
+%token REMOTE_PHONE_INCOMING
+%token REMOTE_PHONE_DIALOUT
+%token REACTION
+%token RECOVERYTIME
+%token REGEXPR
+%token REGPROG
+%token RTPRIO
+%token SYSTEM
+%token UNITLENGTH
+%token UNITLENGTHSRC
+%token USEACCTFILE
+%token USRDEVICENAME
+%token USRDEVICEUNIT
+%token USEDOWN
+%token YES
+
+%token <str> NUMBERSTR
+
+%token <str> STRING
+
+%type <booln> boolean
+
+%type <num> sysfilekeyword sysnumkeyword sysstrkeyword sysboolkeyword
+%type <num> numkeyword strkeyword boolkeyword monrights monright
+%type <str> filename
+
+%union {
+ int booln;
+ int num;
+ char *str;
+}
+
+%%
+
+config: sections
+ ;
+
+sections: possible_nullentries
+ syssect
+ entrysects
+ ;
+
+possible_nullentries:
+ /* lambda */
+ | possible_nullentries error '\n'
+ | possible_nullentries nullentry
+ ;
+
+nullentry: '\n'
+ ;
+
+entrysects: entrysect
+ | entrysects entrysect
+ ;
+
+syssect: SYSTEM sysentries
+ ;
+
+sysentries: sysentry
+ {
+ saw_system = 1;
+ monitor_clear_rights();
+ }
+ | sysentries sysentry
+ ;
+
+sysentry: sysfileentry
+ | sysboolentry
+ | sysnumentry
+ | sysstrentry
+ | sysmonitorstart
+ | sysmonitorrights
+ | nullentry
+ | error '\n'
+ ;
+
+
+sysmonitorstart:
+ MONITOR '=' STRING '\n'
+ {
+ char *err = NULL;
+ switch (monitor_start_rights($3)) {
+ case I4BMAR_OK:
+ break;
+ case I4BMAR_LENGTH:
+ err = "local socket name too long: %s";
+ break;
+ case I4BMAR_DUP:
+ err = "duplicate entry: %s";
+ break;
+ case I4BMAR_CIDR:
+ err = "invalid CIDR specification: %s";
+ break;
+ case I4BMAR_NOIP:
+ err = "could not resolve host or net specification: %s";
+ break;
+ }
+ if (err) {
+ char msg[1024];
+ snprintf(msg, sizeof msg, err, $3);
+ yyerror(msg);
+ }
+ }
+ ;
+
+sysmonitorrights:
+ MONITORACCESS '=' monrights '\n'
+ { monitor_add_rights($3); }
+ ;
+
+monrights: monrights ',' monright { $$ = $1 | $3; }
+ | monright { $$ = $1; }
+ ;
+
+monright: FULLCMD { $$ = I4B_CA_COMMAND_FULL; }
+ | RESTRICTEDCMD { $$ = I4B_CA_COMMAND_RESTRICTED; }
+ | CHANNELSTATE { $$ = I4B_CA_EVNT_CHANSTATE; }
+ | CALLIN { $$ = I4B_CA_EVNT_CALLIN; }
+ | CALLOUT { $$ = I4B_CA_EVNT_CALLOUT; }
+ | LOGEVENTS { $$ = I4B_CA_EVNT_I4B; }
+ ;
+
+sysfileentry: sysfilekeyword '=' filename '\n'
+ {
+ cfg_setval($1);
+ }
+ ;
+
+sysboolentry: sysboolkeyword '=' boolean '\n'
+ {
+ yylval.booln = $3;
+ cfg_setval($1);
+ }
+ ;
+
+sysnumentry: sysnumkeyword '=' NUMBERSTR '\n'
+ {
+ yylval.num = atoi($3);
+ cfg_setval($1);
+ }
+ ;
+
+sysstrentry: sysstrkeyword '=' STRING '\n'
+ {
+ cfg_setval($1);
+ }
+ | sysstrkeyword '=' NUMBERSTR '\n'
+ {
+ cfg_setval($1);
+ }
+ ;
+
+filename: STRING {
+ if ($1[0] != '/')
+ {
+ yyerror("filename doesn't start with a slash");
+ YYERROR;
+ }
+ $$ = $1;
+ }
+ ;
+
+boolean: NO { $$ = FALSE; }
+ | OFF { $$ = FALSE; }
+ | ON { $$ = TRUE; }
+ | YES { $$ = TRUE; }
+ ;
+
+sysfilekeyword: RATESFILE { $$ = RATESFILE; }
+ | ACCTFILE { $$ = ACCTFILE; }
+ | ALIASFNAME { $$ = ALIASFNAME; }
+ ;
+
+sysboolkeyword: USEACCTFILE { $$ = USEACCTFILE; }
+ | ALIASING { $$ = ALIASING; }
+ | ACCTALL { $$ = ACCTALL; }
+ | ISDNTIME { $$ = ISDNTIME; }
+ | MONITORSW { $$ = MONITORSW; }
+ ;
+
+sysnumkeyword: MONITORPORT { $$ = MONITORPORT; }
+ | RTPRIO { $$ = RTPRIO; }
+ ;
+
+sysstrkeyword: REGEXPR { $$ = REGEXPR; }
+ | REGPROG { $$ = REGPROG; }
+ ;
+
+entrysect: ENTRY
+ {
+ entrycount++;
+ nentries++;
+ }
+ entries
+ ;
+
+entries: entry
+ | entries entry
+ ;
+
+entry: strentry
+ | numentry
+ | boolentry
+ | nullentry
+ | error '\n'
+ ;
+
+strentry: strkeyword '=' STRING '\n'
+ {
+ cfg_setval($1);
+ }
+ | strkeyword '=' NUMBERSTR '\n'
+ {
+ cfg_setval($1);
+ }
+ ;
+
+boolentry: boolkeyword '=' boolean '\n'
+ {
+ yylval.booln = $3;
+ cfg_setval($1);
+ }
+ ;
+
+numentry: numkeyword '=' NUMBERSTR '\n'
+ {
+ yylval.num = atoi($3);
+ cfg_setval($1);
+ }
+ ;
+
+strkeyword: ANSWERPROG { $$ = ANSWERPROG; }
+ | B1PROTOCOL { $$ = B1PROTOCOL; }
+ | CONNECTPROG { $$ = CONNECTPROG; }
+ | DIALOUTTYPE { $$ = DIALOUTTYPE; }
+ | DIRECTION { $$ = DIRECTION; }
+ | DISCONNECTPROG { $$ = DISCONNECTPROG; }
+ | LOCAL_PHONE_INCOMING { $$ = LOCAL_PHONE_INCOMING; }
+ | LOCAL_PHONE_DIALOUT { $$ = LOCAL_PHONE_DIALOUT; }
+ | NAME { $$ = NAME; }
+ | REACTION { $$ = REACTION; }
+ | REMOTE_NUMBERS_HANDLING { $$ = REMOTE_NUMBERS_HANDLING; }
+ | REMOTE_PHONE_INCOMING { $$ = REMOTE_PHONE_INCOMING; }
+ | REMOTE_PHONE_DIALOUT { $$ = REMOTE_PHONE_DIALOUT; }
+ | UNITLENGTHSRC { $$ = UNITLENGTHSRC; }
+ | USRDEVICENAME { $$ = USRDEVICENAME; }
+ ;
+
+numkeyword: ALERT { $$ = ALERT; }
+ | CALLBACKWAIT { $$ = CALLBACKWAIT; }
+ | CALLEDBACKWAIT { $$ = CALLEDBACKWAIT; }
+ | DIALRETRIES { $$ = DIALRETRIES; }
+ | EARLYHANGUP { $$ = EARLYHANGUP; }
+ | IDLETIME_IN { $$ = IDLETIME_IN; }
+ | IDLETIME_OUT { $$ = IDLETIME_OUT; }
+ | ISDNCONTROLLER { $$ = ISDNCONTROLLER; }
+ | ISDNCHANNEL { $$ = ISDNCHANNEL; }
+ | ISDNTXDELIN { $$ = ISDNTXDELIN; }
+ | ISDNTXDELOUT { $$ = ISDNTXDELOUT; }
+ | RATETYPE { $$ = RATETYPE; }
+ | RECOVERYTIME { $$ = RECOVERYTIME; }
+ | UNITLENGTH { $$ = UNITLENGTH; }
+ | USRDEVICEUNIT { $$ = USRDEVICEUNIT; }
+ | DOWNTIME { $$ = DOWNTIME; }
+ | DOWNTRIES { $$ = DOWNTRIES; }
+ ;
+
+boolkeyword: DIALRANDINCR { $$ = DIALRANDINCR; }
+ | USEDOWN { $$ = USEDOWN; }
+ ;
+
+%%
diff --git a/usr.sbin/i4b/isdnd/rc_scan.l b/usr.sbin/i4b/isdnd/rc_scan.l
new file mode 100644
index 0000000..dfca28c
--- /dev/null
+++ b/usr.sbin/i4b/isdnd/rc_scan.l
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 1997 Joerg Wunsch. All rights reserved.
+ *
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * i4b daemon - runtime configuration lexical analyzer
+ * ---------------------------------------------------
+ *
+ * $Id: rc_scan.l,v 1.19 1998/12/18 17:17:57 hm Exp $
+ *
+ * last edit-date: [Fri Dec 18 18:08:25 1998]
+ *
+ *---------------------------------------------------------------------------*/
+
+%{
+
+#include <err.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <sysexits.h>
+
+#include "y.tab.h"
+
+int lineno;
+
+%}
+
+%option noyywrap
+%option nounput
+
+%%
+
+#.*$ { /*
+ * Drop comment. NB: this prevents a hash
+ * sign from appearing inside a quoted string.
+ */
+ }
+
+["][^"]*["] {
+ char *str;
+ if ((str = malloc(yyleng - 1)) == 0)
+ errx(EX_OSERR, "Out of virtual memory");
+ memcpy(str, yytext + 1, yyleng - 2);
+ str[yyleng - 2] = 0;
+ yylval.str = str;
+ return STRING;
+ }
+
+(-*[0-9]+)|\* {
+ char *str;
+ char *p = yytext;
+ int i = 0;
+ if ((str = malloc(128)) == 0)
+ errx(EX_OSERR, "Out of virtual memory");
+ while(*p == '-' || isdigit(*p) || *p == '*')
+ str[i++] = *p++;
+ str[i] = '\0';
+ yylval.str = str;
+ return NUMBERSTR;
+ }
+
+acctall { return ACCTALL; }
+acctfile { return ACCTFILE; }
+alert { return ALERT; }
+aliasing { return ALIASING; }
+aliasfile { return ALIASFNAME; }
+answerprog { return ANSWERPROG; }
+b1protocol { return B1PROTOCOL; }
+callbackwait { return CALLBACKWAIT; }
+calledbackwait { return CALLEDBACKWAIT; }
+connectprog { return CONNECTPROG; }
+dialin-reaction { return REACTION; }
+dialout-type { return DIALOUTTYPE; }
+dialrandincr { return DIALRANDINCR; }
+dialretries { return DIALRETRIES; }
+direction { return DIRECTION; }
+disconnectprog { return DISCONNECTPROG; }
+downtries { return DOWNTRIES; }
+downtime { return DOWNTIME; }
+earlyhangup { return EARLYHANGUP; }
+entry { return ENTRY; }
+idletime-incoming { return IDLETIME_IN; }
+idletime-outgoing { return IDLETIME_OUT; }
+isdncontroller { return ISDNCONTROLLER; }
+isdnchannel { return ISDNCHANNEL; }
+isdntime { return ISDNTIME; }
+isdntxdel-incoming { return ISDNTXDELIN; }
+isdntxdel-outgoing { return ISDNTXDELOUT; }
+local-phone-dialout { return LOCAL_PHONE_DIALOUT; }
+local-phone-incoming { return LOCAL_PHONE_INCOMING; }
+monitor-allowed { return MONITORSW; }
+monitor-port { return MONITORPORT; }
+monitor { return MONITOR; }
+monitor-access { return MONITORACCESS; }
+fullcmd { return FULLCMD; }
+restrictedcmd { return RESTRICTEDCMD; }
+channelstate { return CHANNELSTATE; }
+callin { return CALLIN; }
+callout { return CALLOUT; }
+logevents { return LOGEVENTS; }
+name { return NAME; }
+no { return NO; }
+off { return OFF; }
+on { return ON; }
+ratesfile { return RATESFILE; }
+ratetype { return RATETYPE; }
+recoverytime { return RECOVERYTIME; }
+regexpr { return REGEXPR; }
+regprog { return REGPROG; }
+remdial-handling { return REMOTE_NUMBERS_HANDLING; }
+remote-phone-dialout { return REMOTE_PHONE_DIALOUT; }
+remote-phone-incoming { return REMOTE_PHONE_INCOMING; }
+rtprio { return RTPRIO; }
+system { return SYSTEM; }
+unitlength { return UNITLENGTH; }
+unitlengthsrc { return UNITLENGTHSRC; }
+useacctfile { return USEACCTFILE; }
+usrdevicename { return USRDEVICENAME; }
+usrdeviceunit { return USRDEVICEUNIT; }
+usedown { return USEDOWN; }
+yes { return YES; }
+
+\n { lineno++; return '\n'; }
+
+[A-Za-z/.][-A-Za-z0-9_/.]* {
+ char *str;
+ if ((str = strdup(yytext)) == 0)
+ err(EX_OSERR, "Out of virtual memory");
+ yylval.str = str;
+ return STRING;
+ }
+
+[ \t] { /* drop white space */ }
+
+. { return yytext[0]; }
+
+%%
+
+void
+reset_scanner(FILE *infile)
+{
+ yyrestart(infile);
+ lineno = 1;
+}
diff --git a/usr.sbin/i4b/isdnd/support.c b/usr.sbin/i4b/isdnd/support.c
new file mode 100644
index 0000000..77c0841
--- /dev/null
+++ b/usr.sbin/i4b/isdnd/support.c
@@ -0,0 +1,831 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * i4b daemon - misc support routines
+ * ----------------------------------
+ *
+ * $Id: support.c,v 1.43 1998/12/18 09:47:09 hm Exp $
+ *
+ * last edit-date: [Mon Dec 14 11:17:22 1998]
+ *
+ *---------------------------------------------------------------------------*/
+
+#include "isdnd.h"
+
+#define SRC (aliasing == 0 ? mp->src_telno : src_tela)
+#define DST (aliasing == 0 ? mp->dst_telno : dst_tela)
+
+/*---------------------------------------------------------------------------*
+ * find an active entry by driver type and driver unit
+ *---------------------------------------------------------------------------*/
+cfg_entry_t *
+find_active_entry_by_driver(int drivertype, int driverunit)
+{
+ cfg_entry_t *cep = NULL;
+ int i;
+
+ for(i=0; i < nentries; i++)
+ {
+ cep = &cfg_entry_tab[i]; /* ptr to config entry */
+
+ if(!((cep->usrdevicename == drivertype) &&
+ (cep->usrdeviceunit == driverunit)))
+ {
+ continue;
+ }
+
+ /* found */
+
+ if(cep->cdid == CDID_UNUSED)
+ {
+ DBGL(DL_MSG, (log(LL_DBG, "find_active_entry_by_driver: entry %d, cdid is CDID_UNUSED!", i)));
+ return(NULL);
+ }
+ else if(cep->cdid == CDID_RESERVED)
+ {
+ DBGL(DL_MSG, (log(LL_DBG, "find_active_entry_by_driver: entry %d, cdid is CDID_RESERVED!", i)));
+ return(NULL);
+ }
+ return(cep);
+ }
+ return(NULL);
+}
+
+/*---------------------------------------------------------------------------*
+ * find entry by drivertype and driverunit and setup for dialing out
+ *---------------------------------------------------------------------------*/
+cfg_entry_t *
+find_by_device_for_dialout(int drivertype, int driverunit)
+{
+ cfg_entry_t *cep = NULL;
+ int i;
+
+ for(i=0; i < nentries; i++)
+ {
+ cep = &cfg_entry_tab[i]; /* ptr to config entry */
+
+ /* compare driver type and unit */
+
+ if(!((cep->usrdevicename == drivertype) &&
+ (cep->usrdeviceunit == driverunit)))
+ {
+ continue;
+ }
+
+ /* found, check if already reserved */
+
+ if(cep->cdid == CDID_RESERVED)
+ {
+ DBGL(DL_MSG, (log(LL_DBG, "find_by_device_for_dialout: entry %d, cdid reserved!", i)));
+ return(NULL);
+ }
+
+ /* check if this entry is already in use ? */
+
+ if(cep->cdid != CDID_UNUSED)
+ {
+ DBGL(DL_MSG, (log(LL_DBG, "find_by_device_for_dialout: entry %d, cdid in use", i)));
+ return(NULL);
+ }
+
+ if((setup_dialout(cep)) == GOOD)
+ {
+ /* found an entry to be used for calling out */
+
+ DBGL(DL_MSG, (log(LL_DBG, "find_by_device_for_dialout: found entry %d!", i)));
+ return(cep);
+ }
+ else
+ {
+ DBGL(DL_MSG, (log(LL_DBG, "find_by_device_for_dialout: entry %d, setup_dialout() failed!", i)));
+ return(NULL);
+ }
+ }
+
+ DBGL(DL_MSG, (log(LL_DBG, "find_by_device_for_dialout: no entry found!")));
+ return(NULL);
+}
+
+/*---------------------------------------------------------------------------*
+ * find entry by drivertype and driverunit and setup for dialing out
+ *---------------------------------------------------------------------------*/
+int
+setup_dialout(cfg_entry_t *cep)
+{
+ /* check controller operational */
+
+ if((get_controller_state(cep->isdncontroller)) != CTRL_UP)
+ {
+ DBGL(DL_MSG, (log(LL_DBG, "setup_dialout: entry %s, controller is down", cep->name)));
+ return(ERROR);
+ }
+
+ cep->isdncontrollerused = cep->isdncontroller;
+
+ /* check channel available */
+
+ switch(cep->isdnchannel)
+ {
+ case CHAN_B1:
+ case CHAN_B2:
+ if((ret_channel_state(cep->isdncontroller, cep->isdnchannel)) != CHAN_IDLE)
+ {
+ DBGL(DL_MSG, (log(LL_DBG, "setup_dialout: entry %s, channel not free", cep->name)));
+ return(ERROR);
+ }
+ cep->isdnchannelused = cep->isdnchannel;
+ break;
+
+ case CHAN_ANY:
+ if(((ret_channel_state(cep->isdncontroller, CHAN_B1)) != CHAN_IDLE) &&
+ ((ret_channel_state(cep->isdncontroller, CHAN_B2)) != CHAN_IDLE))
+ {
+ DBGL(DL_MSG, (log(LL_DBG, "setup_dialout: entry %s, no channel free", cep->name)));
+ return(ERROR);
+ }
+ cep->isdnchannelused = CHAN_ANY;
+ break;
+
+ default:
+ DBGL(DL_MSG, (log(LL_DBG, "setup_dialout: entry %s, channel undefined", cep->name)));
+ return(ERROR);
+ break;
+ }
+
+ DBGL(DL_MSG, (log(LL_DBG, "setup_dialout: entry %s ok!", cep->name)));
+
+ /* preset disconnect cause */
+
+ SET_CAUSE_TYPE(cep->disc_cause, CAUSET_I4B);
+ SET_CAUSE_VAL(cep->disc_cause, CAUSE_I4B_NORMAL);
+
+ return(GOOD);
+}
+
+/*---------------------------------------------------------------------------*
+ * find entry by drivertype and driverunit
+ *---------------------------------------------------------------------------*/
+cfg_entry_t *
+get_cep_by_driver(int drivertype, int driverunit)
+{
+ cfg_entry_t *cep = NULL;
+ int i;
+
+ for(i=0; i < nentries; i++)
+ {
+ cep = &cfg_entry_tab[i]; /* ptr to config entry */
+
+ if(!((cep->usrdevicename == drivertype) &&
+ (cep->usrdeviceunit == driverunit)))
+ {
+ continue;
+ }
+
+ DBGL(DL_MSG, (log(LL_DBG, "get_cep_by_driver: found entry %d!", i)));
+ return(cep);
+ }
+ return(NULL);
+}
+
+/*---------------------------------------------------------------------------*
+ * find a matching entry for an incoming call
+ *
+ * - not found/no match: log output with LL_CHD and return NULL
+ * - found/match: make entry in free cep, return address
+ *---------------------------------------------------------------------------*/
+cfg_entry_t *
+find_matching_entry_incoming(msg_connect_ind_t *mp)
+{
+ cfg_entry_t *cep = NULL;
+ int i;
+ char *src_tela = "ERROR-src_tela";
+ char *dst_tela = "ERROR-dst_tela";
+
+ for(i=0; i < nentries; i++)
+ {
+ int n;
+ cep = &cfg_entry_tab[i]; /* ptr to config entry */
+
+ /* check my number */
+
+ if(strncmp(cep->local_phone_incoming, mp->dst_telno, strlen(cep->local_phone_incoming)))
+ {
+ DBGL(DL_MSG, (log(LL_DBG, "find_matching_entry_incoming: entry %d, myno %s != incomingno %s", i,
+ cep->local_phone_incoming, mp->dst_telno)));
+ continue;
+ }
+
+ /* check all allowed remote number's for this entry */
+
+ for (n = 0; n < cep->incoming_numbers_count; n++)
+ {
+ incoming_number_t *in = &cep->remote_phone_incoming[n];
+ if(in->number[0] == '*')
+ break;
+ if(strncmp(in->number, mp->src_telno, strlen(in->number)))
+ {
+ DBGL(DL_MSG, (log(LL_DBG, "find_matching_entry_incoming: entry %d, remno %s != incomingfromno %s", i,
+ in->number, mp->src_telno)));
+ }
+ else
+ break;
+ }
+ if (n >= cep->incoming_numbers_count)
+ continue;
+
+ /* screening indicator XXX */
+
+ switch(mp->scr_ind)
+ {
+ case SCR_NONE:
+ DBGL(DL_MSG, (log(LL_DBG, "find_matching_entry_incoming: %s - no screening indicator", mp->src_telno)));
+ break;
+
+ case SCR_USR_NOSC:
+ DBGL(DL_MSG, (log(LL_DBG, "find_matching_entry_incoming: %s - screening user provided, not screened", mp->src_telno)));
+ break;
+
+ case SCR_USR_PASS:
+ DBGL(DL_MSG, (log(LL_DBG, "find_matching_entry_incoming: %s - screening user provided, verified & passed", mp->src_telno)));
+ break;
+
+ case SCR_USR_FAIL:
+ DBGL(DL_MSG, (log(LL_DBG, "find_matching_entry_incoming: %s - screening user provided, verified & failed", mp->src_telno)));
+ break;
+
+ case SCR_NET:
+ DBGL(DL_MSG, (log(LL_DBG, "find_matching_entry_incoming: %s - screening network provided", mp->src_telno)));
+ break;
+
+ default:
+ DBGL(DL_MSG, (log(LL_DBG, "find_matching_entry_incoming: ERROR %s - invalid screening indicator!", mp->src_telno)));
+ break;
+ }
+
+ /* check b protocol */
+
+ if(cep->b1protocol != mp->bprot)
+ {
+ DBGL(DL_MSG, (log(LL_DBG, "find_matching_entry_incoming: entry %d, bprot %d != incomingprot %d", i,
+ cep->b1protocol, mp->bprot)));
+ continue;
+ }
+
+ /* is this entry currently in use ? */
+
+ if(cep->cdid != CDID_UNUSED)
+ {
+ if(cep->cdid == CDID_RESERVED)
+ {
+ DBGL(DL_MSG, (log(LL_DBG, "find_matching_entry_incoming: entry %d, cdid is reserved", i)));
+ }
+ else if (cep->dialin_reaction == REACT_ACCEPT
+ && cep->dialouttype == DIALOUT_CALLEDBACK)
+ {
+ /*
+ * We might consider doing this even if this is
+ * not a calledback config entry - BUT: there are
+ * severe race conditions and timinig problems
+ * ex. if both sides run I4B with no callback
+ * delay - both may shutdown the outgoing call
+ * and never be able to establish a connection.
+ * In the called-back case this should not happen.
+ */
+ DBGL(DL_MSG, (log(LL_DBG, "find_matching_entry_incoming: entry %d, incoming call for callback in progress (cdid %05d)", i, cep->cdid)));
+
+ /* save the current call state, we're going to overwrite it with the
+ * new incoming state below... */
+ cep->saved_call.cdid = cep->cdid;
+ cep->saved_call.controller = cep->isdncontrollerused;
+ cep->saved_call.channel = cep->isdnchannelused;
+ }
+ else
+ {
+ DBGL(DL_MSG, (log(LL_DBG, "find_matching_entry_incoming: entry %d, cdid in use", i)));
+ continue; /* yes, next */
+ }
+ }
+
+ /* check controller value ok */
+
+ if(mp->controller > ncontroller)
+ {
+ log(LL_CHD, "%05d %s incoming call with invalid controller %d",
+ mp->header.cdid, cep->name, mp->controller);
+ return(NULL);
+ }
+
+ /* check controller marked up */
+
+ if((get_controller_state(mp->controller)) != CTRL_UP)
+ {
+ log(LL_CHD, "%05d %s incoming call, controller %d DOWN!",
+ mp->header.cdid, cep->name, mp->controller);
+ return(NULL);
+ }
+
+ /* check channel he wants */
+
+ switch(mp->channel)
+ {
+ case CHAN_B1:
+ case CHAN_B2:
+ if((ret_channel_state(mp->controller, mp->channel)) != CHAN_IDLE)
+ {
+ log(LL_CHD, "%05d %s incoming call, channel %s not free!",
+ mp->header.cdid, cep->name, mp->channel == CHAN_B1 ? "B1" : "B2");
+ return(NULL);
+ }
+ break;
+
+ case CHAN_ANY:
+ if(((ret_channel_state(mp->controller, CHAN_B1)) != CHAN_IDLE) &&
+ ((ret_channel_state(mp->controller, CHAN_B2)) != CHAN_IDLE))
+ {
+ log(LL_CHD, "%05d %s incoming call, no channel free!",
+ mp->header.cdid, cep->name);
+ return(NULL);
+ }
+ break;
+
+ case CHAN_NO:
+ log(LL_CHD, "%05d %s incoming call, call waiting (no channel available)!",
+ mp->header.cdid, cep->name);
+ return(NULL);
+ break;
+
+ default:
+ log(LL_CHD, "%05d %s incoming call, ERROR, channel undefined!",
+ mp->header.cdid, cep->name);
+ return(NULL);
+ break;
+ }
+
+ /* found a matching entry */
+
+ cep->cdid = mp->header.cdid;
+ cep->isdncontrollerused = mp->controller;
+ cep->isdnchannelused = mp->channel;
+/*XXX*/ cep->disc_cause = 0;
+
+ /* cp number to real one used */
+
+ strcpy(cep->real_phone_incoming, mp->src_telno);
+
+ /* copy display string */
+
+ strcpy(cep->display, mp->display);
+
+ /* entry currently down ? */
+
+ if(cep->state == ST_DOWN)
+ {
+ msg_updown_ind_t mui;
+
+ /* set interface up */
+
+ DBGL(DL_MSG, (log(LL_DBG, "find_matching_entry_incoming: entry %d, ", i)));
+
+ mui.driver = cep->usrdevicename;
+ mui.driver_unit = cep->usrdeviceunit;
+ mui.updown = SOFT_ENA;
+
+ if((ioctl(isdnfd, I4B_UPDOWN_IND, &mui)) < 0)
+ {
+ log(LL_ERR, "find_matching_entry_incoming: ioctl I4B_UPDOWN_IND failed: %s", strerror(errno));
+ do_exit(1);
+ }
+
+ cep->down_retry_count = 0;
+ cep->state = ST_IDLE;
+ }
+ return(cep);
+ }
+
+ if(aliasing)
+ {
+ src_tela = get_alias(mp->src_telno);
+ dst_tela = get_alias(mp->dst_telno);
+ }
+ log(LL_CHD, /* A number not listed in /etc/isdn/isdnd.rc */
+ ( (!aliasing) ?
+ "%05d <unknown> incoming call from %s to %s" :
+ /* Probably a phone call, likely from someone
+ in phone book /etc/isdn/isdntel.alias, so
+ avoid looking silly by saying "unknown",
+ & allow more space to print names.
+ */
+ "%05d Call from %s to %s"
+ ) ,
+ mp->header.cdid, SRC, DST, mp->dst_telno);
+
+ return(NULL);
+}
+
+/*---------------------------------------------------------------------------*
+ * return address of ACTIVE config entry by controller and channel
+ *---------------------------------------------------------------------------*/
+cfg_entry_t *
+get_cep_by_cc(int ctrlr, int chan)
+{
+ int i;
+
+ if((chan != CHAN_B1) && (chan != CHAN_B2))
+ return(NULL);
+
+ for(i=0; i < nentries; i++)
+ {
+ if((cfg_entry_tab[i].cdid != CDID_UNUSED) &&
+ (cfg_entry_tab[i].cdid != CDID_RESERVED) &&
+ (cfg_entry_tab[i].isdnchannelused == chan) &&
+ (cfg_entry_tab[i].isdncontrollerused == ctrlr) &&
+ ((ret_channel_state(ctrlr, chan)) == CHAN_RUN))
+ {
+ return(&cfg_entry_tab[i]);
+ }
+ }
+ return(NULL);
+}
+
+/*---------------------------------------------------------------------------*
+ * return address of config entry identified by cdid
+ *---------------------------------------------------------------------------*/
+cfg_entry_t *
+get_cep_by_cdid(int cdid)
+{
+ int i;
+
+ for(i=0; i < nentries; i++)
+ {
+ if(cfg_entry_tab[i].cdid == cdid
+ || cfg_entry_tab[i].saved_call.cdid == cdid)
+ return(&cfg_entry_tab[i]);
+ }
+ return(NULL);
+}
+
+/*---------------------------------------------------------------------------*
+ * get name of a controller
+ *---------------------------------------------------------------------------*/
+const char *
+name_of_controller(int ctrl_type, int card_type)
+{
+ static char *passive_card[] = {
+ "Teles S0/8",
+ "Teles S0/16",
+ "Teles S0/16.3",
+ "AVM A1 or Fritz!Card",
+ "Teles S0/16.3 PnP",
+ "Creatix S0 PnP",
+ "USRobotics Sportster ISDN TA",
+ "Dr. Neuhaus NICCY Go@",
+ "Sedlbauer win speed",
+ "Dynalink IS64PH",
+ "ISDN Master or Blaster",
+ "AVM PCMCIA Fritz!Card",
+ "ELSA QuickStep 1000pro/ISA",
+ "ELSA QuickStep 1000pro/PCI",
+ "Siemens I-Talk",
+ "ELSA MicroLink ISDN/MC",
+ "ELSA MicroLink MCall",
+ "ITK ix1 micro"
+ };
+ static char *daic_card[] = {
+ "EICON.Diehl S",
+ "EICON.Diehl SX/SXn",
+ "EICON.Diehl SCOM",
+ "EICON.Diehl QUADRO",
+ };
+
+ if (ctrl_type == CTRL_PASSIVE) {
+ int index = card_type - CARD_TYPEP_8;
+ if (index >= 0 && index < (sizeof passive_card / sizeof passive_card[0]))
+ return passive_card[index];
+ } else if (ctrl_type == CTRL_DAIC) {
+ int index = card_type - CARD_TYPEA_DAIC_S;
+ if (index >= 0 && index < (sizeof daic_card / sizeof daic_card[0] ))
+ return daic_card[index];
+ }
+
+ return "unknown card type";
+}
+
+/*---------------------------------------------------------------------------*
+ * init controller state array
+ *---------------------------------------------------------------------------*/
+void
+init_controller(void)
+{
+ int i;
+ int max = 1;
+ msg_ctrl_info_req_t mcir;
+
+ for(i=0; i < max; i++)
+ {
+ mcir.controller = i;
+
+ if((ioctl(isdnfd, I4B_CTRL_INFO_REQ, &mcir)) < 0)
+ {
+ log(LL_ERR, "init_controller: ioctl I4B_CTRL_INFO_REQ failed: %s", strerror(errno));
+ do_exit(1);
+ }
+
+ if((ncontroller = max = mcir.ncontroller) == 0)
+ {
+ log(LL_ERR, "init_controller: no ISDN controller found!");
+ do_exit(1);
+ }
+
+ if(mcir.ctrl_type == -1 || mcir.card_type == -1)
+ {
+ log(LL_ERR, "init_controller: ctrl/card is invalid!");
+ do_exit(1);
+ }
+
+ /* init controller tab */
+
+ if((init_controller_state(i, mcir.ctrl_type, mcir.card_type, mcir.tei)) == ERROR)
+ {
+ log(LL_ERR, "init_controller: init_controller_state for controller %d failed", i);
+ do_exit(1);
+ }
+ }
+ log(LL_DMN, "init_controller: found %d ISDN controller(s)", max);
+}
+
+/*---------------------------------------------------------------------------*
+ * return b channel driver type name string
+ *---------------------------------------------------------------------------*/
+char *
+bdrivername(int drivertype)
+{
+ static char *bdtab[] = {
+ "rbch",
+ "tel",
+ "ipr",
+ "isp"
+ };
+
+ if(drivertype >= BDRV_RBCH && drivertype <= BDRV_ISPPP)
+ return(bdtab[drivertype]);
+ else
+ return("unknown");
+}
+
+/*---------------------------------------------------------------------------*
+ * process AOCD charging messages
+ *---------------------------------------------------------------------------*/
+void
+handle_charge(cfg_entry_t *cep)
+{
+ time_t now = time(NULL);
+
+ if(cep->aoc_last == 0) /* no last timestamp yet ? */
+ {
+ cep->aoc_last = now; /* add time stamp */
+ }
+ else if(cep->aoc_now == 0) /* no current timestamp yet ? */
+ {
+ cep->aoc_now = now; /* current timestamp */
+ }
+ else
+ {
+ cep->aoc_last = cep->aoc_now;
+ cep->aoc_now = now;
+ cep->aoc_diff = cep->aoc_now - cep->aoc_last;
+ cep->aoc_valid = AOC_VALID;
+ }
+
+#ifdef USE_CURSES
+ if(do_fullscreen)
+ display_charge(cep);
+#endif
+
+#ifdef I4B_EXTERNAL_MONITOR
+ if(do_monitor && accepted)
+ monitor_evnt_charge(cep, cep->charge, 0);
+#endif
+
+ if(cep->aoc_valid == AOC_VALID)
+ {
+ if(cep->aoc_diff != cep->unitlength)
+ {
+ DBGL(DL_MSG, (log(LL_DBG, "handle_charge: AOCD unit length updated %d -> %d secs", cep->unitlength, cep->aoc_diff)));
+
+ cep->unitlength = cep->aoc_diff;
+
+ unitlen_chkupd(cep);
+ }
+ else
+ {
+#ifdef NOTDEF
+ DBGL(DL_MSG, (log(LL_DBG, "handle_charge: AOCD unit length still %d secs", cep->unitlength)));
+#endif
+ }
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ *
+ *---------------------------------------------------------------------------*/
+void
+unitlen_chkupd(cfg_entry_t *cep)
+{
+ msg_timeout_upd_t tupd;
+
+/* XXX check if the values are possible, if not, adjust them */
+
+ tupd.cdid = cep->cdid;
+ tupd.unitlen_time = cep->unitlength;
+ tupd.idle_time = cep->idle_time_out;
+ tupd.earlyhup_time = cep->earlyhangup;
+
+ if((ioctl(isdnfd, I4B_TIMEOUT_UPD, &tupd)) < 0)
+ {
+ log(LL_ERR, "ioctl I4B_TIMEOUT_UPD failed: %s", strerror(errno));
+ do_exit(1);
+ }
+}
+
+/*--------------------------------------------------------------------------*
+ * this is intended to be called by do_exit and closes down all
+ * active connections before the daemon exits or is reconfigured.
+ *--------------------------------------------------------------------------*/
+void
+close_allactive(void)
+{
+ int i, j;
+ cfg_entry_t *cep = NULL;
+
+ j = 0;
+
+ for (i = 0; i < ncontroller; i++)
+ {
+ if((get_controller_state(i)) != CTRL_UP)
+ continue;
+
+ if((ret_channel_state(i, CHAN_B1)) == CHAN_RUN)
+ {
+ if((cep = get_cep_by_cc(i, CHAN_B1)) != NULL)
+ {
+#ifdef USE_CURSES
+ if(do_fullscreen)
+ display_disconnect(cep);
+#endif
+#ifdef I4B_EXTERNAL_MONITOR
+ monitor_evnt_disconnect(cep);
+#endif
+ next_state(cep, EV_DRQ);
+ j++;
+ }
+ }
+
+ if((ret_channel_state(i, CHAN_B2)) == CHAN_RUN)
+ {
+ if((cep = get_cep_by_cc(i, CHAN_B2)) != NULL)
+ {
+#ifdef USE_CURSES
+ if(do_fullscreen)
+ display_disconnect(cep);
+#endif
+#ifdef I4B_EXTERNAL_MONITOR
+ monitor_evnt_disconnect(cep);
+#endif
+ next_state(cep, EV_DRQ);
+ j++;
+ }
+ }
+ }
+
+ if(j)
+ {
+ log(LL_DMN, "close_allactive: waiting for all connections terminated");
+ sleep(5);
+ }
+}
+
+/*--------------------------------------------------------------------------*
+ * set an interface up
+ *--------------------------------------------------------------------------*/
+void
+if_up(cfg_entry_t *cep)
+{
+ msg_updown_ind_t mui;
+
+ /* set interface up */
+
+ DBGL(DL_MSG, (log(LL_DBG, "if_up: taking %s%d up", bdrivername(cep->usrdevicename), cep->usrdeviceunit)));
+
+ mui.driver = cep->usrdevicename;
+ mui.driver_unit = cep->usrdeviceunit;
+ mui.updown = SOFT_ENA;
+
+ if((ioctl(isdnfd, I4B_UPDOWN_IND, &mui)) < 0)
+ {
+ log(LL_ERR, "if_up: ioctl I4B_UPDOWN_IND failed: %s", strerror(errno));
+ do_exit(1);
+ }
+ cep->down_retry_count = 0;
+
+#ifdef USE_CURSES
+ if(do_fullscreen)
+ display_updown(cep, 1);
+#endif
+#ifdef I4B_EXTERNAL_MONITOR
+ monitor_evnt_updown(cep, 1);
+#endif
+
+}
+
+/*--------------------------------------------------------------------------*
+ * set an interface down
+ *--------------------------------------------------------------------------*/
+void
+if_down(cfg_entry_t *cep)
+{
+ msg_updown_ind_t mui;
+
+ /* set interface up */
+
+ DBGL(DL_MSG, (log(LL_DBG, "if_down: taking %s%d down", bdrivername(cep->usrdevicename), cep->usrdeviceunit)));
+
+ mui.driver = cep->usrdevicename;
+ mui.driver_unit = cep->usrdeviceunit;
+ mui.updown = SOFT_DIS;
+
+ if((ioctl(isdnfd, I4B_UPDOWN_IND, &mui)) < 0)
+ {
+ log(LL_ERR, "if_down: ioctl I4B_UPDOWN_IND failed: %s", strerror(errno));
+ do_exit(1);
+ }
+ cep->went_down_time = time(NULL);
+ cep->down_retry_count = 0;
+
+#ifdef USE_CURSES
+ if(do_fullscreen)
+ display_updown(cep, 0);
+#endif
+#ifdef I4B_EXTERNAL_MONITOR
+ monitor_evnt_updown(cep, 0);
+#endif
+
+}
+
+/*--------------------------------------------------------------------------*
+ * send a dial response to (an interface in) the kernel
+ *--------------------------------------------------------------------------*/
+void
+dialresponse(cfg_entry_t *cep, int dstat)
+{
+ msg_dialout_resp_t mdr;
+
+ static char *stattab[] = {
+ "normal condition",
+ "temporary failure",
+ "permanent failure",
+ "dialout not allowed"
+ };
+
+ if(dstat < DSTAT_NONE || dstat > DSTAT_INONLY)
+ {
+ log(LL_ERR, "dialresponse: dstat out of range %d!", dstat);
+ return;
+ }
+
+ mdr.driver = cep->usrdevicename;
+ mdr.driver_unit = cep->usrdeviceunit;
+ mdr.stat = dstat;
+
+ if((ioctl(isdnfd, I4B_DIALOUT_RESP, &mdr)) < 0)
+ {
+ log(LL_ERR, "dialresponse: ioctl I4B_DIALOUT_RESP failed: %s", strerror(errno));
+ do_exit(1);
+ }
+
+ DBGL(DL_DRVR, (log(LL_DBG, "dialresponse: sent [%s]", stattab[dstat])));
+}
+/* EOF */
+
diff --git a/usr.sbin/i4b/isdnd/timer.c b/usr.sbin/i4b/isdnd/timer.c
new file mode 100644
index 0000000..5534efe
--- /dev/null
+++ b/usr.sbin/i4b/isdnd/timer.c
@@ -0,0 +1,411 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * i4b daemon - timer/timing support routines
+ * ------------------------------------------
+ *
+ * $Id: timer.c,v 1.16 1998/12/05 18:03:43 hm Exp $
+ *
+ * last edit-date: [Sat Dec 5 18:13:10 1998]
+ *
+ *---------------------------------------------------------------------------*/
+
+#include "isdnd.h"
+
+static int hr_callgate(void);
+static void handle_reserved(cfg_entry_t *cep, time_t now);
+static void handle_active(cfg_entry_t *cep, time_t now);
+static void recover_illegal(cfg_entry_t *cep);
+
+/*---------------------------------------------------------------------------*
+ * recover from illegal state
+ *---------------------------------------------------------------------------*/
+static void
+recover_illegal(cfg_entry_t *cep)
+{
+ log(LL_ERR, "recover_illegal: ERROR, entry %s attempting disconnect!", cep->name);
+ sendm_disconnect_req(cep, (CAUSET_I4B << 8) | CAUSE_I4B_NORMAL);
+ log(LL_ERR, "recover_illegal: ERROR, entry %s - reset state/cdid!", cep->name);
+ cep->state = ST_IDLE;
+ cep->cdid = CDID_UNUSED;
+}
+
+/*---------------------------------------------------------------------------*
+ * start the timer
+ *---------------------------------------------------------------------------*/
+void
+start_timer(cfg_entry_t *cep, int seconds)
+{
+ cep->timerval = cep->timerremain = seconds;
+}
+
+/*---------------------------------------------------------------------------*
+ * stop the timer
+ *---------------------------------------------------------------------------*/
+void
+stop_timer(cfg_entry_t *cep)
+{
+ cep->timerval = cep->timerremain = 0;
+}
+
+/*---------------------------------------------------------------------------*
+ * callgate for handle_recovery()
+ *---------------------------------------------------------------------------*/
+static int
+hr_callgate(void)
+{
+ static int tv_first = 1;
+ static struct timeval tv_last;
+ struct timeval tv_now;
+
+ /* there must be 1 sec minimum between calls to this section */
+
+ if(tv_first)
+ {
+ gettimeofday(&tv_last, NULL);
+ tv_first = 0;
+ }
+
+ gettimeofday(&tv_now, NULL);
+
+ if((tv_now.tv_sec - tv_last.tv_sec) < 1)
+ {
+
+ DBGL(DL_TIME, (log(LL_DBG, "time < 1 - last %ld:%ld now %ld:%ld",
+ tv_last.tv_sec, tv_last.tv_usec,
+ tv_now.tv_sec, tv_now.tv_usec)));
+ return(1);
+ }
+ else if((tv_now.tv_sec - tv_last.tv_sec) == 1)
+ {
+ if(((1000000 - tv_last.tv_usec) + tv_now.tv_usec) < 900000)
+ {
+ DBGL(DL_TIME, (log(LL_DBG, "time < 900000us - last %ld:%ld now %ld:%ld",
+ tv_last.tv_sec, tv_last.tv_usec,
+ tv_now.tv_sec, tv_now.tv_usec)));
+ return(1);
+ }
+ }
+
+ DBGL(DL_TIME, (log(LL_DBG, "time OK! - last %ld:%ld now %ld:%ld",
+ tv_last.tv_sec, tv_last.tv_usec,
+ tv_now.tv_sec, tv_now.tv_usec)));
+
+ gettimeofday(&tv_last, NULL);
+
+ return(0);
+}
+
+/*---------------------------------------------------------------------------*
+ * timeout, recovery and retry handling
+ *---------------------------------------------------------------------------*/
+void
+handle_recovery(void)
+{
+ cfg_entry_t *cep = NULL;
+ int i;
+ time_t now;
+
+ if(hr_callgate()) /* last call to handle_recovery < 1 sec ? */
+ return; /* yes, exit */
+
+ now = time(NULL); /* get current time */
+
+ /* walk thru all entries, look for work to do */
+
+ for(i=0; i < nentries; i++)
+ {
+ cep = &cfg_entry_tab[i]; /* ptr to config entry */
+
+ switch(cep->cdid)
+ {
+ case CDID_UNUSED: /* entry unused */
+ continue;
+ break;
+
+ case CDID_RESERVED: /* entry reserved */
+ handle_reserved(cep, now);
+ break;
+
+ default: /* entry in use */
+ handle_active(cep, now);
+ break;
+ }
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * timeout, recovery and retry handling for active entry
+ *---------------------------------------------------------------------------*/
+static void
+handle_active(cfg_entry_t *cep, time_t now)
+{
+ switch(cep->state)
+ {
+ case ST_ACCEPTED:
+ if(cep->timerval && (--(cep->timerremain)) <= 0)
+ {
+ DBGL(DL_RCVRY, (log(LL_DBG, "handle_active: entry %s, TIMEOUT !!!", cep->name)));
+ cep->timerval = cep->timerremain = 0;
+ next_state(cep, EV_TIMO);
+ }
+ break;
+
+ case ST_ALERT:
+ if(cep->alert_time > 0)
+ {
+ cep->alert_time--;
+ }
+ else
+ {
+ log(LL_CHD, "%05d %s answering: incoming call from %s to %s",
+ cep->cdid, cep->name,
+ cep->real_phone_incoming,
+ cep->local_phone_incoming);
+ next_state(cep, EV_MCI);
+ }
+ break;
+
+ case ST_ILL:
+ recover_illegal(cep);
+ break;
+
+ default:
+ /* check hangup flag: if active, close connection */
+
+ if(cep->hangup)
+ {
+ DBGL(DL_RCVRY, (log(LL_DBG, "handle_active: entry %s, hangup request!", cep->name)));
+ cep->hangup = 0;
+ next_state(cep, EV_DRQ);
+ }
+
+ /*
+ * if shorthold mode is rates based, check if
+ * we entered a time with a new unit length
+ */
+
+ if(cep->unitlengthsrc == ULSRC_RATE)
+ {
+ int connecttime = (int)difftime(now, cep->connect_time);
+
+ if((connecttime > 1) &&
+ (connecttime % 60))
+ {
+ int newrate = get_current_rate(cep, 0);
+
+ if(newrate != cep->unitlength)
+ {
+ DBGL(DL_MSG, (log(LL_DBG, "handle_active: rates unit length updated %d -> %d", cep->unitlength, newrate)));
+
+ cep->unitlength = newrate;
+
+ unitlen_chkupd(cep);
+ }
+ }
+ }
+ break;
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * timeout, recovery and retry handling for reserved entry
+ *---------------------------------------------------------------------------*/
+static void
+handle_reserved(cfg_entry_t *cep, time_t now)
+{
+ time_t waittime;
+
+ switch(cep->state)
+ {
+ case ST_DIALRTMRCHD: /* wait for dial retry time reached */
+
+ if(cep->dialrandincr)
+ waittime = cep->randomtime;
+ else
+ waittime = cep->recoverytime;
+
+
+ if(now > (cep->last_dial_time + waittime))
+ {
+ DBGL(DL_RCVRY, (log(LL_DBG, "handle_reserved: entry %s, dial retry request!", cep->name)));
+ cep->state = ST_DIALRETRY;
+
+ if((cep->cdid = get_cdid()) == 0)
+ {
+ log(LL_ERR, "handle_reserved: dialretry get_cdid() returned 0!");
+ cep->state = ST_IDLE;
+ cep->cdid = CDID_UNUSED;
+ return;
+ }
+
+ if((setup_dialout(cep)) == GOOD)
+ {
+ sendm_connect_req(cep);
+ }
+ else
+ {
+ log(LL_ERR, "handle_reserved: dialretry setup_dialout returned ERROR!");
+ cep->state = ST_IDLE;
+ cep->cdid = CDID_UNUSED;
+ return;
+ }
+ }
+ break;
+
+
+ case ST_ACB_WAITDIAL: /* active callback wait for time between disconnect and dial */
+
+ if(now > (cep->last_release_time + cep->callbackwait))
+ {
+ DBGL(DL_RCVRY, (log(LL_DBG, "handle_reserved: entry %s, callback dial!", cep->name)));
+ cep->state = ST_ACB_DIAL;
+
+ if((cep->cdid = get_cdid()) == 0)
+ {
+ log(LL_ERR, "handle_reserved: callback get_cdid() returned 0!");
+ cep->state = ST_IDLE;
+ cep->cdid = CDID_UNUSED;
+ return;
+ }
+
+ select_first_dialno(cep);
+
+ if((setup_dialout(cep)) == GOOD)
+ {
+ sendm_connect_req(cep);
+ }
+ else
+ {
+ log(LL_ERR, "handle_reserved: callback setup_dialout returned ERROR!");
+ cep->state = ST_IDLE;
+ cep->cdid = CDID_UNUSED;
+ return;
+ }
+ }
+ break;
+
+ case ST_ACB_DIALFAIL: /* callback to remote failed */
+
+ if(cep->dialrandincr)
+ waittime = cep->randomtime + cep->recoverytime;
+ else
+ waittime = cep->recoverytime;
+
+ if(now > (cep->last_release_time + waittime))
+ {
+ DBGL(DL_RCVRY, (log(LL_DBG, "handle_reserved: entry %s, callback dial retry request!", cep->name)));
+ cep->state = ST_ACB_DIAL;
+
+ if((cep->cdid = get_cdid()) == 0)
+ {
+ log(LL_ERR, "handle_reserved: callback dialretry get_cdid() returned 0!");
+ cep->state = ST_IDLE;
+ cep->cdid = CDID_UNUSED;
+ return;
+ }
+
+ if((setup_dialout(cep)) == GOOD)
+ {
+ sendm_connect_req(cep);
+ }
+ else
+ {
+ log(LL_ERR, "handle_reserved: callback dialretry setup_dialout returned ERROR!");
+ cep->state = ST_IDLE;
+ cep->cdid = CDID_UNUSED;
+ return;
+ }
+ }
+ break;
+
+ case ST_PCB_WAITCALL: /* wait for remote calling back */
+
+ if(now > (cep->last_release_time + cep->calledbackwait))
+ {
+ cep->dial_count++;
+
+ if(cep->dial_count < cep->dialretries)
+ {
+ /* inside normal retry cycle */
+
+ DBGL(DL_RCVRY, (log(LL_DBG, "handle_reserved: entry %s, retry calledback dial #%d!",
+ cep->name, cep->dial_count)));
+ cep->state = ST_PCB_DIAL;
+
+ if((cep->cdid = get_cdid()) == 0)
+ {
+ log(LL_ERR, "handle_reserved: calledback get_cdid() returned 0!");
+ cep->state = ST_IDLE;
+ cep->cdid = CDID_UNUSED;
+ return;
+ }
+ select_next_dialno(cep);
+
+ if((setup_dialout(cep)) == GOOD)
+ {
+ sendm_connect_req(cep);
+ }
+ else
+ {
+ log(LL_ERR, "handle_reserved: calledback setup_dialout returned ERROR!");
+ cep->state = ST_IDLE;
+ cep->cdid = CDID_UNUSED;
+ return;
+ }
+ }
+ else
+ {
+ /* retries exhausted */
+
+ DBGL(DL_RCVRY, (log(LL_DBG, "handle_reserved: calledback dial retries exhausted")));
+ dialresponse(cep, DSTAT_TFAIL);
+ cep->cdid = CDID_UNUSED;
+ cep->dial_count = 0;
+ cep->state = ST_IDLE;
+ }
+ }
+ break;
+
+ case ST_DOWN: /* interface was taken down */
+
+ if(now > (cep->went_down_time + cep->downtime))
+ {
+ DBGL(DL_RCVRY, (log(LL_DBG, "handle_reserved: taking %s%d up", bdrivername(cep->usrdevicename), cep->usrdeviceunit)));
+ if_up(cep);
+ cep->state = ST_IDLE;
+ cep->cdid = CDID_UNUSED;
+ }
+ break;
+
+ case ST_ILL: /* illegal state reached, recover ! */
+
+ recover_illegal(cep);
+ break;
+ }
+}
+
+/* EOF */
diff --git a/usr.sbin/i4b/isdnd/vararray.h b/usr.sbin/i4b/isdnd/vararray.h
new file mode 100644
index 0000000..c71f816
--- /dev/null
+++ b/usr.sbin/i4b/isdnd/vararray.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 1997, 1998 Martin Husemann <martin@rumolt.teuto.de>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software withough specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * vararray.h: basic collection macros for variable sized (growing) arrays:
+ * macro version of popular C++ template classes,
+ * not as elegant in use as the template version,
+ * but has maximum runtime performance and can give
+ * pointers to array contents (i.e. for ioctl's).
+ * Works in C as well as in C++.
+ * CAVEAT: in C++ only useable for aggregateable objects,
+ * it does use memcpy instead of copy constructors!
+ */
+
+#ifndef VARARRAY_H
+#define VARARRAY_H
+/* declare a variable sized array, element type is t */
+#define VARA_DECL(t) struct { int used, allocated; t *data; }
+
+/* aggregate initializer for a variable array */
+#define VARA_INITIALIZER { 0, 0, NULL }
+
+/* free all allocated storage */
+#define VARA_FREE(a) { if ((a).data != NULL) free((a).data); \
+ (a).allocated = 0; (a).used = 0; }
+
+/* number of elments currently in array*/
+#define VARA_NUM(a) ((a).used)
+
+/* number of elements already allocated in array */
+#define VARA_ALLOCATED(a) ((a).allocated)
+
+/* pointer to array data */
+#define VARA_PTR(a) ((a).data)
+
+/* empty the array */
+#define VARA_EMPTY(a) { (a).used = 0; }
+
+#ifdef __cplusplus
+#define VARA_NEW(t,c) new t[c]
+#define VARA_DELETE(p) delete [] p
+#else
+#define VARA_NEW(t,c) (t*)malloc(sizeof(t)*(c))
+#define VARA_DELETE(p) free(p)
+#endif
+
+/* add an element (not changing any data).
+ * a is the array, i the index,
+ * t the element type and n the initial allocation */
+#define VARA_ADD_AT(a,i,t,n) \
+{ \
+ if ((i) >= (a).allocated) { \
+ int new_alloc = (a).allocated ? (a).allocated*2 : (n); \
+ t *new_data; \
+ if (new_alloc <= (i)) new_alloc = (i)+1; \
+ new_data = VARA_NEW(t, new_alloc); \
+ if ((a).data) { \
+ memcpy(new_data, (a).data, (a).used*sizeof(t)); \
+ VARA_DELETE((a).data); \
+ } \
+ (a).data = new_data; \
+ (a).allocated = new_alloc; \
+ } \
+ if ((i) >= (a).used) { \
+ if (i > (a).used) \
+ memset(&((a).data[(a).used]), 0, \
+ sizeof(t)*((i)-(a).used+1)); \
+ (a).used = (i)+1; \
+ } \
+}
+
+/* return an l-value at index i */
+#define VARA_AT(a,i) ((a).data[(i)])
+
+/* iterate through the array */
+#define VARA_FOREACH(a,i) for ((i) = 0; (i) < (a).used; (i)++)
+
+/* check for a valid index */
+#define VARA_VALID(a,i) ((i) >= 0 && (i) < (a).used)
+
+/* remove one entry */
+#define VARA_REMOVEAT(a,i) \
+{ \
+ if ((i) < ((a).used -1)) \
+ memmove(&((a).data[(i)]), &((a).data[(i)+1]), sizeof((a).data[0])); \
+ (a).used--; \
+}
+
+/* free all storage allocated for the array */
+#define VARA_DESTROY(a) \
+{ \
+ if ((a).data) VARA_DELETE((a).data); \
+ (a).allocated = 0; \
+ (a).used = 0; \
+ (a).data = NULL; \
+}
+
+#endif
+
diff --git a/usr.sbin/i4b/isdndebug/Makefile b/usr.sbin/i4b/isdndebug/Makefile
new file mode 100644
index 0000000..cf52818
--- /dev/null
+++ b/usr.sbin/i4b/isdndebug/Makefile
@@ -0,0 +1,5 @@
+PROG = isdndebug
+SRCS = main.c
+MAN8 = isdndebug.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/i4b/isdndebug/isdndebug.8 b/usr.sbin/i4b/isdndebug/isdndebug.8
new file mode 100644
index 0000000..f3903e3
--- /dev/null
+++ b/usr.sbin/i4b/isdndebug/isdndebug.8
@@ -0,0 +1,102 @@
+.\"
+.\" Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id: isdndebug.8,v 1.4 1998/12/05 18:03:47 hm Exp $
+.\"
+.\" last edit-date: [Sat Dec 5 18:13:34 1998]
+.\"
+.\" -hm writing manual pages
+.\" -hm getting uptodate
+.\"
+.\"
+.Dd July 9, 1998
+.Dt isdndebug 8
+.Sh NAME
+.Nm isdndebug
+.Nd control debugging handling inside isdn4bsd kernel
+.Sh SYNOPSIS
+.Nm
+.Op Fl e
+.Op Fl g
+.Op Fl h
+.Op Fl l Ar layer
+.Op Fl m
+.Op Fl r
+.Op Fl s Ar value
+.Op Fl u Ar unit
+.Op Fl z
+.Op Fl H
+.Sh DESCRIPTION
+.Nm isdndebug
+is part of the isdn4bsd package and is used to control debugging output
+of the isdn4bsd kernel part. Every layer of the isdn4bsd kernel uses a
+debugging mask which can be manipulated using this utility.
+.Pp
+A second usage of
+.Nm
+is to display and reset the HSCX error counters.
+.Pp
+The following options are available:
+.Bl -tag -width Ds
+.It Fl e
+Set debugging mask for the selected layer(s) to display errors only.
+.It Fl g
+Get the debugging mask for the selected layer(s).
+.It Fl h
+Display the the HSCX error counters.
+.It Fl l
+Specify the layer for which a command applies. Default is all layers.
+.It Fl m
+Set debugging mask for the selected layer(s) to display all possible
+debugging messages (maximum output).
+.It Fl r
+Set debugging mask for the selected layer(s) to the compiled in default
+(reset).
+.It Fl s
+Set debugging mask for the selected layer(s) to value. Value can be
+specified in any number base supported by
+.Xr sscanf 3 .
+.It Fl u
+Set the unit numbers for the -h and -H flags.
+.It Fl z
+Set debugging mask for the selected layer(s) to no output at all (zero).
+.It Fl H
+Reset the HSCX error counters to zero.
+.Pp
+.Sh FILES
+/dev/i4bctl
+
+.Sh EXAMPLES
+The command:
+.Bd -literal -offset indent
+isdndebug -g
+.Ed
+.Pp
+displays the current debugging level for all ISDN layers
+
+.Sh AUTHOR
+The
+.Nm
+utility and this manpage were written by Hellmuth Michaelis. He can be
+contacted at hm@kts.org.
diff --git a/usr.sbin/i4b/isdndebug/main.c b/usr.sbin/i4b/isdndebug/main.c
new file mode 100644
index 0000000..7fdbf7f
--- /dev/null
+++ b/usr.sbin/i4b/isdndebug/main.c
@@ -0,0 +1,553 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * main.c - i4b set debug options
+ * ------------------------------
+ *
+ * $Id: main.c,v 1.13 1998/12/05 18:03:49 hm Exp $
+ *
+ * last edit-date: [Sat Dec 5 18:13:55 1998]
+ *
+ *---------------------------------------------------------------------------*/
+
+#include <stdio.h>
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <machine/i4b_debug.h>
+#include <machine/i4b_ioctl.h>
+
+char *bin_str(unsigned long val, int length);
+
+static void usage ( void );
+void printl1(unsigned long val);
+void printl2(unsigned long val);
+void printl3(unsigned long val);
+void printl4(unsigned long val);
+
+static int isdnfd;
+
+#define I4BCTLDEVICE "/dev/i4bctl"
+
+int opt_get = 0;
+int opt_layer = -1;
+int opt_set = 0;
+int opt_setval;
+int opt_reset = 0;
+int opt_max = 0;
+int opt_err = 0;
+int opt_zero = 0;
+int opt_unit = 0;
+int opt_hscx = 0;
+int opt_rhscx = 0;
+
+/*---------------------------------------------------------------------------*
+ * program entry
+ *---------------------------------------------------------------------------*/
+int
+main(int argc, char **argv)
+{
+ int c;
+ ctl_debug_t cdbg;
+ int ret;
+
+ while ((c = getopt(argc, argv, "eghl:mrs:u:zH?")) != EOF)
+ {
+ switch(c)
+ {
+ case 'e':
+ opt_err = 1;
+ break;
+
+ case 'g':
+ opt_get = 1;
+ break;
+
+ case 'h':
+ opt_hscx = 1;
+ break;
+
+ case 'r':
+ opt_reset = 1;
+ break;
+
+ case 'm':
+ opt_max = 1;
+ break;
+
+ case 'l':
+ opt_layer = atoi(optarg);
+ if(opt_layer < 1 || opt_layer > 4)
+ usage();
+ break;
+
+ case 's':
+ if((sscanf(optarg, "%i", &opt_setval)) != 1)
+ usage();
+ opt_set = 1;
+ break;
+
+ case 'u':
+ opt_unit = atoi(optarg);
+ if(opt_unit < 0 || opt_unit > 9)
+ usage();
+ break;
+
+ case 'z':
+ opt_zero = 1;
+ break;
+
+ case 'H':
+ opt_rhscx = 1;
+ break;
+
+ case '?':
+ default:
+ usage();
+ break;
+ }
+ }
+
+ if(opt_get == 0 && opt_set == 0 && opt_reset == 0 && opt_max == 0 &&
+ opt_err == 0 && opt_zero == 0 && opt_hscx == 0 && opt_rhscx == 0)
+ {
+ usage();
+ }
+
+ if((opt_get + opt_set + opt_reset + opt_max + opt_err + opt_zero +
+ opt_hscx + opt_rhscx) > 1)
+ {
+ usage();
+ }
+
+ if((isdnfd = open(I4BCTLDEVICE, O_RDWR)) < 0)
+ {
+ fprintf(stderr, "i4bctl: cannot open %s: %s\n", I4BCTLDEVICE, strerror(errno));
+ exit(1);
+ }
+
+ if(opt_hscx)
+ {
+ hscxstat_t hst;
+
+ hst.unit = opt_unit;
+ hst.chan = 0;
+
+ if((ret = ioctl(isdnfd, I4B_CTL_GET_HSCXSTAT, &hst)) < 0)
+ {
+ fprintf(stderr, "ioctl I4B_CTL_GET_HSCXSTAT failed: %s", strerror(errno));
+ exit(1);
+ }
+
+ printf("\nHSCX events: VFR RDO CRC RAB XDU RFO\n");
+
+ printf("unit %d chan %d: %6d %6d %6d %6d %6d %6d\n",
+ hst.unit, hst.chan,
+ hst.vfr, hst.rdo, hst.crc, hst.rab, hst.xdu, hst.rfo);
+
+ hst.unit = opt_unit;
+ hst.chan = 1;
+
+ if((ret = ioctl(isdnfd, I4B_CTL_GET_HSCXSTAT, &hst)) < 0)
+ {
+ fprintf(stderr, "ioctl I4B_CTL_GET_HSCXSTAT failed: %s", strerror(errno));
+ exit(1);
+ }
+
+ printf("unit %d chan %d: %6d %6d %6d %6d %6d %6d\n",
+ hst.unit, hst.chan,
+ hst.vfr, hst.rdo, hst.crc, hst.rab, hst.xdu, hst.rfo);
+
+ exit(0);
+ }
+
+ if(opt_rhscx)
+ {
+ hscxstat_t hst;
+
+ hst.unit = opt_unit;
+ hst.chan = 0;
+
+ if((ret = ioctl(isdnfd, I4B_CTL_CLR_HSCXSTAT, &hst)) < 0)
+ {
+ fprintf(stderr, "ioctl I4B_CTL_CLR_HSCXSTAT failed: %s", strerror(errno));
+ exit(1);
+ }
+
+ printf("HSCX event counters unit %d chan %d reset to zero!\n",
+ hst.unit, hst.chan);
+
+ hst.unit = opt_unit;
+ hst.chan = 1;
+
+ if((ret = ioctl(isdnfd, I4B_CTL_CLR_HSCXSTAT, &hst)) < 0)
+ {
+ fprintf(stderr, "ioctl I4B_CTL_CLR_HSCXSTAT failed: %s", strerror(errno));
+ exit(1);
+ }
+
+ printf("HSCX event counters unit %d chan %d reset to zero!\n",
+ hst.unit, hst.chan);
+
+ exit(0);
+ }
+
+ if((ret = ioctl(isdnfd, I4B_CTL_GET_DEBUG, &cdbg)) < 0)
+ {
+ fprintf(stderr, "ioctl I4B_CTL_GET_DEBUG failed: %s", strerror(errno));
+ exit(1);
+ }
+
+ if(opt_get)
+ {
+ switch(opt_layer)
+ {
+ case -1:
+ printl1(cdbg.l1);
+ printl2(cdbg.l2);
+ printl3(cdbg.l3);
+ printl4(cdbg.l4);
+ break;
+
+ case 1:
+ printl1(cdbg.l1);
+ break;
+
+ case 2:
+ printl2(cdbg.l2);
+ break;
+
+ case 3:
+ printl3(cdbg.l3);
+ break;
+
+ case 4:
+ printl4(cdbg.l4);
+ break;
+ }
+ printf("\n");
+ return(0);
+ }
+ else if(opt_set)
+ {
+ switch(opt_layer)
+ {
+ case -1:
+ usage();
+ break;
+
+ case 1:
+ cdbg.l1 = opt_setval;
+ break;
+
+ case 2:
+ cdbg.l2 = opt_setval;
+ break;
+
+ case 3:
+ cdbg.l3 = opt_setval;
+ break;
+
+ case 4:
+ cdbg.l4 = opt_setval;
+ break;
+ }
+ }
+ else if(opt_reset)
+ {
+ switch(opt_layer)
+ {
+ case -1:
+ cdbg.l1 = L1_DEBUG_DEFAULT;
+ cdbg.l2 = L2_DEBUG_DEFAULT;
+ cdbg.l3 = L3_DEBUG_DEFAULT;
+ cdbg.l4 = L4_DEBUG_DEFAULT;
+ break;
+
+ case 1:
+ cdbg.l1 = L1_DEBUG_DEFAULT;
+ break;
+
+ case 2:
+ cdbg.l2 = L2_DEBUG_DEFAULT;
+ break;
+
+ case 3:
+ cdbg.l3 = L3_DEBUG_DEFAULT;
+ break;
+
+ case 4:
+ cdbg.l4 = L4_DEBUG_DEFAULT;
+ break;
+ }
+ }
+ else if(opt_max)
+ {
+ switch(opt_layer)
+ {
+ case -1:
+ cdbg.l1 = L1_DEBUG_MAX;
+ cdbg.l2 = L2_DEBUG_MAX;
+ cdbg.l3 = L3_DEBUG_MAX;
+ cdbg.l4 = L4_DEBUG_MAX;
+ break;
+
+ case 1:
+ cdbg.l1 = L1_DEBUG_MAX;
+ break;
+
+ case 2:
+ cdbg.l2 = L2_DEBUG_MAX;
+ break;
+
+ case 3:
+ cdbg.l3 = L3_DEBUG_MAX;
+ break;
+
+ case 4:
+ cdbg.l4 = L4_DEBUG_MAX;
+ break;
+ }
+ }
+ else if(opt_err)
+ {
+ switch(opt_layer)
+ {
+ case -1:
+ cdbg.l1 = L1_DEBUG_ERR;
+ cdbg.l2 = L2_DEBUG_ERR;
+ cdbg.l3 = L3_DEBUG_ERR;
+ cdbg.l4 = L4_DEBUG_ERR;
+ break;
+
+ case 1:
+ cdbg.l1 = L1_DEBUG_ERR;
+ break;
+
+ case 2:
+ cdbg.l2 = L2_DEBUG_ERR;
+ break;
+
+ case 3:
+ cdbg.l3 = L3_DEBUG_ERR;
+ break;
+
+ case 4:
+ cdbg.l4 = L4_DEBUG_ERR;
+ break;
+ }
+ }
+ else if(opt_zero)
+ {
+ switch(opt_layer)
+ {
+ case -1:
+ cdbg.l1 = 0;
+ cdbg.l2 = 0;
+ cdbg.l3 = 0;
+ cdbg.l4 = 0;
+ break;
+
+ case 1:
+ cdbg.l1 = 0;
+ break;
+
+ case 2:
+ cdbg.l2 = 0;
+ break;
+
+ case 3:
+ cdbg.l3 = 0;
+ break;
+
+ case 4:
+ cdbg.l4 = 0;
+ break;
+ }
+ }
+ else
+ {
+ exit(1);
+ }
+
+ if((ret = ioctl(isdnfd, I4B_CTL_SET_DEBUG, &cdbg)) < 0)
+ {
+ fprintf(stderr, "ioctl I4B_CTL_SET_DEBUG failed: %s", strerror(errno));
+ exit(1);
+ }
+ return(0);
+}
+
+/*---------------------------------------------------------------------------*
+ * return ptr to string of 1's and 0's for value
+ *---------------------------------------------------------------------------*/
+char *
+bin_str(unsigned long val, int length)
+{
+ static char buffer[80];
+ int i = 0;
+
+ if (length > 32)
+ length = 32;
+
+ val = val << (32 - length);
+
+ while (length--)
+ {
+ if (val & 0x80000000)
+ buffer[i++] = '1';
+ else
+ buffer[i++] = '0';
+ if ((length % 4) == 0 && length)
+ buffer[i++] = '.';
+ val = val << 1;
+ }
+ return (buffer);
+}
+
+/*---------------------------------------------------------------------------*
+ * print l1 info
+ *---------------------------------------------------------------------------*/
+void
+printl1(unsigned long val)
+{
+ printf("\nLayer 1: %s = 0x%lX\n", bin_str(val, 32), val);
+ printf(" || |||| |||| ||||\n"),
+ printf(" || |||| |||| |||+- general error messages\n");
+ printf(" || |||| |||| ||+-- PH primitives exchanged\n");
+ printf(" || |||| |||| |+--- B channel actions\n");
+ printf(" || |||| |||| +---- HSCX error messages\n");
+ printf(" || |||| |||+------ HSCX IRQ messages\n");
+ printf(" || |||| ||+------- ISAC error messages\n");
+ printf(" || |||| |+-------- ISAC messages\n");
+ printf(" || |||| +--------- ISAC setup messages\n");
+ printf(" || |||+----------- FSM general messages\n");
+ printf(" || ||+------------ FSM error messages\n");
+ printf(" || |+------------- timer general messages\n");
+ printf(" || +-------------- timer error messages\n");
+ printf(" |+---------------- HSCX data xfer errors msgs\n");
+ printf(" +----------------- ISAC CICO messages\n");
+ printf(" ++++-++++-++++-++++-++------------------ unassigned\n");
+}
+
+/*---------------------------------------------------------------------------*
+ * print l2 info
+ *---------------------------------------------------------------------------*/
+void
+printl2(unsigned long val)
+{
+ printf("\nLayer 2: %s = 0x%lX\n", bin_str(val, 32), val);
+ printf(" || |||| |||| ||||\n"),
+ printf(" || |||| |||| |||+- general error messages\n");
+ printf(" || |||| |||| ||+-- DL primitives exchanged\n");
+ printf(" || |||| |||| |+--- U frame messages\n");
+ printf(" || |||| |||| +---- U frame error messages\n");
+ printf(" || |||| |||+------ S frame messages\n");
+ printf(" || |||| ||+------- S frame error messages\n");
+ printf(" || |||| |+-------- I frame messages\n");
+ printf(" || |||| +--------- I frame error messages\n");
+ printf(" || |||+----------- FSM general messages\n");
+ printf(" || ||+------------ FSM error messages\n");
+ printf(" || |+------------- timer general messages\n");
+ printf(" || +-------------- timer error messages\n");
+ printf(" |+---------------- TEI general messages\n");
+ printf(" +----------------- TEI error messages\n");
+ printf(" ++++-++++-++++-++++-++------------------ unassigned\n");
+}
+
+/*---------------------------------------------------------------------------*
+ * print l3 info
+ *---------------------------------------------------------------------------*/
+void
+printl3(unsigned long val)
+{
+ printf("\nLayer 3: %s = 0x%lX\n", bin_str(val, 32), val);
+ printf(" ||| |||| ||||\n"),
+ printf(" ||| |||| |||+- general error messages\n");
+ printf(" ||| |||| ||+-- general messages\n");
+ printf(" ||| |||| |+--- FSM messages\n");
+ printf(" ||| |||| +---- FSM error messages\n");
+ printf(" ||| |||+------ timer messages\n");
+ printf(" ||| ||+------- timer error messages\n");
+ printf(" ||| |+-------- protocol messages\n");
+ printf(" ||| +--------- protocol error messages\n");
+ printf(" ||+----------- facility messages\n");
+ printf(" |+------------ facility error messages\n");
+ printf(" +------------- Q.931 messages exchanged\n");
+ printf(" ++++-++++-++++-++++-++++-++------------- unassigned\n");
+}
+
+/*---------------------------------------------------------------------------*
+ * print l4 info
+ *---------------------------------------------------------------------------*/
+void
+printl4(unsigned long val)
+{
+ printf("\nLayer 4: %s = 0x%lX\n", bin_str(val, 32), val);
+ printf(" || ||||\n"),
+ printf(" || |||+- general error messages\n");
+ printf(" || ||+-- general messages\n");
+ printf(" || |+--- B-ch timeout messages\n");
+ printf(" || +---- network driver dial state\n");
+ printf(" |+------ ipr driver debug messages\n");
+ printf(" +------- rbch driver debug messages\n");
+ printf(" ++++-++++-++++-++++-++++-++++-++-------- unassigned\n");
+}
+
+/*---------------------------------------------------------------------------*
+ * usage display and exit
+ *---------------------------------------------------------------------------*/
+static void
+usage(void)
+{
+ fprintf(stderr, "\n");
+ fprintf(stderr, "isdndebug - i4b set debug level, version %02d.%02d, compiled %s %s\n", VERSION, REL, __DATE__, __TIME__);
+ fprintf(stderr, "usage: isdndebug -e -h -g -l <layer> -m -r -s <value> -u <unit> -z -H\n");
+ fprintf(stderr, " -e set error only debugging output\n");
+ fprintf(stderr, " -g get current debugging values\n");
+ fprintf(stderr, " -h get HSCX event counters\n");
+ fprintf(stderr, " -l layer specify layer (1...4)\n");
+ fprintf(stderr, " -m set maximum debugging output\n");
+ fprintf(stderr, " -r reset values(s) to compiled in default\n");
+ fprintf(stderr, " -s value set new debugging value for layer\n");
+ fprintf(stderr, " -u unit unit number for -h and -H commands\n");
+ fprintf(stderr, " -z set zero (=no) debugging output\n");
+ fprintf(stderr, " -H reset HSCX event counters to zero\n");
+ fprintf(stderr, "\n");
+ exit(1);
+}
+
+/* EOF */
diff --git a/usr.sbin/i4b/isdndecode/Makefile b/usr.sbin/i4b/isdndecode/Makefile
new file mode 100644
index 0000000..cad91437
--- /dev/null
+++ b/usr.sbin/i4b/isdndecode/Makefile
@@ -0,0 +1,7 @@
+PROG = isdndecode
+SRCS = main.c layer1.c layer2.c layer3.c \
+ layer3_subr.c facility.c pcause.c
+MAN8 = isdndecode.8
+
+.include <bsd.prog.mk>
+
diff --git a/usr.sbin/i4b/isdndecode/decode.h b/usr.sbin/i4b/isdndecode/decode.h
new file mode 100644
index 0000000..0eec0ab
--- /dev/null
+++ b/usr.sbin/i4b/isdndecode/decode.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * decode.h - isdndecode header file
+ * ---------------------------------
+ *
+ * $Id: decode.h,v 1.4 1998/12/18 17:09:38 hm Exp $
+ *
+ * last edit-date: [Fri Dec 18 18:10:13 1998]
+ *
+ *---------------------------------------------------------------------------*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/uio.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/file.h>
+
+#include <machine/i4b_ioctl.h>
+#include <machine/i4b_trace.h>
+
+#include "pcause.h"
+
+#define I4BTRC_DEVICE "/dev/i4btrc" /* trace device file */
+#define DECODE_FILE_NAME "isdndecode" /* default output filename */
+#define DECODE_FILE_NAME_BAK ".last" /* backup filename trailer */
+#define BIN_FILE_NAME "isdntracebin" /* default binary filename */
+
+#define BSIZE 4096 /* read buffer size */
+#define NCOLS 80 /* screen width */
+
+#define RxUDEF 0 /* analyze mode, default unit for receiver side */
+#define TxUDEF 1 /* analyze mode, default unit for transmitter side */
+
+void layer1(char *pbuf, unsigned char *buf);
+int layer2(char *pbuf, unsigned char *buf, int is_te, int printit);
+void layer3(char *pbuf, int n, int off, unsigned char *buf);
+int q932_facility(char *pbuf, unsigned char *buf);
+void sprintline(int, char *, int, int, int, const char *, ...);
+void extension(int, char *, int, unsigned char, unsigned char);
+
+/* EOF */
diff --git a/usr.sbin/i4b/isdndecode/facility.c b/usr.sbin/i4b/isdndecode/facility.c
new file mode 100644
index 0000000..5735abb
--- /dev/null
+++ b/usr.sbin/i4b/isdndecode/facility.c
@@ -0,0 +1,906 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * facility.c - decode Q.932 facilities
+ * ------------------------------------
+ *
+ * $Id: facility.c,v 1.2 1998/12/18 17:09:38 hm Exp $
+ *
+ * last edit-date: [Fri Dec 18 18:10:32 1998]
+ *
+ *---------------------------------------------------------------------------*/
+
+#include "decode.h"
+#include "facility.h"
+
+static int do_component(int length, char *pbuf);
+static char *uni_str(int code);
+static char *opval_str(int val);
+static char *bid_str(int val);
+static void next_state(char *pbuf, int class, int form, int code, int val);
+
+static int byte_len;
+static unsigned char *byte_buf;
+static int state;
+
+/*---------------------------------------------------------------------------*
+ * decode Q.931/Q.932 facility info element
+ *---------------------------------------------------------------------------*/
+int
+q932_facility(char *pbuf, unsigned char *buf)
+{
+ int len;
+
+ sprintf((pbuf+strlen(pbuf)), "[facility (Q.932): ");
+
+ buf++; /* length */
+
+ len = *buf;
+
+ buf++; /* protocol profile */
+
+ sprintf((pbuf+strlen(pbuf)), "Protocol=");
+
+ switch(*buf & 0x1f)
+ {
+ case FAC_PROTO_ROP:
+ sprintf((pbuf+strlen(pbuf)), "Remote Operations Protocol\n");
+ break;
+
+ case FAC_PROTO_CMIP:
+ sprintf((pbuf+strlen(pbuf)), "CMIP Protocol (Q.941), UNSUPPORTED!\n");
+ return(len+2);
+ break;
+
+ case FAC_PROTO_ACSE:
+ sprintf((pbuf+strlen(pbuf)), "ACSE Protocol (X.217/X.227), UNSUPPORTED!\n");
+ return(len+2);
+ break;
+
+ default:
+ sprintf((pbuf+strlen(pbuf)), "Unknown Protocol (val = 0x%x), UNSUPPORTED!\n", *buf & 0x1f);
+ return(len+2);
+ break;
+ }
+
+ /* next byte */
+
+ buf++;
+ len--;
+
+ /* initialize variables for do_component */
+
+ byte_len = 0;
+ byte_buf = buf;
+ state = ST_EXP_COMP_TYP;
+
+ /* decode facility */
+
+ do_component(len, pbuf);
+
+ sprintf((pbuf+(strlen(pbuf)-1)), "]"); /* XXX replace last newline */
+
+ return(len+3);
+}
+
+/*---------------------------------------------------------------------------*
+ * handle a component recursively
+ *---------------------------------------------------------------------------*/
+static int
+do_component(int length, char *pbuf)
+{
+ int comp_tag_class; /* component tag class */
+ int comp_tag_form; /* component form: constructor or primitive */
+ int comp_tag_code; /* component code depending on class */
+ int comp_length = 0; /* component length */
+
+#ifdef FAC_DEBUG
+ sprintf((pbuf+strlen(pbuf)), "ENTER - comp_length = %d, byte_len = %d, length =%d\n", comp_length, byte_len, length);
+#endif
+
+again:
+
+#ifdef FAC_DEBUG
+ sprintf((pbuf+strlen(pbuf)), "AGAIN - comp_length = %d, byte_len = %d, length =%d\n", comp_length, byte_len, length);
+#endif
+
+ /*----------------------------------------*/
+ /* first component element: component tag */
+ /*----------------------------------------*/
+
+ /* tag class bits */
+
+ sprintf((pbuf+strlen(pbuf)), "\t0x%02x Tag: ", *byte_buf);
+
+ comp_tag_class = (*byte_buf & 0xc0) >> 6;
+
+ switch(comp_tag_class)
+ {
+ case FAC_TAGCLASS_UNI:
+ sprintf((pbuf+strlen(pbuf)), "Universal");
+ break;
+ case FAC_TAGCLASS_APW:
+ sprintf((pbuf+strlen(pbuf)), "Applic-wide");
+ break;
+ case FAC_TAGCLASS_COS:
+ sprintf((pbuf+strlen(pbuf)), "Context-spec");
+ break;
+ case FAC_TAGCLASS_PRU:
+ sprintf((pbuf+strlen(pbuf)), "Private");
+ break;
+ }
+
+ /* tag form bit */
+
+ comp_tag_form = (*byte_buf & 0x20) > 5;
+
+ sprintf((pbuf+strlen(pbuf)), ", ");
+
+ if(comp_tag_form == FAC_TAGFORM_CON)
+ {
+ sprintf((pbuf+strlen(pbuf)), "Constructor");
+ }
+ else
+ {
+ sprintf((pbuf+strlen(pbuf)), "Primitive");
+ }
+
+ /* tag code bits */
+
+ comp_tag_code = *byte_buf & 0x1f;
+
+ sprintf((pbuf+strlen(pbuf)), ", ");
+
+ if(comp_tag_code == 0x1f)
+ {
+ comp_tag_code = 0;
+
+ byte_buf++;
+ byte_len++;
+
+ while(*byte_buf & 0x80)
+ {
+ comp_tag_code += (*byte_buf & 0x7f);
+ byte_buf++;
+ byte_len++;
+ }
+ comp_tag_code += (*byte_buf & 0x7f);
+ sprintf((pbuf+strlen(pbuf)), "%d (ext)\n", comp_tag_code);
+ }
+ else
+ {
+ comp_tag_code = (*byte_buf & 0x1f);
+
+ if(comp_tag_class == FAC_TAGCLASS_UNI)
+ {
+ sprintf((pbuf+strlen(pbuf)), "%s (%d)\n", uni_str(comp_tag_code), comp_tag_code);
+ }
+ else
+ {
+ sprintf((pbuf+strlen(pbuf)), "code = %d\n", comp_tag_code);
+ }
+ }
+
+ byte_buf++;
+ byte_len++;
+
+ /*--------------------------------------------*/
+ /* second component element: component length */
+ /*--------------------------------------------*/
+
+ sprintf((pbuf+strlen(pbuf)), "\t0x%02x Len: ", *byte_buf);
+
+ comp_length = 0;
+
+ if(*byte_buf & 0x80)
+ {
+ int i = *byte_buf & 0x7f;
+
+ byte_len += i;
+
+ for(;i > 0;i++)
+ {
+ byte_buf++;
+ comp_length += (*byte_buf * (i*256));
+ }
+ sprintf((pbuf+strlen(pbuf)), "%d (long form)\n", comp_length);
+ }
+ else
+ {
+ comp_length = *byte_buf & 0x7f;
+ sprintf((pbuf+strlen(pbuf)), "%d (short form)\n", comp_length);
+ }
+
+ next_state(pbuf, comp_tag_class, comp_tag_form, comp_tag_code, -1);
+
+ byte_len++;
+ byte_buf++;
+
+ if(comp_length)
+ {
+
+ /*---------------------------------------------*/
+ /* third component element: component contents */
+ /*---------------------------------------------*/
+
+ if(comp_tag_form) /* == constructor */
+ {
+ do_component(comp_length, pbuf);
+ }
+ else
+ {
+ int val = 0;
+ if(comp_tag_class == FAC_TAGCLASS_UNI)
+ {
+ switch(comp_tag_code)
+ {
+ case FAC_CODEUNI_INT:
+ case FAC_CODEUNI_ENUM:
+ case FAC_CODEUNI_BOOL:
+ if(comp_length)
+ {
+ int i;
+
+ sprintf((pbuf+strlen(pbuf)), "\t");
+
+ for(i = comp_length-1; i >= 0; i--)
+ {
+ sprintf((pbuf+strlen(pbuf)), "0x%02x ", *byte_buf);
+ val += (*byte_buf + (i*255));
+ byte_buf++;
+ byte_len++;
+ if(i)
+ sprintf((pbuf+strlen(pbuf)), "\n\t");
+ }
+ sprintf((pbuf+strlen(pbuf)), "Val: %d\n", val);
+ }
+ break;
+ default:
+ if(comp_length)
+ {
+ int i;
+
+ sprintf((pbuf+strlen(pbuf)), "\t");
+
+ for(i = comp_length-1; i >= 0; i--)
+ {
+ sprintf((pbuf+strlen(pbuf)), "0x%02x = %d", *byte_buf, *byte_buf);
+ if(isprint(*byte_buf))
+ sprintf((pbuf+strlen(pbuf)), " = '%c'", *byte_buf);
+ byte_buf++;
+ byte_len++;
+ if(i)
+ sprintf((pbuf+strlen(pbuf)), "\n\t");
+ }
+ }
+ break;
+ }
+ }
+
+ else /* comp_tag_class != FAC_TAGCLASS_UNI */
+ {
+ if(comp_length)
+ {
+ int i;
+
+ sprintf((pbuf+strlen(pbuf)), "\t");
+
+ for(i = comp_length-1; i >= 0; i--)
+ {
+ sprintf((pbuf+strlen(pbuf)), "0x%02x", *byte_buf);
+ val += (*byte_buf + (i*255));
+ byte_buf++;
+ byte_len++;
+ if(i)
+ sprintf((pbuf+strlen(pbuf)), "\n\t");
+ }
+ sprintf((pbuf+strlen(pbuf)), "\n");
+ }
+ }
+ next_state(pbuf, comp_tag_class, comp_tag_form, comp_tag_code, val);
+ }
+ }
+
+#ifdef FAC_DEBUG
+ sprintf((pbuf+strlen(pbuf)), "PREGOTO - comp_length = %d, byte_len = %d, length =%d\n", comp_length, byte_len, length);
+#endif
+ if(byte_len < length)
+ goto again;
+#ifdef FAC_DEBUG
+ sprintf((pbuf+strlen(pbuf)), "RETURN - comp_length = %d, byte_len = %d, length =%d\n", comp_length, byte_len, length);
+#endif
+ return(byte_len);
+}
+
+/*---------------------------------------------------------------------------*
+ * print universal id type
+ *---------------------------------------------------------------------------*/
+static char *uni_str(int code)
+{
+ static char *tbl[] = {
+ "BOOLEAN",
+ "INTEGER",
+ "BIT STRING",
+ "OCTET STRING",
+ "NULL",
+ "OBJECT IDENTIFIER",
+ "OBJECT DESCRIPTOR",
+ "EXTERNAL",
+ "REAL",
+ "ENUMERATED",
+ "RESERVED11",
+ "RESERVED12",
+ "RESERVED13",
+ "RESERVED14",
+ "RESERVED15",
+ "SEQUENCE",
+ "SET",
+ "NUMERIC STRING",
+ "PRINTABLE STRING",
+ "TELETEX STRING",
+ "ISO646 STRING",
+ "IA5 STRING",
+ "GRAPHIC STRING",
+ "GENERAL STRING"
+ };
+
+ if(code >= 1 && code <= FAC_CODEUNI_GNSTR)
+ return(tbl[code-1]);
+ else
+ return("ERROR, Value out of Range!");
+}
+
+/*---------------------------------------------------------------------------*
+ * print operation value
+ *---------------------------------------------------------------------------*/
+static char *opval_str(int val)
+{
+ static char buffer[80];
+ char *r;
+
+ switch(val)
+ {
+ case FAC_OPVAL_UUS:
+ r = "uUs";
+ break;
+ case FAC_OPVAL_CUG:
+ r = "cUGCall";
+ break;
+ case FAC_OPVAL_MCID:
+ r = "mCIDRequest";
+ break;
+ case FAC_OPVAL_BTPY:
+ r = "beginTPY";
+ break;
+ case FAC_OPVAL_ETPY:
+ r = "endTPY";
+ break;
+ case FAC_OPVAL_ECT:
+ r = "eCTRequest";
+ break;
+ case FAC_OPVAL_DIV_ACT:
+ r = "activationDiversion";
+ break;
+ case FAC_OPVAL_DIV_DEACT:
+ r = "deactivationDiversion";
+ break;
+ case FAC_OPVAL_DIV_ACTSN:
+ r = "activationStatusNotificationDiv";
+ break;
+ case FAC_OPVAL_DIV_DEACTSN:
+ r = "deactivationStatusNotificationDiv";
+ break;
+ case FAC_OPVAL_DIV_INTER:
+ r = "interrogationDiversion";
+ break;
+ case FAC_OPVAL_DIV_INFO:
+ r = "diversionInformation";
+ break;
+ case FAC_OPVAL_DIV_CALLDEF:
+ r = "callDeflection";
+ break;
+ case FAC_OPVAL_DIV_CALLRER:
+ r = "callRerouting";
+ break;
+ case FAC_OPVAL_DIV_LINF2:
+ r = "divertingLegInformation2";
+ break;
+ case FAC_OPVAL_DIV_INVS:
+ r = "invokeStatus";
+ break;
+ case FAC_OPVAL_DIV_INTER1:
+ r = "interrogationDiversion1";
+ break;
+ case FAC_OPVAL_DIV_LINF1:
+ r = "divertingLegInformation1";
+ break;
+ case FAC_OPVAL_DIV_LINF3:
+ r = "divertingLegInformation3";
+ break;
+ case FAC_OPVAL_ER_CRCO:
+ r = "explicitReservationCreationControl";
+ break;
+ case FAC_OPVAL_ER_MGMT:
+ r = "explicitReservationManagement";
+ break;
+ case FAC_OPVAL_ER_CANC:
+ r = "explicitReservationCancel";
+ break;
+ case FAC_OPVAL_MLPP_QUERY:
+ r = "mLPP lfb Query";
+ break;
+ case FAC_OPVAL_MLPP_CALLR:
+ r = "mLPP Call Request";
+ break;
+ case FAC_OPVAL_MLPP_CALLP:
+ r = "mLPP Call Preemption";
+ break;
+ case FAC_OPVAL_AOC_REQ:
+ r = "chargingRequest";
+ break;
+ case FAC_OPVAL_AOC_S_CUR:
+ r = "aOCSCurrency";
+ break;
+ case FAC_OPVAL_AOC_S_SPC:
+ r = "aOCSSpecialArrangement";
+ break;
+ case FAC_OPVAL_AOC_D_CUR:
+ r = "aOCDCurrency";
+ break;
+ case FAC_OPVAL_AOC_D_UNIT:
+ r = "aOCDChargingUnit";
+ break;
+ case FAC_OPVAL_AOC_E_CUR:
+ r = "aOCECurrency";
+ break;
+ case FAC_OPVAL_AOC_E_UNIT:
+ r = "aOCEChargingUnit";
+ break;
+ case FAC_OPVAL_AOC_IDOFCRG:
+ r = "identificationOfCharge";
+ break;
+ case FAC_OPVAL_CONF_BEG:
+ r = "beginConf";
+ break;
+ case FAC_OPVAL_CONF_ADD:
+ r = "addConf";
+ break;
+ case FAC_OPVAL_CONF_SPLIT:
+ r = "splitConf";
+ break;
+ case FAC_OPVAL_CONF_DROP:
+ r = "dropConf";
+ break;
+ case FAC_OPVAL_CONF_ISOLATE:
+ r = "isolateConf";
+ break;
+ case FAC_OPVAL_CONF_REATT:
+ r = "reattachConf";
+ break;
+ case FAC_OPVAL_CONF_PDISC:
+ r = "partyDISC";
+ break;
+ case FAC_OPVAL_CONF_FCONF:
+ r = "floatConf";
+ break;
+ case FAC_OPVAL_CONF_END:
+ r = "endConf";
+ break;
+ case FAC_OPVAL_CONF_IDCFE:
+ r = "indentifyConferee";
+ break;
+ case FAC_OPVAL_REVC_REQ:
+ r = "requestREV";
+ break;
+ default:
+ sprintf(buffer, "unknown operation value %d!", val);
+ r = buffer;
+ }
+ return(r);
+}
+
+/*---------------------------------------------------------------------------*
+ * billing id string
+ *---------------------------------------------------------------------------*/
+static char *bid_str(int val)
+{
+ static char buffer[80];
+ char *r;
+
+ switch(val)
+ {
+ case 0:
+ r = "normalCharging";
+ break;
+ case 1:
+ r = "reverseCharging";
+ break;
+ case 2:
+ r = "creditCardCharging";
+ break;
+ case 3:
+ r = "callForwardingUnconditional";
+ break;
+ case 4:
+ r = "callForwardingBusy";
+ break;
+ case 5:
+ r = "callForwardingNoReply";
+ break;
+ case 6:
+ r = "callDeflection";
+ break;
+ case 7:
+ r = "callTransfer";
+ break;
+ default:
+ sprintf(buffer, "unknown billing-id value %d!", val);
+ r = buffer;
+ }
+ return(r);
+}
+
+/*---------------------------------------------------------------------------*
+ * invoke component
+ *---------------------------------------------------------------------------*/
+static void
+F_1_1(char *pbuf, int val)
+{
+#ifdef ST_DEBUG
+ sprintf((pbuf+strlen(pbuf)), "next_state: exec F_1_1, val = %d\n", val);
+#endif
+ if(val == -1)
+ {
+ sprintf((pbuf+strlen(pbuf)), "\t invokeComponent\n");
+ state = ST_EXP_INV_ID;
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * return result
+ *---------------------------------------------------------------------------*/
+static void
+F_1_2(char *pbuf, int val)
+{
+#ifdef ST_DEBUG
+ sprintf((pbuf+strlen(pbuf)), "next_state: exec F_1_2, val = %d\n", val);
+#endif
+ if(val == -1)
+ {
+ sprintf((pbuf+strlen(pbuf)), "\t returnResult\n");
+ state = ST_EXP_RR_INV_ID;
+ }
+}
+/*---------------------------------------------------------------------------*
+ * return error
+ *---------------------------------------------------------------------------*/
+static void
+F_1_3(char *pbuf, int val)
+{
+#ifdef ST_DEBUG
+ sprintf((pbuf+strlen(pbuf)), "next_state: exec F_1_3, val = %d\n", val);
+#endif
+ if(val == -1)
+ {
+ sprintf((pbuf+strlen(pbuf)), "\t returnError\n");
+ state = ST_EXP_NIX;
+ }
+}
+/*---------------------------------------------------------------------------*
+ * reject
+ *---------------------------------------------------------------------------*/
+static void
+F_1_4(char *pbuf, int val)
+{
+#ifdef ST_DEBUG
+ sprintf((pbuf+strlen(pbuf)), "next_state: exec F_1_4, val = %d\n", val);
+#endif
+ if(val == -1)
+ {
+ sprintf((pbuf+strlen(pbuf)), "\t reject\n");
+ state = ST_EXP_NIX;
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * invoke component: invoke id
+ *---------------------------------------------------------------------------*/
+static void
+F_2(char *pbuf, int val)
+{
+#ifdef ST_DEBUG
+ sprintf((pbuf+strlen(pbuf)), "next_state: exec F_2, val = %d\n", val);
+#endif
+ if(val != -1)
+ {
+ sprintf((pbuf+strlen(pbuf)), "\t InvokeIdentifier = %d\n", val);
+ state = ST_EXP_OP_VAL;
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * return result: invoke id
+ *---------------------------------------------------------------------------*/
+static void
+F_RR2(char *pbuf, int val)
+{
+#ifdef ST_DEBUG
+ sprintf((pbuf+strlen(pbuf)), "next_state: exec F_RR2, val = %d\n", val);
+#endif
+ if(val != -1)
+ {
+ sprintf((pbuf+strlen(pbuf)), "\t InvokeIdentifier = %d\n", val);
+ state = ST_EXP_RR_OP_VAL;
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * invoke component: operation value
+ *---------------------------------------------------------------------------*/
+static void
+F_3(char *pbuf, int val)
+{
+#ifdef ST_DEBUG
+ sprintf((pbuf+strlen(pbuf)), "next_state: exec F_3, val = %d\n", val);
+#endif
+ if(val != -1)
+ {
+ sprintf((pbuf+strlen(pbuf)), "\t Operation Value = %s (%d)\n", opval_str(val), val);
+ state = ST_EXP_INFO;
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * return result: operation value
+ *---------------------------------------------------------------------------*/
+static void
+F_RR3(char *pbuf, int val)
+{
+#ifdef ST_DEBUG
+ sprintf((pbuf+strlen(pbuf)), "next_state: exec F_RR3, val = %d\n", val);
+#endif
+ if(val != -1)
+ {
+ sprintf((pbuf+strlen(pbuf)), "\t Operation Value = %s (%d)\n", opval_str(val), val);
+ state = ST_EXP_RR_RESULT;
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * return result: RESULT
+ *---------------------------------------------------------------------------*/
+static void
+F_RRR(char *pbuf, int val)
+{
+#ifdef ST_DEBUG
+ sprintf((pbuf+strlen(pbuf)), "next_state: exec F_RRR, val = %d\n", val);
+#endif
+ state = ST_EXP_NIX;
+}
+
+/*---------------------------------------------------------------------------*
+ *
+ *---------------------------------------------------------------------------*/
+static void
+F_4(char *pbuf, int val)
+{
+#ifdef ST_DEBUG
+ sprintf((pbuf+strlen(pbuf)), "next_state: exec F_4, val = %d\n", val);
+#endif
+ if(val == -1)
+ {
+ sprintf((pbuf+strlen(pbuf)), "\t specificChargingUnits\n");
+ state = ST_EXP_RUL;
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ *
+ *---------------------------------------------------------------------------*/
+static void
+F_4_1(char *pbuf, int val)
+{
+#ifdef ST_DEBUG
+ sprintf((pbuf+strlen(pbuf)), "next_state: exec F_4_1, val = %d\n", val);
+#endif
+ if(val == -1)
+ {
+ sprintf((pbuf+strlen(pbuf)), "\t freeOfCharge\n");
+ state = ST_EXP_NIX;
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ *
+ *---------------------------------------------------------------------------*/
+static void
+F_4_2(char *pbuf, int val)
+{
+#ifdef ST_DEBUG
+ sprintf((pbuf+strlen(pbuf)), "next_state: exec F_4_2, val = %d\n", val);
+#endif
+ if(val == -1)
+ {
+ sprintf((pbuf+strlen(pbuf)), "\t chargeNotAvailable\n");
+ state = ST_EXP_NIX;
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ *
+ *---------------------------------------------------------------------------*/
+static void
+F_5(char *pbuf, int val)
+{
+#ifdef ST_DEBUG
+ sprintf((pbuf+strlen(pbuf)), "next_state: exec F_5, val = %d\n", val);
+#endif
+ if(val == -1)
+ {
+ sprintf((pbuf+strlen(pbuf)), "\t recordedUnitsList [1]\n");
+ state = ST_EXP_RU;
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ *
+ *---------------------------------------------------------------------------*/
+static void
+F_6(char *pbuf, int val)
+{
+#ifdef ST_DEBUG
+ sprintf((pbuf+strlen(pbuf)), "next_state: exec F_6, val = %d\n", val);
+#endif
+ if(val == -1)
+ {
+ sprintf((pbuf+strlen(pbuf)), "\t RecordedUnits\n");
+ state = ST_EXP_RNOU;
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ *
+ *---------------------------------------------------------------------------*/
+static void
+F_7(char *pbuf, int val)
+{
+#ifdef ST_DEBUG
+ sprintf((pbuf+strlen(pbuf)), "next_state: exec F_7, val = %d\n", val);
+#endif
+ if(val != -1)
+ {
+ sprintf((pbuf+strlen(pbuf)), "\t NumberOfUnits = %d\n", val);
+ state = ST_EXP_TOCI;
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ *
+ *---------------------------------------------------------------------------*/
+static void
+F_8(char *pbuf, int val)
+{
+#ifdef ST_DEBUG
+ sprintf((pbuf+strlen(pbuf)), "next_state: exec F_8, val = %d\n", val);
+#endif
+ if(val != -1)
+ {
+ sprintf((pbuf+strlen(pbuf)), "\t typeOfChargingInfo = %s\n", val == 0 ? "subTotal" : "total");
+ state = ST_EXP_DBID;
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ *
+ *---------------------------------------------------------------------------*/
+static void
+F_9(char *pbuf, int val)
+{
+#ifdef ST_DEBUG
+ sprintf((pbuf+strlen(pbuf)), "next_state: exec F_9, val = %d\n", val);
+#endif
+ if(val != -1)
+ {
+ sprintf((pbuf+strlen(pbuf)), "\t AOCDBillingId = %s (%d)\n", bid_str(val), val);
+ state = ST_EXP_NIX;
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * state table
+ *---------------------------------------------------------------------------*/
+static struct statetab {
+ int currstate; /* input: current state we are in */
+ int form; /* input: current tag form */
+ int class; /* input: current tag class */
+ int code; /* input: current tag code */
+ void (*func)(char *,int); /* output: func to exec */
+} statetab[] = {
+
+/* current state tag form tag class tag code function */
+/* --------------------- ---------------------- ---------------------- ---------------------- ----------------*/
+
+/* invoke */
+
+ {ST_EXP_COMP_TYP, FAC_TAGFORM_CON, FAC_TAGCLASS_COS, 1, F_1_1 },
+ {ST_EXP_COMP_TYP, FAC_TAGFORM_CON, FAC_TAGCLASS_COS, 2, F_1_2 },
+ {ST_EXP_COMP_TYP, FAC_TAGFORM_CON, FAC_TAGCLASS_COS, 3, F_1_3 },
+ {ST_EXP_COMP_TYP, FAC_TAGFORM_CON, FAC_TAGCLASS_COS, 4, F_1_4 },
+ {ST_EXP_INV_ID, FAC_TAGFORM_PRI, FAC_TAGCLASS_UNI, FAC_CODEUNI_INT, F_2 },
+ {ST_EXP_OP_VAL, FAC_TAGFORM_PRI, FAC_TAGCLASS_UNI, FAC_CODEUNI_INT, F_3 },
+ {ST_EXP_INFO, FAC_TAGFORM_CON, FAC_TAGCLASS_UNI, FAC_CODEUNI_SEQ, F_4 },
+ {ST_EXP_INFO, FAC_TAGFORM_PRI, FAC_TAGCLASS_UNI, FAC_CODEUNI_NULL, F_4_1 },
+ {ST_EXP_INFO, FAC_TAGFORM_PRI, FAC_TAGCLASS_COS, 1, F_4_2 },
+ {ST_EXP_RUL, FAC_TAGFORM_CON, FAC_TAGCLASS_COS, 1, F_5 },
+ {ST_EXP_RU, FAC_TAGFORM_CON, FAC_TAGCLASS_UNI, FAC_CODEUNI_SEQ, F_6 },
+ {ST_EXP_RNOU, FAC_TAGFORM_PRI, FAC_TAGCLASS_UNI, FAC_CODEUNI_INT, F_7 },
+ {ST_EXP_TOCI, FAC_TAGFORM_PRI, FAC_TAGCLASS_COS, 2, F_8 },
+ {ST_EXP_DBID, FAC_TAGFORM_PRI, FAC_TAGCLASS_COS, 3, F_9 },
+
+/* return result */
+
+ {ST_EXP_RR_INV_ID, FAC_TAGFORM_PRI, FAC_TAGCLASS_UNI, FAC_CODEUNI_INT, F_RR2 },
+ {ST_EXP_RR_OP_VAL, FAC_TAGFORM_PRI, FAC_TAGCLASS_UNI, FAC_CODEUNI_INT, F_RR3 },
+ {ST_EXP_RR_RESULT, FAC_TAGFORM_CON, FAC_TAGCLASS_UNI, FAC_CODEUNI_SET, F_RRR },
+
+/* end */
+
+ {-1, -1, -1, -1, NULL }
+};
+
+/*---------------------------------------------------------------------------*
+ * state decode for do_component
+ *---------------------------------------------------------------------------*/
+static void
+next_state(char *pbuf, int class, int form, int code, int val)
+{
+ int i;
+
+#ifdef ST_DEBUG
+ sprintf((pbuf+strlen(pbuf)), "next_state: class=%d, form=%d, code=%d, val=%d\n", class, form, code, val);
+#endif
+
+ for(i=0; ; i++)
+ {
+ if((statetab[i].currstate > state) ||
+ (statetab[i].currstate == -1))
+ {
+ break;
+ }
+
+ if((statetab[i].currstate == state) &&
+ (statetab[i].form == form) &&
+ (statetab[i].class == class) &&
+ (statetab[i].code == code))
+ {
+ (*statetab[i].func)(pbuf, val);
+ break;
+ }
+ }
+}
+
+/* EOF */
+
diff --git a/usr.sbin/i4b/isdndecode/facility.h b/usr.sbin/i4b/isdndecode/facility.h
new file mode 100644
index 0000000..7080c22
--- /dev/null
+++ b/usr.sbin/i4b/isdndecode/facility.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * facility.h - Q.932 facility header file
+ * ---------------------------------------
+ *
+ * $Id: facility.h,v 1.2 1998/12/18 17:09:38 hm Exp $
+ *
+ * last edit-date: [Fri Dec 18 18:10:48 1998]
+ *
+ *---------------------------------------------------------------------------*/
+
+/* #define FAC_DEBUG */
+/* #define ST_DEBUG */
+
+/* protocols */
+#define FAC_PROTO_ROP 0x11
+#define FAC_PROTO_CMIP 0x12
+#define FAC_PROTO_ACSE 0x13
+
+/* tag classes */
+#define FAC_TAGCLASS_UNI 0x00
+#define FAC_TAGCLASS_APW 0x01
+#define FAC_TAGCLASS_COS 0x02
+#define FAC_TAGCLASS_PRU 0x03
+
+/* tag forms */
+#define FAC_TAGFORM_PRI 0x00
+#define FAC_TAGFORM_CON 0x01
+
+/* class UNIVERSAL values */
+#define FAC_CODEUNI_BOOL 1
+#define FAC_CODEUNI_INT 2
+#define FAC_CODEUNI_BITS 3
+#define FAC_CODEUNI_OCTS 4
+#define FAC_CODEUNI_NULL 5
+#define FAC_CODEUNI_OBJI 6
+#define FAC_CODEUNI_OBJD 7
+#define FAC_CODEUNI_EXT 8
+#define FAC_CODEUNI_REAL 9
+#define FAC_CODEUNI_ENUM 10
+#define FAC_CODEUNI_R11 11
+#define FAC_CODEUNI_R12 12
+#define FAC_CODEUNI_R13 13
+#define FAC_CODEUNI_R14 14
+#define FAC_CODEUNI_R15 15
+#define FAC_CODEUNI_SEQ 16
+#define FAC_CODEUNI_SET 17
+#define FAC_CODEUNI_NSTR 18
+#define FAC_CODEUNI_PSTR 19
+#define FAC_CODEUNI_TSTR 20
+#define FAC_CODEUNI_VSTR 21
+#define FAC_CODEUNI_ISTR 22
+#define FAC_CODEUNI_UTIME 23
+#define FAC_CODEUNI_GTIME 24
+#define FAC_CODEUNI_GSTR 25
+#define FAC_CODEUNI_VISTR 26
+#define FAC_CODEUNI_GNSTR 27
+
+/* operation values */
+#define FAC_OPVAL_UUS 1
+#define FAC_OPVAL_CUG 2
+#define FAC_OPVAL_MCID 3
+#define FAC_OPVAL_BTPY 4
+#define FAC_OPVAL_ETPY 5
+#define FAC_OPVAL_ECT 6
+
+#define FAC_OPVAL_DIV_ACT 7
+#define FAC_OPVAL_DIV_DEACT 8
+#define FAC_OPVAL_DIV_ACTSN 9
+#define FAC_OPVAL_DIV_DEACTSN 10
+#define FAC_OPVAL_DIV_INTER 11
+#define FAC_OPVAL_DIV_INFO 12
+#define FAC_OPVAL_DIV_CALLDEF 13
+#define FAC_OPVAL_DIV_CALLRER 14
+#define FAC_OPVAL_DIV_LINF2 15
+#define FAC_OPVAL_DIV_INVS 16
+#define FAC_OPVAL_DIV_INTER1 17
+#define FAC_OPVAL_DIV_LINF1 18
+#define FAC_OPVAL_DIV_LINF3 19
+
+#define FAC_OPVAL_ER_CRCO 20
+#define FAC_OPVAL_ER_MGMT 21
+#define FAC_OPVAL_ER_CANC 22
+
+#define FAC_OPVAL_MLPP_QUERY 24
+#define FAC_OPVAL_MLPP_CALLR 25
+#define FAC_OPVAL_MLPP_CALLP 26
+
+#define FAC_OPVAL_AOC_REQ 30
+#define FAC_OPVAL_AOC_S_CUR 31
+#define FAC_OPVAL_AOC_S_SPC 32
+#define FAC_OPVAL_AOC_D_CUR 33
+#define FAC_OPVAL_AOC_D_UNIT 34
+#define FAC_OPVAL_AOC_E_CUR 35
+#define FAC_OPVAL_AOC_E_UNIT 36
+#define FAC_OPVAL_AOC_IDOFCRG 37
+
+#define FAC_OPVAL_CONF_BEG 40
+#define FAC_OPVAL_CONF_ADD 41
+#define FAC_OPVAL_CONF_SPLIT 42
+#define FAC_OPVAL_CONF_DROP 43
+#define FAC_OPVAL_CONF_ISOLATE 44
+#define FAC_OPVAL_CONF_REATT 45
+#define FAC_OPVAL_CONF_PDISC 46
+#define FAC_OPVAL_CONF_FCONF 47
+#define FAC_OPVAL_CONF_END 48
+#define FAC_OPVAL_CONF_IDCFE 49
+
+#define FAC_OPVAL_REVC_REQ 60
+
+enum states {
+ ST_EXP_COMP_TYP,
+ ST_EXP_INV_ID,
+ ST_EXP_OP_VAL,
+ ST_EXP_INFO,
+ ST_EXP_RUL,
+ ST_EXP_RU,
+ ST_EXP_RNOU,
+ ST_EXP_TOCI,
+ ST_EXP_DBID,
+
+ ST_EXP_RR_INV_ID,
+ ST_EXP_RR_OP_VAL,
+ ST_EXP_RR_RESULT,
+
+ ST_EXP_NIX
+};
+
+/* EOF */
+
diff --git a/usr.sbin/i4b/isdndecode/isdndecode.8 b/usr.sbin/i4b/isdndecode/isdndecode.8
new file mode 100644
index 0000000..8594686
--- /dev/null
+++ b/usr.sbin/i4b/isdndecode/isdndecode.8
@@ -0,0 +1,190 @@
+.\"
+.\" Copyright (c) 1998 Hellmuth Michaelis. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id: isdndecode.8,v 1.3 1998/12/18 17:09:38 hm Exp $
+.\"
+.\" last edit-date: [Fri Dec 18 18:11:31 1998]
+.\"
+.\" -hm writing manual page
+.\"
+.Dd September 17, 1998
+.Dt isdndecode 8
+.Sh NAME
+.Nm isdndecode
+.Nd isdn4bsd ISDN protocol decode utility
+.Sh SYNOPSIS
+.Nm isdndecode
+.Op Fl a
+.Op Fl b
+.Op Fl d
+.Op Fl f Ar filename
+.Op Fl h
+.Op Fl i
+.Op Fl l
+.Op Fl o
+.Op Fl p Ar filename
+.Op Fl u Ar number
+.Op Fl B
+.Op Fl P
+.Op Fl R Ar unit
+.Op Fl T Ar unit
+.Sh DESCRIPTION
+.Nm isdndecode
+is part of the isdn4bsd package and is used to provide the user with a
+detailed mnemonic display of the layers 1, 2 and 3 protocol activities on
+the D channel and hex dump of the B channel(s) activities.
+.Pp
+Together with two passive supported cards and an easy to build cable it can
+also be used to monitor the complete traffic on a S0 bus providing S0 bus
+analyzer features.
+.Pp
+The
+.Nm
+utility is only available for passive supported cards.
+.Pp
+The following options can be used:
+.Bl -tag -width Ds
+
+.It Fl a
+Run
+.Nm
+in analyzer mode by using two passive cards and a custom cable which can
+be build as described in the file
+.Em cable.txt
+in the isdn4bsd source distribution. One card acts as a receiver for the
+transmitting direction on the S0 bus while the other card acts as a receiver
+for the receiving direction on the S0 bus. Complete traffic monitoring is
+possible using this setup.
+
+.It Fl b
+switch B channel tracing on (default off).
+
+.It Fl d
+switch D channel tracing off (default on).
+
+.It Fl f
+Use
+.Ar filename
+as the name of a file into which to write tracing output (default filename is
+isdndecode<n> where n is the number of the unit to decode).
+
+.It Fl h
+switch display of header off (default on).
+
+.It Fl i
+print layer 1 (I.430) INFO signals to monitor layer 1 activity (default off).
+
+.It Fl l
+switch displaying of Layer 2 (Q.921) frames off (default on).
+
+.It Fl o
+switch off writing decode output to a file (default on).
+
+.It Fl p
+Use
+.Ar filename
+as the name of a file used for the -B and -P options (default filename
+is isdntracebin<n> where n is the number of the unit to decode).
+
+.It Fl u
+Use
+.Ar number
+as the unit number of the controller card to decode (default 0).
+
+.It Fl B
+Write undecoded binary decode data to a file for later or remote
+analyzing (default off).
+
+.It Fl P
+Read undecoded binary decode data from file instead from device (default off).
+
+.It Fl R
+Use
+.Ar unit
+as the receiving interface unit number in analyze mode.
+
+.It Fl T
+Use
+.Ar unit
+as the transmitting interface unit number in analyze mode.
+
+.Pp
+When the USR1 signal is sent to a
+.Nm
+process, the currently used logfiles are reopened, so that logfile
+rotation becomes possible.
+.Pp
+The decode output should be obvious. It is very handy to have the following
+standard texts available when tracing ISDN protocols:
+.Pp
+.Bl -tag -width Ds -compact -offset indent
+.It Ar I.430
+ISDN BRI layer 1 protocol description.
+.It Ar Q.921
+ISDN D-channel layer 2 protocol description.
+.It Ar Q.931
+ISDN D-channel layer 3 protocol description.
+.El
+.Pp
+
+.Sh FILES
+.Bl -tag -width daddeldi -compact
+.It Pa /dev/i4btrc<n>
+The devicefile(s) used to get the decode messages for ISDN card unit <n>
+out of the kernel.
+.El
+
+.Sh EXAMPLES
+The command:
+.Bd -literal -offset indent
+isdndecode -f /var/tmp/isdn.decode
+.Ed
+.Pp
+will start D channel tracing on passive controller 0 with all except B
+channel tracing enabled and logs everything into the output file
+/tmp/isdn.decode.
+
+.Sh SEE ALSO
+.Xr isdnd 8
+
+.Sh BUGS
+Still one left.
+
+.Sh STANDARDS
+ITU Recommendations I.430, Q.920, Q.921, Q.930, Q.931
+.Pp
+ITU Recommendation Q.932 (03/93), Q.950 (03/93)
+.Pp
+ETSI Recommendation ETS 300 179 (10/92), ETS 300 180 (10/92)
+.Pp
+ETSI Recommendation ETS 300 181 (04/93), ETS 300 182 (04/93)
+.Pp
+ITU Recommendation X.208, X.209
+
+.Sh AUTHOR
+The
+.Nm
+utility and this manual page was written by Hellmuth Michaelis,
+he can be reached at hm@kts.org.
+
diff --git a/usr.sbin/i4b/isdndecode/layer1.c b/usr.sbin/i4b/isdndecode/layer1.c
new file mode 100644
index 0000000..8dee4b7
--- /dev/null
+++ b/usr.sbin/i4b/isdndecode/layer1.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * layer1.c - isdndecode, decode and print layer 1 information
+ * -----------------------------------------------------------
+ *
+ * $Id: layer1.c,v 1.2 1998/12/18 17:09:38 hm Exp $
+ *
+ * last edit-date: [Fri Dec 18 18:11:55 1998]
+ *
+ *---------------------------------------------------------------------------*/
+
+#include "decode.h"
+
+/*---------------------------------------------------------------------------*
+ * decode layer 1 information
+ *---------------------------------------------------------------------------*/
+void
+layer1(char *buffer, unsigned char *buf)
+{
+ switch(*buf)
+ {
+ case INFO0:
+ strcpy(buffer,"L1 INFO0 (No Signal)\n");
+ break;
+
+ case INFO1_8:
+ strcpy(buffer,"L1 INFO1 (Activation Request, Priority = 8)\n");
+ break;
+
+ case INFO1_10:
+ strcpy(buffer,"L1 INFO1 (Activation Request, Priority = 10)\n");
+ break;
+
+ case INFO2:
+ strcpy(buffer,"L1 INFO2 (Pending Activation)\n");
+ break;
+
+ case INFO3:
+ strcpy(buffer,"L1 INFO3 (Synchronized)\n");
+ break;
+
+ case INFO4_8:
+ strcpy(buffer,"L1 INFO4 (Activated, Priority = 8/9)\n");
+ break;
+
+ case INFO4_10:
+ strcpy(buffer,"L1 INFO4 (Activated, Priority = 10/11)\n");
+ break;
+
+ default:
+ sprintf(buffer,"L1 ERROR, invalid INFO value 0x%x!\n", *buf);
+ break;
+ }
+}
+
+/* EOF */
diff --git a/usr.sbin/i4b/isdndecode/layer2.c b/usr.sbin/i4b/isdndecode/layer2.c
new file mode 100644
index 0000000..b7997dd
--- /dev/null
+++ b/usr.sbin/i4b/isdndecode/layer2.c
@@ -0,0 +1,298 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * layer2.c - decode and print layer 2 (Q.921) information
+ * -------------------------------------------------------
+ *
+ * $Id: layer2.c,v 1.3 1998/12/18 17:09:38 hm Exp $
+ *
+ * last edit-date: [Fri Dec 18 18:12:09 1998]
+ *
+ *---------------------------------------------------------------------------*/
+
+#include "decode.h"
+
+/*---------------------------------------------------------------------------*
+ * decode poll bit
+ *---------------------------------------------------------------------------*/
+static void
+poll(int layer, char *buffer, int cnt, unsigned char value, unsigned char mask)
+{
+ sprintline(layer, buffer, cnt, value, mask, "P/F, Poll = %s", (value & mask) ? "Immediate Response Required" : "No Immediate Response Required");
+}
+
+/*---------------------------------------------------------------------------*
+ * decode final bit
+ *---------------------------------------------------------------------------*/
+static void
+final(int layer, char *buffer, int cnt, unsigned char value, unsigned char mask)
+{
+ sprintline(layer, buffer, cnt, value, mask, "P/F, Final = %s", (value & mask) ? "Result of Poll" : "No Result of Poll");
+}
+
+/*---------------------------------------------------------------------------*
+ * decode protocol specified in Q.921
+ *---------------------------------------------------------------------------*/
+int
+layer2(char *pbuf, unsigned char *buf, int dir, int printit)
+{
+ int sap, tei, cmd;
+ int cnt = 0;
+ char locbuf[32000];
+ char *lbufp = &locbuf[0];
+ char buffer[80];
+
+ *lbufp = '\0';
+ *pbuf = '\0';
+
+ /* address high */
+
+ sap = (buf[0] >> 2) & 0x3f;
+
+ if(sap == 0)
+ strcpy(buffer, "Call Control");
+ else if((sap >= 1) && (sap <= 15))
+ strcpy(buffer, "Reserved");
+ else if(sap == 16)
+ strcpy(buffer, "X.25");
+ else if((sap >= 17) && (sap <= 31))
+ strcpy(buffer, "Reserved");
+ else if(sap == 63)
+ strcpy(buffer, "Layer 2 Management");
+ else
+ strcpy(buffer, "Not available for Q.921");
+ sprintline(2, lbufp+strlen(lbufp), cnt, buf[0], 0xfc, "SAPI = %d (%s)", sap, buffer);
+
+ if(dir == FROM_TE)
+ cmd = !(buf[0] & 0x02);
+ else
+ cmd = buf[0] & 0x02;
+
+ sprintline(2, lbufp+strlen(lbufp), cnt, buf[0], 0x02, "C/R = %s", cmd ? "Command" : "Response");
+ extension(2, lbufp+strlen(lbufp), cnt, buf[0], 0x01);
+ cnt++;
+
+ /* address low */
+
+ tei = buf[1] >> 1;
+
+ if((tei >= 0) && (tei <= 63))
+ strcpy(buffer, "Non-automatic TEI");
+ else if((tei >= 64) && (tei <= 126))
+ strcpy(buffer, "Automatic TEI");
+ if(tei == 127)
+ strcpy(buffer, "Group TEI");
+
+ sprintline(2, lbufp+strlen(lbufp), cnt, buf[1], 0xfe, "TEI = %d (%s)", tei, buffer);
+ extension(2, lbufp+strlen(lbufp), cnt, buf[1], 0x01);
+ cnt++;
+
+ /* control 1 */
+
+ if((buf[2] & 0x03) == 0x03)
+ {
+ /* U-frame */
+
+ if((buf[2] & 0xef) == 0x6f)
+ {
+ /* SABME */
+
+ sprintline(2, lbufp+strlen(lbufp), cnt, buf[2], 0xef, "U-Frame: SABME (Set Asynchonous Balanced Mode)");
+ poll(2, lbufp+strlen(lbufp), cnt, buf[2], 0x10);
+ cnt++;
+ }
+ else if((buf[2] & 0xef) == 0x0f)
+ {
+ /* DM */
+
+ sprintline(2, lbufp+strlen(lbufp), cnt, buf[2], 0xef, "U-Frame: DM (Disconnected Mode)");
+ final(2, lbufp+strlen(lbufp), cnt, buf[2], 0x10);
+ cnt++;
+ }
+ else if((buf[2] & 0xef) == 0x03)
+ {
+ /* UI */
+
+ sprintline(2, lbufp+strlen(lbufp), cnt, buf[2], 0xef, "U-Frame: UI (Unnumbered Information)");
+ poll(2, lbufp+strlen(lbufp), cnt, buf[2], 0x10);
+ cnt++;
+
+ if(sap == 63 && (buf[3] == 0x0f)) /* TEI management */
+ {
+ sprintline(2, lbufp+strlen(lbufp), cnt, buf[3], 0xff, "MEI (Management Entity Identifier)");
+ cnt++;
+ sprintline(2, lbufp+strlen(lbufp), cnt, buf[4], 0xff, "Ri = 0x%04x (Reference number high)", (buf[4] << 8) | buf[5]);
+ cnt++;
+ sprintline(2, lbufp+strlen(lbufp), cnt, buf[5], 0xff, "Ri (Reference Number low)");
+ cnt++;
+
+ switch(buf[6])
+ {
+ case 0x01:
+ strcpy(buffer, "Identity Request");
+ break;
+ case 0x02:
+ strcpy(buffer, "Identity Assigned");
+ break;
+ case 0x03:
+ strcpy(buffer, "Identity denied");
+ break;
+ case 0x04:
+ strcpy(buffer, "Identity Check Request");
+ break;
+ case 0x05:
+ strcpy(buffer, "Identity Check Response");
+ break;
+ case 0x06:
+ strcpy(buffer, "Identity Remove");
+ break;
+ case 0x07:
+ strcpy(buffer, "Identity Verify");
+ break;
+ default:
+ strcpy(buffer, "undefined");
+ break;
+ }
+
+ sprintline(2, lbufp+strlen(lbufp), cnt, buf[6], 0xff, "TEI %s (Message Type %d)", buffer, buf[6]);
+ cnt++;
+
+ switch(buf[6])
+ {
+ case 0x01:
+ strcpy(buffer, "Any TEI value acceptable");
+ break;
+ case 0x02:
+ strcpy(buffer, "");
+ break;
+ case 0x03:
+ strcpy(buffer, "No TEI Value available");
+ break;
+ case 0x04:
+ strcpy(buffer, "Check all TEI values");
+ break;
+ case 0x05:
+ strcpy(buffer, "");
+ break;
+ case 0x06:
+ strcpy(buffer, "Request for removal of all TEI values");
+ break;
+ case 0x07:
+ strcpy(buffer, "");
+ break;
+ default:
+ strcpy(buffer, "");
+ break;
+ }
+ if(((buf[7] >> 1) & 0x7f) == 127)
+ sprintline(2, lbufp+strlen(lbufp), cnt, buf[7], 0xfe, "Ai = %d (Action Indicator = %s)", (buf[7] >> 1) & 0x7f, buffer);
+ else
+ sprintline(2, lbufp+strlen(lbufp), cnt, buf[7], 0xfe, "Ai = %d (Action Indicator)", (buf[7] >> 1) & 0x7f);
+ extension(2, lbufp+strlen(lbufp), cnt, buf[7], 0x01);
+ cnt++;
+ }
+ }
+ else if((buf[2] & 0xef) == 0x43)
+ {
+ /* DISC */
+
+ sprintline(2, lbufp+strlen(lbufp), cnt, buf[2], 0xef, "U-Frame: DISC (Disconnect)");
+ poll(2, lbufp+strlen(lbufp), cnt, buf[2], 0x10);
+ cnt++;
+ }
+ else if((buf[2] & 0xef) == 0x63)
+ {
+ /* UA */
+
+ sprintline(2, lbufp+strlen(lbufp), cnt, buf[2], 0xef, "U-Frame: UA (Unnumbered Acknowledge)");
+ final(2, lbufp+strlen(lbufp), cnt, buf[2], 0x10);
+ cnt++;
+ }
+ else if((buf[2] & 0xef) == 0x87)
+ {
+ /* FRMR */
+
+ sprintline(2, lbufp+strlen(lbufp), cnt, buf[2], 0xef, "U-Frame: FRMR (Frame Reject)");
+ final(2, lbufp+strlen(lbufp), cnt, buf[2], 0x10);
+ cnt++;
+ }
+ else if((buf[2] & 0xef) == 0x9f)
+ {
+ /* XID */
+
+ sprintline(2, lbufp+strlen(lbufp), cnt, buf[2], 0xef, "U-Frame: XID (Exchange Identification)");
+ if(cmd)
+ poll(2, lbufp+strlen(lbufp), cnt, buf[2], 0x10);
+ else
+ final(2, lbufp+strlen(lbufp), cnt, buf[2], 0x10);
+ cnt++;
+ }
+
+ }
+ else if((buf[2] & 0x03) == 0x01)
+ {
+ /* S-frame */
+
+ if(buf[2] == 0x01)
+ strcpy(buffer, "RR (Receiver Ready)");
+ else if(buf[2] == 0x05)
+ strcpy(buffer, "RNR (Receiver Not Ready)");
+ else if(buf[2] == 0x09)
+ strcpy(buffer, "REJ (Reject)");
+ else
+ strcpy(buffer, "Unknown");
+
+ sprintline(2, lbufp+strlen(lbufp), cnt, buf[2], 0xff, "S-Frame: %s", buffer);
+ cnt++;
+
+ sprintline(2, lbufp+strlen(lbufp), cnt, buf[3], 0xfe, "N(R) = %d (receive sequence number)", (buf[3] >> 1) & 0x7f);
+ if(cmd)
+ poll(2, lbufp+strlen(lbufp), cnt, buf[3], 0x01);
+ else
+ final(2, lbufp+strlen(lbufp), cnt, buf[3], 0x01);
+ cnt++;
+
+ }
+ else if((buf[2] & 0x01) == 0x00)
+ {
+ /* I-frame */
+
+ sprintline(2, lbufp+strlen(lbufp), cnt, buf[2], 0xfe, "N(S) = %d (send sequence number)", (buf[2] >> 1) & 0x7f);
+ sprintline(2, lbufp+strlen(lbufp), cnt, buf[2], 0x01, "I-Frame: Information transfer");
+ cnt++;
+
+ sprintf(buffer, "N(R) = %d", (buf[3] >> 1) & 0x7f);
+ sprintline(2, lbufp+strlen(lbufp), cnt, buf[3], 0xfe, "N(R) = %d (receive sequence number)", (buf[3] >> 1) & 0x7f);
+ poll(2, lbufp+strlen(lbufp), cnt, buf[3], 0x01);
+ cnt++;
+
+ }
+
+ sprintf((pbuf+strlen(pbuf)),"%s", &locbuf[0]);
+ return (cnt);
+}
+
+/* EOF */
diff --git a/usr.sbin/i4b/isdndecode/layer3.c b/usr.sbin/i4b/isdndecode/layer3.c
new file mode 100644
index 0000000..6376a13
--- /dev/null
+++ b/usr.sbin/i4b/isdndecode/layer3.c
@@ -0,0 +1,508 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * layer3.c - decode and print layer 3 (Q.931) information
+ * -------------------------------------------------------
+ *
+ * $Id: layer3.c,v 1.5 1998/12/18 17:09:38 hm Exp $
+ *
+ * last edit-date: [Fri Dec 18 18:12:21 1998]
+ *
+ *---------------------------------------------------------------------------*/
+
+#include "decode.h"
+
+char *mttab[] = {
+
+/* 0x00 */ /* call establishment group */
+
+ "ESCAPE",
+ "ALERTING",
+ "CALL PROCEEDING",
+ "PROGRESS",
+ "undefined (0x04)",
+ "SETUP",
+ "undefined (0x06)",
+ "CONNECT",
+ "undefined (0x08)",
+ "undefined (0x09)",
+ "undefined (0x0a)",
+ "undefined (0x0b)",
+ "undefined (0x0c)",
+ "SETUP ACKNOWLEDGE",
+ "undefined (0x0e)",
+ "CONNECT ACKNOWLEDGE",
+
+/* 0x10 */
+ "undefined (0x10)",
+ "undefined (0x11)",
+ "undefined (0x12)",
+ "undefined (0x13)",
+ "undefined (0x14)",
+ "undefined (0x15)",
+ "undefined (0x16)",
+ "undefined (0x17)",
+ "undefined (0x18)",
+ "undefined (0x19)",
+ "undefined (0x1a)",
+ "undefined (0x1b)",
+ "undefined (0x1c)",
+ "undefined (0x1d)",
+ "undefined (0x1e)",
+ "undefined (0x1f)",
+
+/* 0x20 */
+
+ "USER INFORMATION", /* call information phase */
+ "SUSPEND REJECT",
+ "RESUME REJECT",
+ "undefined (0x23)",
+ "HOLD",
+ "SUSPEND",
+ "RESUME",
+ "undefined (0x27)",
+ "HOLD ACKNOWLEDGE",
+ "undefined (0x29)",
+ "undefined (0x2a)",
+ "undefined (0x2b)",
+ "undefined (0x2c)",
+ "SUSPEND ACKNOWLEDGE",
+ "RESUME ACKNOWLEDGE",
+ "undefined (0x2f)",
+
+/* 0x30 */
+
+ "HOLD REJECT",
+ "RETRIEVE",
+ "undefined (0x32)",
+ "RETRIEVE ACKNOWLEDGE",
+ "undefined (0x34)",
+ "undefined (0x35)",
+ "undefined (0x36)",
+ "RETRIEVE REJECT",
+ "undefined (0x38)",
+ "undefined (0x39)",
+ "undefined (0x3a)",
+ "undefined (0x3b)",
+ "undefined (0x3c)",
+ "undefined (0x3d)",
+ "undefined (0x3e)",
+ "undefined (0x3f)",
+
+/* 0x40 */
+
+ "DETACH", /* call clearing */
+ "undefined (0x41)",
+ "undefined (0x42)",
+ "undefined (0x43)",
+ "undefined (0x44)",
+ "DISCONNECT",
+ "RESTART",
+ "undefined (0x47)",
+ "DETACH ACKNOWLEDGE",
+ "undefined (0x49)",
+ "undefined (0x4a)",
+ "undefined (0x4b)",
+ "undefined (0x4c)",
+ "RELEASE",
+ "RESTART ACKNOWLEDGE",
+ "undefined (0x4f)",
+
+/* 0x50 */
+
+ "undefined (0x50)",
+ "undefined (0x51)",
+ "undefined (0x52)",
+ "undefined (0x53)",
+ "undefined (0x54)",
+ "undefined (0x55)",
+ "undefined (0x56)",
+ "undefined (0x57)",
+ "undefined (0x58)",
+ "undefined (0x59)",
+ "RELEASE COMPLETE",
+ "undefined (0x5b)",
+ "undefined (0x5c)",
+ "undefined (0x5d)",
+ "undefined (0x5e)",
+ "undefined (0x5f)",
+
+/* 0x60 */
+
+ "SEGMENT", /* misc messages */
+ "undefined (0x61)",
+ "FACILITY",
+ "undefined (0x63)",
+ "REGISTER",
+ "undefined (0x65)",
+ "undefined (0x66)",
+ "undefined (0x67)",
+ "CANCEL ACKNOWLEDGE",
+ "undefined (0x69)",
+ "FACILITY ACKNOWLEDGE",
+ "undefined (0x6b)",
+ "REGISTER ACKNOWLEDGE",
+ "undefined (0x6d)",
+ "NOTIFY",
+ "undefined (0x6f)",
+
+/* 0x70 */
+
+ "CANCEL REJECT",
+ "undefined (0x71)",
+ "FACILITY REJECT",
+ "undefined (0x73)",
+ "REGISTER REJECT",
+ "STATUS ENQIRY",
+ "undefined (0x76)",
+ "undefined (0x77)",
+ "undefined (0x78)",
+ "CONGESTION CONTROL",
+ "undefined (0x7a)",
+ "INFORMATION",
+ "undefined (0x7c)",
+ "STATUS",
+ "undefined (0x7e)",
+ "undefined (0x7f)",
+};
+
+#define MTTAB_MAX 0x7f
+
+extern int f_null(char *pbuf, unsigned char *buf, int off);
+extern int f_bc(char *pbuf, unsigned char *buf, int off);
+extern int f_cause(char *pbuf, unsigned char *buf, int off);
+extern int f_cstat(char *pbuf, unsigned char *buf, int off);
+extern int f_chid(char *pbuf, unsigned char *buf, int off);
+extern int f_fac(char *pbuf, unsigned char *buf, int off);
+extern int f_progi(char *pbuf, unsigned char *buf, int off);
+extern int f_displ(char *pbuf, unsigned char *buf, int off);
+extern int f_date(char *pbuf, unsigned char *buf, int off);
+extern int f_cnu(char *pbuf, unsigned char *buf, int off);
+extern int f_cgpn(char *pbuf, unsigned char *buf, int off);
+extern int f_cdpn(char *pbuf, unsigned char *buf, int off);
+extern int f_hlc(char *pbuf, unsigned char *buf, int off);
+
+struct ie {
+ unsigned char code; /* information element identifier code */
+ char *name; /* ie name */
+ int (*func) (char *pbuf, unsigned char *buf, int off); /* decode function */
+} ietab[] = {
+ { 0x00, "segmented message", f_null },
+ { 0x04, "bearer capability", f_bc },
+ { 0x08, "cause", f_cause },
+ { 0x0c, "connected address", f_null },
+ { 0x0d, "extended facility", f_null },
+ { 0x10, "call identity", f_null },
+ { 0x14, "call state", f_cstat },
+ { 0x18, "channel id", f_chid },
+ { 0x19, "data link connection id", f_null },
+ { 0x1c, "facility", f_fac },
+ { 0x1e, "progress indicator", f_progi },
+ { 0x20, "network specific facilities", f_null },
+ { 0x24, "terminal capabilities", f_null },
+ { 0x27, "notification indicator", f_null },
+ { 0x28, "display", f_displ },
+ { 0x29, "date/time", f_date },
+ { 0x2c, "keypad", f_null },
+ { 0x30, "keypad echo", f_null },
+ { 0x32, "information request", f_null },
+ { 0x34, "signal", f_null },
+ { 0x36, "switchhook", f_null },
+ { 0x38, "feature activation", f_null },
+ { 0x39, "feature indication", f_null },
+ { 0x3a, "service profile id", f_null },
+ { 0x3b, "endpoint identifier", f_null },
+ { 0x40, "information rate", f_null },
+ { 0x41, "precedence level", f_null },
+ { 0x42, "end-to-end transit delay", f_null },
+ { 0x43, "transit delay detection", f_null },
+ { 0x44, "packet layer binary parms", f_null },
+ { 0x45, "packet layer window size", f_null },
+ { 0x46, "packet size", f_null },
+ { 0x47, "closed user group", f_null },
+ { 0x48, "link layer core parameters", f_null },
+ { 0x49, "link layer protocol parms", f_null },
+ { 0x4a, "reverse charging information", f_null },
+ { 0x4c, "connected number", f_cnu },
+ { 0x4d, "connected subaddress", f_null },
+ { 0x50, "X.213 priority", f_null },
+ { 0x51, "report type", f_null },
+ { 0x53, "link integrity verification", f_null },
+ { 0x57, "PVC status", f_null },
+ { 0x6c, "calling party number", f_cnu },
+ { 0x6d, "calling party subaddress", f_null },
+ { 0x70, "called party number", f_cnu },
+ { 0x71, "called party subaddress", f_null },
+ { 0x74, "redirecting number", f_null },
+ { 0x78, "transit network selection", f_null },
+ { 0x79, "restart indicator", f_null },
+ { 0x7c, "low layer compatibility", f_null },
+ { 0x7d, "high layer compatibility", f_hlc },
+ { 0x7e, "user-user", f_null },
+ { 0x7f, "escape for extension", f_null },
+ { 0xff, "unknown information element", f_null }
+};
+
+/*---------------------------------------------------------------------------*
+ * decode Q.931 protocol
+ *---------------------------------------------------------------------------*/
+void
+layer3(char *pbuf, int n, int off, unsigned char *buf)
+{
+ char buffer[256];
+ int codeset = 0;
+ int codelock = 0;
+ int oldcodeset = 0;
+
+ int pd;
+ int len;
+ int j;
+ int i;
+
+ if(n <= 0)
+ return;
+
+ *pbuf = '\0';
+
+ i = 0;
+
+ /* protocol discriminator */
+
+ pd = buf[i];
+
+ if(pd >= 0x00 && pd <= 0x07)
+ sprintf(buffer, "User-User IE (0x%02x)",pd);
+ else if(pd == 0x08)
+ sprintf(buffer, "Q.931/I.451");
+ else if(pd >= 0x10 && pd <= 0x3f)
+ sprintf(buffer, "Other Layer 3 or X.25 (0x%02x)",pd);
+ else if(pd >= 0x40 && pd <= 0x4f)
+ sprintf(buffer, "National Use (0x%02x)",pd);
+ else if(pd >= 0x50 && pd <= 0xfe)
+ sprintf(buffer, "Other Layer 3 or X.25 (0x%02x)",pd);
+ else
+ sprintf(buffer, "Reserved (0x%02x)",pd);
+
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, pd, 0xff, "Protocol discriminator = %s", buffer);
+ i++;
+
+ /* call reference */
+
+ len = buf[i] & 0x0f;
+
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0xf0, "Call Reference");
+
+ switch(len)
+ {
+ case 0:
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x0f, "Length of Call Reference = 0 (Dummy CR)");
+ break;
+ case 1:
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x0f, "Length of Call Reference = 1");
+ i++;
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x80, "Call Reference sent %s origination side", (buf[i] & 0x80) ? "to" : "from");
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x7f, "Call Reference = %d = 0x%02x", (buf[i] & 0x7f), (buf[i] & 0x7f));
+ break;
+ case 2:
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x0f, "Length of Call Reference = 2");
+ i++;
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x80, "Call Reference sent %s origination side", (buf[i] & 0x80) ? "to" : "from");
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x7f, "Call reference = %d = %02x", (buf[i] & 0x7f));
+ i++;
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0xff, "Call reference = %d = %02x", (buf[i]));
+ break;
+ }
+ i++;
+
+ /* message type */
+
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x80, "Message type extension = %d", buf[i] & 0x80 ? 1 : 0);
+
+ if(buf[i] <= MTTAB_MAX)
+ strcpy(buffer, mttab[buf[i]]);
+ else
+ sprintf(buffer, "unknown (0x%02x)", buf[i]);
+
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x7f, "Message type = %s", buffer);
+ i++;
+
+ /* information elements */
+
+ for (; i < n;)
+ {
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x80, "%s Information element", buf[i] & 0x80 ? "Single octet" : "Variable length");
+
+ if(buf[i] & 0x80)
+ {
+ /* single octett info element type 1 */
+
+ if((buf[i] & 0x70) == 0x00)
+ {
+ strcpy(buffer, "Reserved");
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x70, "Reserved");
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x0f, "Reserved, content of IE");
+ }
+ else if((buf[i] & 0x70) == 0x10)
+ {
+ strcpy(buffer, "Shift");
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x70, "Shift");
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x08, "%s shift", buf[i] & 0x08 ? "Non-locking" : "Locking");
+
+ switch(buf[i] & 0x07)
+ {
+ case 0:
+ strcpy(buffer, "Not applicable");
+ break;
+ case 1:
+ case 2:
+ case 3:
+ sprintf(buffer, "Reserved (%d)", buf[i] & 0x07);
+ break;
+ case 4:
+ strcpy(buffer, "Codeset 4 (ISO/IEC)");
+ break;
+ case 5:
+ strcpy(buffer, "Codeset 5 (National use)");
+ break;
+ case 6:
+ strcpy(buffer, "Codeset 6 (Local network specific)");
+ break;
+ case 7:
+ strcpy(buffer, "Codeset 7 (User specific)");
+ break;
+ }
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x07, "%s", buffer);
+ break;
+ }
+ else if((buf[i] & 0x70) == 0x30)
+ {
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x70, "Congestion Level");
+ switch(buf[i] & 0x0f)
+ {
+ case 0x00:
+ strcpy(buffer, "receiver ready");
+ break;
+ case 0x0f:
+ strcpy(buffer, "receiver not ready");
+ break;
+ default:
+ sprintf(buffer, "reserved (0x%02x)", buf[i] & 0x0f);
+ break;
+ }
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x0f, "Congestion Level = ", buffer);
+ break;
+ }
+ else if((buf[i] & 0x70) == 0x50)
+ {
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x70, "Repeat Indicator");
+ switch(buf[i] & 0x0f)
+ {
+ case 0x02:
+ strcpy(buffer, "Prioritized list for selecting one possibility");
+ break;
+ default:
+ sprintf(buffer, "reserved (0x%02x)", buf[i] & 0x0f);
+ break;
+ }
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x0f, "Repeat indication = ", buffer);
+ break;
+ }
+
+ /* single octett info element type 2 */
+
+ else if((buf[i] & 0x7f) == 0x20)
+ {
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x7f, "More data");
+ }
+ else if((buf[i] & 0x7f) == 0x21)
+ {
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x7f, "Sending complete");
+ }
+ else
+ {
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0xff, "UNKNOWN single octet IE = 0x%02x", buf[i]);
+ }
+ i++; /* next */
+ }
+ else
+ {
+ if(codeset == 0)
+ {
+ struct ie *iep = &ietab[0];
+
+ for(;;)
+ {
+ if((iep->code == buf[i]) ||
+ (iep->code == 0xff))
+ break;
+ iep++;
+ }
+
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x7f, "IE = %s", iep->name);
+ sprintline(3, pbuf+strlen(pbuf), off+i+1, buf[i+1], 0xff, "IE Length = %d", buf[i+1]);
+
+ if(iep->func == f_null)
+ {
+ }
+ else
+ {
+ i += (iep->func)(pbuf, &buf[i], off+i);
+ goto next;
+ }
+ }
+ else
+ {
+ sprintf((pbuf+strlen(pbuf)), "UNKNOWN CODESET=%d, IE=0x%02x", codeset, buf[i]);
+ }
+
+ i++; /* index -> length */
+
+ len = buf[i];
+
+ sprintf((pbuf+strlen(pbuf)), "LEN=0x%02x, DATA=", len);
+
+ i++; /* index -> 1st param */
+
+ for(j = 0; j < len; j++)
+ {
+ sprintf((pbuf+strlen(pbuf)),"0x%02x ", buf[j+i]);
+ }
+
+ sprintf((pbuf+strlen(pbuf)),"]");
+
+ i += len;
+
+next:
+
+ if(!codelock && (codeset != oldcodeset))
+ codeset = oldcodeset;
+ }
+ }
+/* sprintf((pbuf+strlen(pbuf)),"\n"); */
+}
+
+/* EOF */
+
diff --git a/usr.sbin/i4b/isdndecode/layer3_subr.c b/usr.sbin/i4b/isdndecode/layer3_subr.c
new file mode 100644
index 0000000..e1480b6
--- /dev/null
+++ b/usr.sbin/i4b/isdndecode/layer3_subr.c
@@ -0,0 +1,1045 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * layer3_subr.c - subroutines for IE decoding
+ * -------------------------------------------
+ *
+ * $Id: layer3_subr.c,v 1.4 1998/12/18 17:09:38 hm Exp $
+ *
+ * last edit-date: [Fri Dec 18 18:12:37 1998]
+ *
+ *---------------------------------------------------------------------------*/
+
+#include "decode.h"
+
+/*---------------------------------------------------------------------------*
+ * dummy function
+ *---------------------------------------------------------------------------*/
+int
+f_null(char *pbuf, unsigned char *buf, int off)
+{
+ return(0);
+}
+
+/*---------------------------------------------------------------------------*
+ *
+ *---------------------------------------------------------------------------*/
+int
+f_cstat(char *pbuf, unsigned char *buf, int off)
+{
+ int i = 0;
+ int len = 0;
+ char buffer[256];
+
+ i++;
+ len = buf[i];
+ i++;
+ sprintf((pbuf+strlen(pbuf)), "Std=");
+ switch((buf[i] & 0x60) >> 5)
+ {
+ case 0:
+ strcpy(buffer, "CCITT");
+ break;
+ case 1:
+ strcpy(buffer, "ISO/IEC");
+ break;
+ case 2:
+ strcpy(buffer, "National");
+ break;
+ case 3:
+ strcpy(buffer, "Special");
+ break;
+ }
+ sprintf((pbuf+strlen(pbuf)), ", State=");
+
+ switch((buf[i] & 0x3f))
+ {
+ case 0:
+ strcpy(buffer, "Null");
+ break;
+ case 1:
+ strcpy(buffer, "Call initiated");
+ break;
+ case 2:
+ strcpy(buffer, "Overlap sending");
+ break;
+ case 3:
+ strcpy(buffer, "Outgoing call proceeding");
+ break;
+ case 4:
+ strcpy(buffer, "Call delivered");
+ break;
+ case 6:
+ strcpy(buffer, "Call present");
+ break;
+ case 7:
+ strcpy(buffer, "Call received");
+ break;
+ case 8:
+ strcpy(buffer, "Connect request");
+ break;
+ case 9:
+ strcpy(buffer, "Incoming call proceeding");
+ break;
+ case 10:
+ strcpy(buffer, "Active");
+ break;
+ case 11:
+ strcpy(buffer, "Disconnect request");
+ break;
+ case 12:
+ strcpy(buffer, "Disconnect indication");
+ break;
+ case 15:
+ strcpy(buffer, "Suspend request");
+ break;
+ case 17:
+ strcpy(buffer, "Resume request");
+ break;
+ case 19:
+ strcpy(buffer, "Release request");
+ break;
+ case 22:
+ strcpy(buffer, "Call abort");
+ break;
+ case 25:
+ strcpy(buffer, "Overlap receiving");
+ break;
+ case 0x3d:
+ strcpy(buffer, "Restart request");
+ break;
+ case 0x3e:
+ strcpy(buffer, "Restart");
+ break;
+ default:
+ strcpy(buffer, "ERROR: undefined/reserved");
+ break;
+ }
+ sprintf((pbuf+strlen(pbuf)), "]");
+ i++;
+ return(i);
+}
+
+/*---------------------------------------------------------------------------*
+ *
+ *---------------------------------------------------------------------------*/
+int
+f_chid(char *pbuf, unsigned char *buf, int off)
+{
+ int i = 0;
+ int len = 0;
+ char buffer[256];
+
+ i++;
+ len = buf[i];
+ i++;
+
+ extension(3, pbuf+strlen(pbuf), off+i, buf[i], 0x80);
+
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x40, "Interface Id present = %s", buf[i] & 0x40 ? "Yes" : "No");
+
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x20, "Interface Type = %s", buf[i] & 0x20 ? "Other (PRI)" : "BRI");
+
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x10, "Spare");
+
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x08, "Channel = %s", buf[i] & 0x08 ? "exclusive" : "preferred");
+
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x04, "Channel is%s the D-Channel", buf[i] & 0x04 ? "" : " not");
+
+ switch(buf[i] & 0x03)
+ {
+ case 0:
+ strcpy(buffer, "no channel");
+ break;
+ case 1:
+ strcpy(buffer, "B-1");
+ break;
+ case 2:
+ strcpy(buffer, "B-2");
+ break;
+ case 3:
+ strcpy(buffer, "any channel");
+ break;
+ }
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x03, "Channel = %s", buffer);
+
+ i++;
+ return(i);
+}
+
+/*---------------------------------------------------------------------------*
+ *
+ *---------------------------------------------------------------------------*/
+int
+f_fac(char *pbuf, unsigned char *buf, int off)
+{
+ return(q932_facility(pbuf, buf));
+}
+
+/*---------------------------------------------------------------------------*
+ *
+ *---------------------------------------------------------------------------*/
+int
+f_progi(char *pbuf, unsigned char *buf, int off)
+{
+ int i = 0;
+ int len = 0;
+ char buffer[256];
+
+ i++;
+ len = buf[i];
+ i++;
+ sprintf((pbuf+strlen(pbuf)), "Std=");
+ switch((buf[i] & 0x60) >> 5)
+ {
+ case 0:
+ strcpy(buffer, "CCITT");
+ break;
+ case 1:
+ strcpy(buffer, "ISO/IEC");
+ break;
+ case 2:
+ strcpy(buffer, "National");
+ break;
+ case 3:
+ strcpy(buffer, "Local");
+ break;
+ }
+ sprintf((pbuf+strlen(pbuf)), ", Loc=");
+
+ switch((buf[i] & 0x0f))
+ {
+ case 0:
+ strcpy(buffer, "User");
+ break;
+ case 1:
+ strcpy(buffer, "Private network serving local user");
+ break;
+ case 2:
+ strcpy(buffer, "Public network serving local user");
+ break;
+ case 3:
+ strcpy(buffer, "Transit network");
+ break;
+ case 4:
+ strcpy(buffer, "Public network serving remote user");
+ break;
+ case 5:
+ strcpy(buffer, "Private network serving remote user");
+ break;
+ case 6:
+ strcpy(buffer, "Network beyond interworking point");
+ break;
+ default:
+ strcpy(buffer, "ERROR: undefined/reserved");
+ break;
+ }
+
+ i++;
+
+ sprintf((pbuf+strlen(pbuf)), "\n Description");
+
+ switch((buf[i] & 0x7f))
+ {
+ case 1:
+ strcpy(buffer, "Call is not end-to-end ISDN");
+ break;
+ case 2:
+ strcpy(buffer, "Destination address is non-ISDN");
+ break;
+ case 3:
+ strcpy(buffer, "Origination address is non-ISDN");
+ break;
+ case 4:
+ strcpy(buffer, "Call has returned to the ISDN");
+ break;
+ case 5:
+ strcpy(buffer, "Interworking occured, Service change");
+ break;
+ case 8:
+ strcpy(buffer, "In-band info or appropriate pattern now available");
+ break;
+ default:
+ strcpy(buffer, "ERROR: undefined/reserved");
+ break;
+ }
+ sprintf((pbuf+strlen(pbuf)), "]");
+ i++;
+
+ return(i);
+}
+
+/*---------------------------------------------------------------------------*
+ *
+ *---------------------------------------------------------------------------*/
+int
+f_displ(char *pbuf, unsigned char *buf, int off)
+{
+ int i = 0;
+ int j = 0;
+ int len = 0;
+
+ i++;
+ len = buf[i];
+ i++;
+ for(j = 0; j < len; j++)
+ {
+ sprintf((pbuf+strlen(pbuf)),"%c", buf[j+i]);
+ }
+ sprintf((pbuf+strlen(pbuf)),"]");
+ i += j;
+
+ return(i);
+}
+
+/*---------------------------------------------------------------------------*
+ *
+ *---------------------------------------------------------------------------*/
+int
+f_date(char *pbuf, unsigned char *buf, int off)
+{
+ int i = 0;
+ int j = 0;
+ int len = 0;
+
+ i++;
+ len = buf[i];
+ i++;
+
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0xff, "Year = %02d", buf[i]);
+ i++;
+
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0xff, "Month = %02d", buf[i]);
+ i++;
+
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0xff, "Day = %02d", buf[i]);
+ i++;
+
+ j=3;
+ if(j < len)
+ {
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0xff, "Hour = %02d", buf[i]);
+ i++;
+ j++;
+ }
+ if(j < len)
+ {
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0xff, "Minute = %02d", buf[i]);
+ i++;
+ j++;
+ }
+ if(j < len)
+ {
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0xff, "Second = %02d", buf[i]);
+ i++;
+ j++;
+ }
+ i += len;
+ return(i);
+}
+
+/*---------------------------------------------------------------------------*
+ * decode and print the cause
+ *---------------------------------------------------------------------------*/
+int
+f_cause(char *pbuf, unsigned char *buf, int off)
+{
+ int j;
+ int len;
+ int i = 0;
+ int ls;
+ char buffer[256];
+
+ i++; /* index -> length */
+
+ len = buf[i];
+
+ i++; /* coding/location */
+ len--;
+
+ ls = buf[i];
+
+ extension(3, pbuf+strlen(pbuf), off+i, buf[i], 0x80);
+
+ switch((ls & 0x60) >> 5)
+ {
+ case 0:
+ strcpy(buffer, "CCITT");
+ break;
+ case 1:
+ strcpy(buffer, "ISO/IEC");
+ break;
+ case 2:
+ strcpy(buffer, "National");
+ break;
+ case 3:
+ strcpy(buffer, "Local");
+ break;
+ }
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x60, "Coding Standard = %s", buffer);
+
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x10, "Spare");
+
+ switch(ls & 0x0f)
+ {
+ case 0x00:
+ strcpy(buffer, "user");
+ break;
+ case 0x01:
+ strcpy(buffer, "private network serving local user");
+ break;
+ case 0x02:
+ strcpy(buffer, "public network serving local user");
+ break;
+ case 0x03:
+ strcpy(buffer, "transit network");
+ break;
+ case 0x04:
+ strcpy(buffer, "public network serving remote user");
+ break;
+ case 0x05:
+ strcpy(buffer, "private network serving remote user");
+ break;
+ case 0x07:
+ strcpy(buffer, "international network");
+ break;
+ case 0x0a:
+ strcpy(buffer, "network beyond interworking point");
+ break;
+ default:
+ sprintf(buffer, "reserved (0x%02x)", ls & 0x0f);
+ break;
+ }
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x0f, "Location = %s", buffer);
+
+ i++;
+ len--;
+
+ if(!(ls & 0x80))
+ {
+ extension(3, pbuf+strlen(pbuf), off+i, buf[i], 0x80);
+
+ switch(buf[i] & 0x7f)
+ {
+ case 0:
+ strcpy(buffer, "Q.931");
+ break;
+ case 3:
+ strcpy(buffer, "X.21");
+ break;
+ case 4:
+ strcpy(buffer, "X.25");
+ break;
+ case 5:
+ strcpy(buffer, "Q.1031/Q.1051");
+ break;
+ default:
+ strcpy(buffer, "Reserved");
+ break;
+ }
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x7f, "Recommendation = %s", buffer);
+ i++;
+ len--;
+ }
+
+ extension(3, pbuf+strlen(pbuf), off+i, buf[i], 0x80);
+
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x7f, "Cause = %s", print_cause_q850(buf[i] & 0x7f));
+
+ i++;
+ len--;
+
+ for(j = 0; j < len; j++)
+ sprintline(3, (pbuf+strlen(pbuf)), off+i+j, buf[i+j], 0xff, "Diagnostics = %02d %s", buf[i+j]);
+
+ i += (len+1);
+
+ return(i);
+}
+
+/*---------------------------------------------------------------------------*
+ * decode and print the bearer capability
+ *---------------------------------------------------------------------------*/
+int
+f_bc(char *pbuf, unsigned char *buf, int off)
+{
+ int len;
+ int i = 0;
+ int mr = 0;
+ char buffer[256];
+
+ i++; /* index -> length */
+
+ len = buf[i];
+ i++;
+
+ extension(3, pbuf+strlen(pbuf), off+i, buf[i], 0x80);
+
+ switch((buf[i] & 0x60) >> 5)
+ {
+ case 0:
+ strcpy(buffer, "CCITT");
+ break;
+ case 1:
+ strcpy(buffer, "ISO/IEC");
+ break;
+ case 2:
+ strcpy(buffer, "National");
+ break;
+ case 3:
+ strcpy(buffer, "NSI Std");
+ break;
+ }
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x60, "Coding standard = %s", buffer);
+
+ switch(buf[i] & 0x1f)
+ {
+ case 0x00:
+ strcpy(buffer, "speech");
+ break;
+ case 0x08:
+ strcpy(buffer, "unrestricted digital information");
+ break;
+ case 0x09:
+ strcpy(buffer, "restricted digital information");
+ break;
+ case 0x10:
+ strcpy(buffer, "3.1 kHz audio");
+ break;
+ case 0x11:
+ strcpy(buffer, "unrestricted digital information with tones");
+ break;
+ case 0x18:
+ strcpy(buffer, "video");
+ break;
+ default:
+ sprintf(buffer, "reserved (0x%02x)", buf[i] & 0x0f);
+ break;
+ }
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x1f, "Capability = %s", buffer);
+
+ i++;
+ len--;
+
+ extension(3, pbuf+strlen(pbuf), off+i, buf[i], 0x80);
+
+ switch((buf[i] & 0x60) >> 5)
+ {
+ case 0:
+ strcpy(buffer, "circuit");
+ break;
+ case 2:
+ strcpy(buffer, "packet");
+ break;
+ default:
+ sprintf((pbuf+strlen(pbuf)), "reserved (0x%02x)", ((buf[i] & 0x60) >> 5));
+ break;
+ }
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x60, "Mode = %s", buffer);
+
+ switch(buf[i] & 0x1f)
+ {
+ case 0x00:
+ strcpy(buffer, "packet mode");
+ break;
+ case 0x10:
+ strcpy(buffer, "64 kbit/s");
+ break;
+ case 0x11:
+ strcpy(buffer, "2 x 64 kbit/s");
+ break;
+ case 0x13:
+ strcpy(buffer, "384 kbit/s");
+ break;
+ case 0x15:
+ strcpy(buffer, "1536 kbit/s");
+ break;
+ case 0x17:
+ strcpy(buffer, "1920 kbit/s");
+ break;
+ case 0x18:
+ strcpy(buffer, "Multirate");
+ mr = 1;
+ break;
+ default:
+ sprintf((pbuf+strlen(pbuf)), "reserved (0x%02x)", buf[i] & 0x0f);
+ break;
+ }
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x1f, "Rate = %s", buffer);
+
+ i++;
+ len--;
+
+ if(!len)
+ goto exit;
+
+ if(mr)
+ {
+ extension(3, pbuf+strlen(pbuf), off+i, buf[i], 0x80);
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x60, "Rate multiplier = %d", buf[i] & 0x7f);
+ i++;
+ len--;
+ }
+
+ if(!len)
+ goto exit;
+
+ sprintf((pbuf+strlen(pbuf)), "\n layer1=");
+
+ switch(buf[i] & 0x1f)
+ {
+ case 0x01:
+ sprintf((pbuf+strlen(pbuf)), "V.110");
+ break;
+ case 0x02:
+ sprintf((pbuf+strlen(pbuf)), "G.711 u-law");
+ break;
+ case 0x03:
+ sprintf((pbuf+strlen(pbuf)), "G.711 A-law");
+ break;
+ case 0x04:
+ sprintf((pbuf+strlen(pbuf)), "G.721");
+ break;
+ case 0x05:
+ sprintf((pbuf+strlen(pbuf)), "H.221/H.242");
+ break;
+ case 0x07:
+ sprintf((pbuf+strlen(pbuf)), "Non-Std");
+ break;
+ case 0x08:
+ sprintf((pbuf+strlen(pbuf)), "V.120");
+ break;
+ case 0x09:
+ sprintf((pbuf+strlen(pbuf)), "X.31");
+ break;
+ default:
+ sprintf((pbuf+strlen(pbuf)), "reserved (0x%02x)", buf[i] & 0x0f);
+ break;
+ }
+ i++;
+ len--;
+
+ if(!len)
+ goto exit;
+
+ if(!(buf[i-1] & 0x80))
+ {
+ sprintf((pbuf+strlen(pbuf)), "\n user rate=0x%02x ", buf[i] & 0x1f);
+
+ if(buf[i] & 0x40)
+ sprintf((pbuf+strlen(pbuf)), "(async,");
+ else
+ sprintf((pbuf+strlen(pbuf)), "(sync,");
+
+ if(buf[i] & 0x20)
+ sprintf((pbuf+strlen(pbuf)), "in-band neg. possible)");
+ else
+ sprintf((pbuf+strlen(pbuf)), "in-band neg not possible)");
+
+ i++;
+ len--;
+ }
+
+ if(!len)
+ goto exit;
+
+ if(!(buf[i-1] & 0x80))
+ {
+ sprintf((pbuf+strlen(pbuf)), "\n clk/flow=0x%02x", buf[i] & 0x1f);
+
+ sprintf((pbuf+strlen(pbuf)), "\n intermediate rate=");
+
+ switch((buf[i] & 0x60) >> 5)
+ {
+ case 0:
+ sprintf((pbuf+strlen(pbuf)), "not used");
+ break;
+ case 1:
+ sprintf((pbuf+strlen(pbuf)), "8 kbit/s");
+ break;
+ case 2:
+ sprintf((pbuf+strlen(pbuf)), "16 kbit/s");
+ break;
+ case 3:
+ sprintf((pbuf+strlen(pbuf)), "32 kbit/s");
+ break;
+ }
+ i++;
+ len--;
+ }
+
+ if(!len)
+ goto exit;
+
+ if(!(buf[i-1] & 0x80))
+ {
+ sprintf((pbuf+strlen(pbuf)), "\n hdr/mfrm/etc.=0x%02x", buf[i]);
+ i++;
+ len--;
+ }
+
+ if(!len)
+ goto exit;
+
+ if(!(buf[i-1] & 0x80))
+ {
+ sprintf((pbuf+strlen(pbuf)), "\n stop/data/parity=0x%02x", buf[i]);
+ i++;
+ len--;
+ }
+
+ if(!len)
+ goto exit;
+
+ if(!(buf[i-1] & 0x80))
+ {
+ sprintf((pbuf+strlen(pbuf)), "\n modemtype=0x%02x", buf[i]);
+ i++;
+ len--;
+ }
+
+ if(!len)
+ goto exit;
+
+ switch(buf[i] & 0x7f)
+ {
+ case 0x42:
+ sprintf((pbuf+strlen(pbuf)), "\n layer2=Q.921/I.441");
+ break;
+ case 0x46:
+ sprintf((pbuf+strlen(pbuf)), "\n layer2=X.25 link");
+ break;
+ default:
+ sprintf((pbuf+strlen(pbuf)), "\n layer2=0x%02x",(buf[i] & 0x7f));
+ break;
+ }
+ i++;
+ len--;
+
+ if(!len)
+ goto exit;
+
+ switch(buf[i] & 0x7f)
+ {
+ case 0x62:
+ sprintf((pbuf+strlen(pbuf)), "\n layer3=Q.921/I.441");
+ break;
+ case 0x66:
+ sprintf((pbuf+strlen(pbuf)), "\n layer3=X.25 packet");
+ break;
+ default:
+ sprintf((pbuf+strlen(pbuf)), "\n layer3=0x%02x",(buf[i] & 0x7f));
+ break;
+ }
+ i++;
+ len--;
+
+exit:
+
+ return(i);
+}
+
+/*---------------------------------------------------------------------------*
+ * decode and print the ISDN (telephone) number
+ *---------------------------------------------------------------------------*/
+int
+f_cnu(char *pbuf, unsigned char *buf, int off)
+{
+ int j;
+ int len;
+ int i = 0;
+ int tp;
+ int ind = 0;
+ char buffer[256];
+
+ i++; /* index -> length */
+ len = buf[i];
+
+ i++; /* index -> type/plan */
+ tp = buf[i];
+
+ extension(3, pbuf+strlen(pbuf), off+i, buf[i], 0x80);
+
+ switch((tp & 0x70) >> 4)
+ {
+ case 0:
+ strcpy(buffer, "Unknown");
+ break;
+ case 1:
+ strcpy(buffer, "International number");
+ break;
+ case 2:
+ strcpy(buffer, "National number");
+ break;
+ case 3:
+ strcpy(buffer, "Network specific number");
+ break;
+ case 4:
+ strcpy(buffer, "Subscriber number");
+ break;
+ case 6:
+ strcpy(buffer, "Abbreviated number");
+ break;
+ default:
+ sprintf(buffer, "Reserved (%d), ", ((tp & 0x70) >> 4));
+ break;
+ }
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x60, "Type = %s", buffer);
+
+ switch(tp & 0x0f)
+ {
+ case 0:
+ strcpy(buffer, "Unknown");
+ break;
+ case 1:
+ strcpy(buffer, "ISDN (E.164)");
+ break;
+ case 3:
+ strcpy(buffer, "Data (X.121)");
+ break;
+ case 4:
+ strcpy(buffer, "Telex (F.69)");
+ break;
+ case 8:
+ strcpy(buffer, "National");
+ break;
+ case 9:
+ strcpy(buffer, "Private");
+ break;
+ default:
+ sprintf(buffer, "Reserved (%d)", (tp & 0x0f));
+ break;
+ }
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x0f, "Plan = %s", buffer);
+
+ i++;
+ len--;
+
+ if(!(tp & 0x80))
+ {
+ extension(3, pbuf+strlen(pbuf), off+i, buf[i], 0x80);
+
+ switch((buf[i] & 0x60) >> 5)
+ {
+ case 0:
+ strcpy(buffer, "allowed");
+ break;
+ case 1:
+ strcpy(buffer, "restricted");
+ break;
+ case 2:
+ strcpy(buffer, "number not available");
+ break;
+ case 3:
+ strcpy(buffer, "reserved");
+ break;
+ }
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x60, "Presentation = %s", buffer);
+
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x1c, "Spare");
+
+ switch(ind & 0x03)
+ {
+ case 0:
+ strcpy(buffer, "user provided, not screened");
+ break;
+ case 1:
+ strcpy(buffer, "user provided, verified & passed");
+ break;
+ case 2:
+ strcpy(buffer, "user provided, verified & failed");
+ break;
+ case 3:
+ strcpy(buffer, "network provided");
+ break;
+ }
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x03, "Screening = %s", buffer);
+ i++;
+ len--;
+ }
+
+ for(j = 0; j < len; j++)
+ {
+ sprintline(3, (pbuf+strlen(pbuf)), off+i+j, buf[i+j], 0xff, "Number digit = %c", buf[i+j]);
+ }
+
+ i += j;
+
+ return(i);
+}
+
+/*---------------------------------------------------------------------------*
+ * decode and print HL comatibility
+ *---------------------------------------------------------------------------*/
+int
+f_hlc(char *pbuf, unsigned char *buf, int off)
+{
+ int i = 0;
+ int len = 0;
+ char buffer[256];
+
+ i++;
+ len = buf[i];
+
+ i++;
+ extension(3, pbuf+strlen(pbuf), off+i, buf[i], 0x80);
+
+ switch((buf[i] >> 5) & 0x03)
+ {
+ case 0: strcpy(buffer, "CCITT");
+ break;
+ case 1: strcpy(buffer, "ISO/IEC");
+ break;
+ case 2: strcpy(buffer, "National");
+ break;
+ case 3: strcpy(buffer, "Network");
+ }
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x60, "Coding standard = %s", buffer);
+
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x1c, "Interpretation = %s", ((buf[i] >> 2) & 0x07) == 0x04 ? "first" : "reserved");
+
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x03, "Presentation = %s", ((buf[i]) & 0x03) == 0x01 ? "High layer protocol profile" : "reserved");
+
+ i++;
+ len--;
+
+ extension(3, pbuf+strlen(pbuf), off+i, buf[i], 0x80);
+
+ switch(buf[i] & 0x7f)
+ {
+ case 0x01:
+ strcpy(buffer, "Telephony");
+ break;
+ case 0x04:
+ strcpy(buffer, "Fax Group 2/3 (F.182)");
+ break;
+ case 0x21:
+ strcpy(buffer, "Fax Group 4 I (F.184)");
+ break;
+ case 0x24:
+ strcpy(buffer, "Teletex (F.230) or Fax Group 4 II/III (F.184)");
+ break;
+ case 0x28:
+ strcpy(buffer, "Teletex (F.220)");
+ break;
+ case 0x31:
+ strcpy(buffer, "Teletex (F.200)");
+ break;
+ case 0x32:
+ strcpy(buffer, "Videotex (F.300/T.102)");
+ break;
+ case 0x33:
+ strcpy(buffer, "Videotex (F.300/T.101)");
+ break;
+ case 0x35:
+ strcpy(buffer, "Telex (F.60)");
+ break;
+ case 0x38:
+ strcpy(buffer, "MHS (X.400)");
+ break;
+ case 0x41:
+ strcpy(buffer, "OSI (X.200)");
+ break;
+ case 0x5e:
+ strcpy(buffer, "Maintenance");
+ break;
+ case 0x5f:
+ strcpy(buffer, "Management");
+ break;
+ case 0x60:
+ strcpy(buffer, "Audio visual (F.721)");
+ break;
+ default:
+ sprintf(buffer, "Reserved (0x%02x)", buf[i] & 0x7f);
+ break;
+ }
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x7f, "Characteristics = %s", buffer);
+ i++;
+ len--;
+
+ if(buf[i-1] & 0x80)
+ {
+ return(i);
+ }
+
+ extension(3, pbuf+strlen(pbuf), off+i, buf[i], 0x80);
+
+ switch(buf[i] & 0x7f)
+ {
+ case 0x01:
+ strcpy(buffer, "Telephony");
+ break;
+ case 0x04:
+ strcpy(buffer, "Fax Group 2/3 (F.182)");
+ break;
+ case 0x21:
+ strcpy(buffer, "Fax Group 4 I (F.184)");
+ break;
+ case 0x24:
+ strcpy(buffer, "Teletex (F.230) or Fax Group 4 II/III (F.184)");
+ break;
+ case 0x28:
+ strcpy(buffer, "Teletex (F.220)");
+ break;
+ case 0x31:
+ strcpy(buffer, "Teletex (F.200)");
+ break;
+ case 0x32:
+ strcpy(buffer, "Videotex (F.300/T.102)");
+ break;
+ case 0x33:
+ strcpy(buffer, "Videotex (F.300/T.101)");
+ break;
+ case 0x35:
+ strcpy(buffer, "Telex (F.60)");
+ break;
+ case 0x38:
+ strcpy(buffer, "MHS (X.400)");
+ break;
+ case 0x41:
+ strcpy(buffer, "OSI (X.200)");
+ break;
+ case 0x5e:
+ strcpy(buffer, "Maintenance");
+ break;
+ case 0x5f:
+ strcpy(buffer, "Management");
+ break;
+ case 0x60:
+ strcpy(buffer, "Audio visual (F.721)");
+ break;
+ default:
+ sprintf(buffer, "Reserved (0x%02x)", buf[i] & 0x7f);
+ break;
+
+ }
+ sprintline(3, (pbuf+strlen(pbuf)), off+i, buf[i], 0x7f, "Ext. characteristics = %s", buffer);
+ i++;
+ return(i);
+}
+
+/* EOF */
+
diff --git a/usr.sbin/i4b/isdndecode/main.c b/usr.sbin/i4b/isdndecode/main.c
new file mode 100644
index 0000000..a73d708
--- /dev/null
+++ b/usr.sbin/i4b/isdndecode/main.c
@@ -0,0 +1,774 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * main.c - isdndecode main program file
+ * -------------------------------------
+ *
+ * $Id: main.c,v 1.6 1998/12/18 17:09:38 hm Exp $
+ *
+ * last edit-date: [Fri Dec 18 18:12:52 1998]
+ *
+ *---------------------------------------------------------------------------*/
+
+#include "decode.h"
+
+unsigned char buf[BSIZE];
+FILE *Fout = NULL;
+FILE *BP = NULL;
+int outflag = 1;
+int header = 1;
+int print_q921 = 1;
+int unit = 0;
+int dchan = 0;
+int bchan = 0;
+int traceon = 0;
+int analyze = 0;
+int Rx = RxUDEF;
+int Tx = TxUDEF;
+int f;
+int Bopt = 0;
+int Popt = 0;
+int bpopt = 0;
+int info = 0;
+
+static char outfilename[1024];
+static char BPfilename[1024];
+
+static void dumpbuf( int n, unsigned char *buf, i4b_trace_hdr_t *hdr);
+static int switch_driver( int value, int rx, int tx );
+static void usage( void );
+static void exit_hdl( void );
+static void reopenfiles( int );
+
+/*---------------------------------------------------------------------------*
+ * main
+ *---------------------------------------------------------------------------*/
+int
+main(int argc, char *argv[])
+{
+ extern int optind;
+ extern int opterr;
+ extern char *optarg;
+ char devicename[80];
+ char headerbuf[256];
+
+ int n;
+ int c;
+ char *b;
+
+ int enable_trace = TRACE_D_RX | TRACE_D_TX;
+ char *outfile = DECODE_FILE_NAME;
+ char *binfile = BIN_FILE_NAME;
+ int outfileset = 0;
+ time_t tm;
+
+ i4b_trace_hdr_t *ithp = NULL;
+ int l;
+
+ b = &buf[sizeof(i4b_trace_hdr_t)];
+
+ while( (c = getopt(argc, argv, "abdf:hiln:op:u:BPR:T:?")) != EOF)
+ {
+ switch(c)
+ {
+ case 'a':
+ analyze = 1;
+ break;
+
+ case 'b':
+ enable_trace |= (TRACE_B_RX | TRACE_B_TX);
+ break;
+
+ case 'd':
+ enable_trace &= (~(TRACE_D_TX | TRACE_D_RX));
+ break;
+
+ case 'o':
+ outflag = 0;
+ break;
+
+ case 'f':
+ outfile = optarg;
+ outfileset = 1;
+ break;
+
+ case 'h':
+ header = 0;
+ break;
+
+ case 'i':
+ enable_trace |= TRACE_I;
+ info = 1;
+ break;
+
+ case 'l':
+ print_q921 = 0;
+ break;
+
+ case 'p':
+ binfile = optarg;
+ bpopt = 1;
+ break;
+
+ case 'u':
+ unit = atoi(optarg);
+ if(unit < 0 || unit >= MAX_CONTROLLERS)
+ usage();
+ break;
+
+ case 'B':
+ Bopt = 1;
+ break;
+
+ case 'P':
+ Popt = 1;
+ break;
+
+ case 'R':
+ Rx = atoi(optarg);
+ if(Rx < 0 || Rx >= MAX_CONTROLLERS)
+ usage();
+ break;
+
+ case 'T':
+ Tx = atoi(optarg);
+ if(Tx < 0 || Tx >= MAX_CONTROLLERS)
+ usage();
+ break;
+
+ case '?':
+ default:
+ usage();
+ break;
+ }
+ }
+
+ if(enable_trace == 0)
+ usage();
+
+ if(Bopt && Popt)
+ usage();
+
+ atexit(exit_hdl);
+
+ if(Bopt)
+ {
+ if(bpopt)
+ sprintf(BPfilename, "%s", binfile);
+ else
+ sprintf(BPfilename, "%s%d", BIN_FILE_NAME, unit);
+
+ if((BP = fopen(BPfilename, "r")) != NULL)
+ {
+ char buffer[1024];
+ fclose(BP);
+ sprintf(buffer, "%s%s", BPfilename, DECODE_FILE_NAME_BAK);
+ rename(BPfilename, buffer);
+ }
+ if((BP = fopen(BPfilename, "w")) == NULL)
+ {
+ char buffer[80];
+
+ sprintf(buffer, "Error opening file [%s]", BPfilename);
+ perror(buffer);
+ exit(1);
+ }
+
+ if((setvbuf(BP, (char *)NULL, _IONBF, 0)) != 0)
+ {
+ char buffer[80];
+
+ sprintf(buffer, "Error setting file [%s] to unbuffered", BPfilename);
+ perror(buffer);
+ exit(1);
+ }
+ }
+
+ if(Popt)
+ {
+ if(bpopt)
+ sprintf(BPfilename, "%s", binfile);
+ else
+ sprintf(BPfilename, "%s%d", BIN_FILE_NAME, unit);
+
+ if((BP = fopen(BPfilename, "r")) == NULL)
+ {
+ char buffer[80];
+
+ sprintf(buffer, "Error opening file [%s]", BPfilename);
+ perror(buffer);
+ exit(1);
+ }
+ }
+ else
+ {
+ sprintf(devicename, "%s%d", I4BTRC_DEVICE, unit);
+
+ if((f = open(devicename, O_RDWR)) < 0)
+ {
+ char buffer[80];
+
+ sprintf(buffer, "Error opening trace device [%s]", devicename);
+ perror(buffer);
+ exit(1);
+ }
+ }
+
+ if(outflag)
+ {
+ if(outfileset == 0)
+ sprintf(outfilename, "%s%d", DECODE_FILE_NAME, unit);
+ else
+ strcpy(outfilename, outfile);
+
+
+ if((Fout = fopen(outfilename, "r")) != NULL)
+ {
+ char buffer[1024];
+ fclose(Fout);
+ sprintf(buffer, "%s%s", outfilename, DECODE_FILE_NAME_BAK);
+ rename(outfilename, buffer);
+ }
+
+ if((Fout = fopen(outfilename, "w")) == NULL)
+ {
+ char buffer[80];
+
+ sprintf(buffer, "Error opening file [%s]", outfilename);
+ perror(buffer);
+ exit(1);
+ }
+
+ if((setvbuf(Fout, (char *)NULL, _IONBF, 0)) != 0)
+ {
+ char buffer[80];
+
+ sprintf(buffer, "Error setting file [%s] to unbuffered", outfile);
+ perror(buffer);
+ exit(1);
+ }
+ }
+
+ if((setvbuf(stdout, (char *)NULL, _IOLBF, 0)) != 0)
+ {
+ char buffer[80];
+
+ sprintf(buffer, "Error setting stdout to line-buffered");
+ perror(buffer);
+ exit(1);
+ }
+
+ if(!Popt)
+ {
+ if((switch_driver(enable_trace, Rx, Tx)) == -1)
+ exit(1);
+ else
+ traceon = 1;
+ }
+
+ signal(SIGHUP, SIG_IGN); /* ignore hangup signal */
+ signal(SIGUSR1, reopenfiles); /* rotate logfile(s) */
+
+ time(&tm);
+
+ if(analyze)
+ {
+ sprintf(headerbuf, "\n==== isdnanalyze controller rx #%d - tx #%d ==== started %s",
+ Rx, Tx, ctime(&tm));
+ }
+ else
+ {
+ sprintf(headerbuf, "\n=========== isdntrace controller #%d =========== started %s",
+ unit, ctime(&tm));
+ }
+
+ printf("%s", headerbuf);
+
+ if(outflag)
+ fprintf(Fout, "%s", headerbuf);
+
+ for (;;)
+ {
+ if(Popt == 0)
+ {
+ n = read(f, buf, BSIZE);
+
+ if(Bopt)
+ {
+ if((fwrite(buf, 1, n, BP)) != n)
+ {
+ char buffer[80];
+ sprintf(buffer, "Error writing file [%s]", BPfilename);
+ perror(buffer);
+ exit(1);
+ }
+ }
+
+ n -= sizeof(i4b_trace_hdr_t);
+ }
+ else
+ {
+ if((fread(buf, 1, sizeof(i4b_trace_hdr_t), BP)) != sizeof(i4b_trace_hdr_t))
+ {
+ if(feof(BP))
+ {
+ printf("\nEnd of playback input file reached.\n");
+ exit(0);
+ }
+ else
+ {
+ char buffer[80];
+ sprintf(buffer, "Error reading hdr from file [%s]", BPfilename);
+ perror(buffer);
+ exit(1);
+ }
+ }
+
+ ithp = (i4b_trace_hdr_t *)buf;
+ l = ithp->length - sizeof(i4b_trace_hdr_t);
+
+ if((n = fread(buf+sizeof(i4b_trace_hdr_t), 1, l , BP)) != l)
+ {
+ char buffer[80];
+ sprintf(buffer, "Error reading data from file [%s]", BPfilename);
+ perror(buffer);
+ exit(1);
+ }
+
+ }
+
+ if(n > 0)
+ {
+ dumpbuf(n, b, (i4b_trace_hdr_t *)buf);
+ }
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * format header into static buffer, return buffer address
+ *---------------------------------------------------------------------------*/
+char *
+fmt_hdr(i4b_trace_hdr_t *hdr, int frm_len)
+{
+ struct tm *s;
+ static char hbuf[256];
+ int i = 0;
+
+ s = localtime(&(hdr->time.tv_sec));
+
+ if(hdr->type == TRC_CH_I) /* Layer 1 INFO's */
+ {
+ sprintf(hbuf,"\n-- %s - unit:%d ---------------- time:%2.2d.%2.2d %2.2d:%2.2d:%2.2d.%06u ",
+ ((hdr->dir) ? "NT->TE" : "TE->NT"),
+ hdr->unit,
+ s->tm_mday,
+ s->tm_mon + 1,
+ s->tm_hour,
+ s->tm_min,
+ s->tm_sec,
+ (u_int32_t)hdr->time.tv_usec);
+ }
+ else
+ {
+ if(hdr->trunc > 0)
+ {
+ sprintf(hbuf,"\n-- %s - unit:%d - frame:%6.6u - time:%2.2d.%2.2d %2.2d:%2.2d:%2.2d.%06u - length:%d (%d) ",
+ ((hdr->dir) ? "NT->TE" : "TE->NT"),
+ hdr->unit,
+ hdr->count,
+ s->tm_mday,
+ s->tm_mon + 1,
+ s->tm_hour,
+ s->tm_min,
+ s->tm_sec,
+ (u_int32_t)hdr->time.tv_usec,
+ frm_len,
+ hdr->trunc);
+ }
+ else
+ {
+ sprintf(hbuf,"\n-- %s - unit:%d - frame:%6.6u - time:%2.2d.%2.2d %2.2d:%2.2d:%2.2d.%06u - length:%d ",
+ ((hdr->dir) ? "NT->TE" : "TE->NT"),
+ hdr->unit,
+ hdr->count,
+ s->tm_mday,
+ s->tm_mon + 1,
+ s->tm_hour,
+ s->tm_min,
+ s->tm_sec,
+ (u_int32_t)hdr->time.tv_usec,
+ frm_len);
+ }
+ }
+
+ for(i=strlen(hbuf); i <= NCOLS;)
+ hbuf[i++] = '-';
+
+ hbuf[i++] = '\n';
+ hbuf[i] = '\0';
+
+ return(hbuf);
+}
+
+/*---------------------------------------------------------------------------*
+ * decode protocol and output to file(s)
+ *---------------------------------------------------------------------------*/
+static void
+dumpbuf(int n, unsigned char *buf, i4b_trace_hdr_t *hdr)
+{
+ static char l1buf[128];
+ static unsigned char l2buf[32000];
+ static unsigned char l3buf[32000];
+ int cnt;
+ int nsave = n;
+ char *pbuf;
+ int i, j;
+
+ l1buf[0] = '\0';
+ l2buf[0] = '\0';
+ l3buf[0] = '\0';
+
+ switch(hdr->type)
+ {
+ case TRC_CH_I: /* Layer 1 INFO's */
+ layer1(l1buf, buf);
+ break;
+
+ case TRC_CH_D: /* D-channel data */
+ cnt = layer2(l2buf, buf, hdr->dir, print_q921);
+
+ n -= cnt;
+ buf += cnt;
+
+ if(n)
+ layer3(l3buf, n, cnt, buf);
+ break;
+
+ default: /* B-channel data */
+
+ pbuf = &l2buf[0];
+
+ for (i = 0; i < n; i += 16)
+ {
+ sprintf((pbuf+strlen(pbuf)),"B%d:%.3x ", hdr->type, i);
+
+ for (j = 0; j < 16; j++)
+ if (i + j < n)
+ sprintf((pbuf+strlen(pbuf)),"%02x ", buf[i + j]);
+ else
+ sprintf((pbuf+strlen(pbuf))," ");
+
+ sprintf((pbuf+strlen(pbuf))," ");
+
+ for (j = 0; j < 16 && i + j < n; j++)
+ if (isprint(buf[i + j]))
+ sprintf((pbuf+strlen(pbuf)),"%c", buf[i + j]);
+ else
+ sprintf((pbuf+strlen(pbuf)),".");
+
+ sprintf((pbuf+strlen(pbuf)),"\n");
+ }
+ break;
+ }
+
+ if(header && ((l1buf[0] != '\0' || l2buf[0] != '\0') || (l3buf[0] != 0)))
+ {
+ char *p;
+ p = fmt_hdr(hdr, nsave);
+ printf("%s", p);
+ if(outflag)
+ fprintf(Fout, "%s", p);
+ }
+
+ if(l1buf[0] != '\0')
+ {
+ printf("%s", l1buf);
+ if(outflag)
+ fprintf(Fout, "%s", l1buf);
+ }
+
+ if(l2buf[0] != '\0')
+ {
+ printf("%s", l2buf);
+ if(outflag)
+ fprintf(Fout, "%s", l2buf);
+ }
+
+ if(l3buf[0] != '\0')
+ {
+ printf("%s", l3buf);
+ if(outflag)
+ fprintf(Fout, "%s", l3buf);
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * exit handler function to be called at program exit
+ *---------------------------------------------------------------------------*/
+void
+exit_hdl()
+{
+ if(traceon)
+ switch_driver(TRACE_OFF, Rx, Tx);
+}
+
+/*---------------------------------------------------------------------------*
+ * switch driver debugging output on/off
+ *---------------------------------------------------------------------------*/
+static int
+switch_driver(int value, int rx, int tx)
+{
+ char buffer[80];
+ int v = value;
+
+ if(analyze == 0)
+ {
+ if(ioctl(f, I4B_TRC_SET, &v) < 0)
+ {
+ sprintf(buffer, "Error ioctl I4B_TRC_SET, val = %d", v);
+ perror(buffer);
+ return(-1);
+ }
+ }
+ else
+ {
+ if(value == TRACE_OFF)
+ {
+ if(ioctl(f, I4B_TRC_RESETA, &v) < 0)
+ {
+ sprintf(buffer, "Error ioctl I4B_TRC_RESETA - ");
+ perror(buffer);
+ return(-1);
+ }
+ }
+ else
+ {
+ i4b_trace_setupa_t tsa;
+
+ tsa.rxunit = rx;
+ tsa.rxflags = value;
+ tsa.txunit = tx;
+ tsa.txflags = value;
+
+ if(ioctl(f, I4B_TRC_SETA, &tsa) < 0)
+ {
+ sprintf(buffer, "Error ioctl I4B_TRC_SETA, val = %d", v);
+ perror(buffer);
+ return(-1);
+ }
+ }
+ }
+ return(0);
+}
+
+/*---------------------------------------------------------------------------*
+ * reopen files to support rotating logfile(s) on SIGUSR1
+ *
+ * based on an idea from Ripley (ripley@nostromo.in-berlin.de)
+ *
+ * close file and reopen it for append. this will be a nop
+ * if the previously opened file hasn't moved but will open
+ * a new one otherwise, thus enabling a rotation...
+ *
+ *---------------------------------------------------------------------------*/
+static void
+reopenfiles(int dummy)
+{
+ if(outflag)
+ {
+ fclose(Fout);
+
+ if((Fout = fopen(outfilename, "a")) == NULL)
+ {
+ char buffer[80];
+
+ sprintf(buffer, "Error re-opening file [%s]", outfilename);
+ perror(buffer);
+ exit(1);
+ }
+
+ if((setvbuf(Fout, (char *)NULL, _IONBF, 0)) != 0)
+ {
+ char buffer[80];
+
+ sprintf(buffer, "Error re-setting file [%s] to unbuffered", outfilename);
+ perror(buffer);
+ exit(1);
+ }
+ }
+
+ if(Bopt)
+ {
+
+ fclose(BP);
+
+ if((BP = fopen(BPfilename, "a")) == NULL)
+ {
+ char buffer[80];
+
+ sprintf(buffer, "Error re-opening file [%s]", BPfilename);
+ perror(buffer);
+ exit(1);
+ }
+
+ if((setvbuf(BP, (char *)NULL, _IONBF, 0)) != 0)
+ {
+ char buffer[80];
+
+ sprintf(buffer, "Error re-setting file [%s] to unbuffered", BPfilename);
+ perror(buffer);
+ exit(1);
+ }
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * decode extension bit
+ *---------------------------------------------------------------------------*/
+void
+extension(int layer, char *buffer, int cnt, unsigned char value, unsigned char mask)
+{
+ sprintline(layer, buffer, cnt, value, mask, "Extension Bit = %c (%s)",
+ (value & mask) ? '1' : '0',
+ (value & mask) ? "no extension, final octet" : "with extension, octet follows");
+}
+
+/*---------------------------------------------------------------------------*
+ * print bits as 0/1 available for mask
+ *---------------------------------------------------------------------------*/
+static char *
+print_bits(unsigned char val, unsigned char mask)
+{
+ static char buffer[10];
+ int i = 0;
+ int length = 8;
+
+ while(length--)
+ {
+ if(mask & 0x80)
+ {
+ if(val & 0x80)
+ buffer[i++] = '1';
+ else
+ buffer[i++] = '0';
+ }
+ else
+ {
+ buffer[i++] = '-';
+ }
+ val = val << 1;
+ mask = mask << 1;
+ }
+ buffer[i] = '\0';
+ return(buffer);
+}
+
+/*---------------------------------------------------------------------------*
+ * print one decoded output line
+ *---------------------------------------------------------------------------*/
+void
+sprintline(int layer, char *buffer, int oct_count, int oct_val,
+ int oct_mask, const char *fmt, ...)
+{
+ char lbuffer[256];
+ static int lastcount = -1;
+ char *ptr;
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ if(oct_count != lastcount)
+ {
+ lastcount = oct_count;
+
+ sprintf(lbuffer, "L%d %2d %02X %s ",
+ layer,
+ oct_count,
+ oct_val,
+ print_bits(oct_val, oct_mask));
+ }
+ else
+ {
+ sprintf(lbuffer, " %s ",
+ print_bits(oct_val, oct_mask));
+ }
+
+ vsprintf(lbuffer+strlen(lbuffer), fmt, ap);
+
+ va_end(ap);
+
+ sprintf(lbuffer+strlen(lbuffer), "\n");
+
+ if((ptr = rindex(lbuffer, '(')) != NULL)
+ {
+ char *s = lbuffer;
+ char *b = buffer;
+ int len = strlen(lbuffer);
+ int i;
+
+ for(s = lbuffer; s < ptr; *b++ = *s++)
+ ;
+ for(i = 0;(i+len) <= NCOLS; *b++ = ' ', i++)
+ ;
+ for(; *s; *b++ = *s++)
+ ;
+ *b = '\0';
+ }
+ else
+ {
+ strcpy(buffer, lbuffer);
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * usage intructions
+ *---------------------------------------------------------------------------*/
+void
+usage(void)
+{
+ fprintf(stderr,"\n");
+ fprintf(stderr,"isdndecode - isdn4bsd package ISDN decoder for passive cards (%02d.%02d)\n", VERSION, REL);
+ fprintf(stderr,"usage: isdntrace -a -b -d -f <file> -h -i -l -n <val> -o -p <file> -r -u <unit>\n");
+ fprintf(stderr," -B -P -R <unit> -T <unit>\n");
+ fprintf(stderr," -a analyzer mode ................................... (default off)\n");
+ fprintf(stderr," -b switch B channel trace on ....................... (default off)\n");
+ fprintf(stderr," -d switch D channel trace off ....................... (default on)\n");
+ fprintf(stderr," -f <file> write output to file filename ............ (default %s0)\n", DECODE_FILE_NAME);
+ fprintf(stderr," -h don't print header for each message ............. (default off)\n");
+ fprintf(stderr," -i print I.430 (layer 1) INFO signals .............. (default off)\n");
+ fprintf(stderr," -l don't decode low layer Q.921 messages ........... (default off)\n");
+ fprintf(stderr," -o don't write output to a file .................... (default off)\n");
+ fprintf(stderr," -p <file> specify filename for -B and -P ........ (default %s0)\n", BIN_FILE_NAME);
+ fprintf(stderr," -u <unit> specify controller unit number ............... (default unit 0)\n");
+ fprintf(stderr," -B write binary trace data to file filename ........ (default off)\n");
+ fprintf(stderr," -P playback from binary trace data file ............ (default off)\n");
+ fprintf(stderr," -R <unit> analyze Rx controller unit number (for -a) ... (default unit %d)\n", RxUDEF);
+ fprintf(stderr," -T <unit> analyze Tx controller unit number (for -a) ... (default unit %d)\n", TxUDEF);
+ fprintf(stderr,"\n");
+ exit(1);
+}
+
+/* EOF */
diff --git a/usr.sbin/i4b/isdndecode/pcause.c b/usr.sbin/i4b/isdndecode/pcause.c
new file mode 100644
index 0000000..9c5535e
--- /dev/null
+++ b/usr.sbin/i4b/isdndecode/pcause.c
@@ -0,0 +1,328 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * pcause.c - printing cause values
+ * --------------------------------
+ *
+ * $Id: pcause.c,v 1.3 1998/12/23 10:03:55 hm Exp $
+ *
+ * last edit-date: [Wed Dec 23 10:59:54 1998]
+ *
+ *---------------------------------------------------------------------------*/
+
+#include "decode.h"
+#include "pcause.h"
+
+char *
+print_cause_q850(unsigned char code)
+{
+ static char error_message[120];
+ char *e;
+
+ switch(code)
+ {
+ case CAUSE_Q850_SHUTDN:
+ e = "normal D-channel shutdown";
+ break;
+
+ case CAUSE_Q850_NUNALLC:
+ e = "Unallocated (unassigned) number";
+ break;
+
+ case CAUSE_Q850_NRTTN:
+ e = "No route to specified transit network";
+ break;
+
+ case CAUSE_Q850_NRTDST:
+ e = "No route to destination";
+ break;
+
+ case CAUSE_Q850_SSINFTN:
+ e = "Send special information tone";
+ break;
+
+ case CAUSE_Q850_MDIALTP:
+ e = "Misdialled trunk prefix";
+ break;
+
+ case CAUSE_Q850_CHUNACC:
+ e = "Channel unacceptable";
+ break;
+
+ case CAUSE_Q850_CALLAWD:
+ e = "Call awarded and being delivered in an established channel";
+ break;
+
+ case CAUSE_Q850_PREEMPT:
+ e = "Preemption";
+ break;
+
+ case CAUSE_Q850_PREECRR:
+ e = "Preemption - circuit reserved for reuse";
+ break;
+
+ case CAUSE_Q850_NCCLR:
+ e = "Normal call clearing";
+ break;
+
+ case CAUSE_Q850_USRBSY:
+ e = "User busy";
+ break;
+
+ case CAUSE_Q850_NOUSRRSP:
+ e = "No user responding";
+ break;
+
+ case CAUSE_Q850_NOANSWR:
+ e = "No answer from user (user alerted)";
+ break;
+
+ case CAUSE_Q850_SUBSABS:
+ e = "Subscriber absent";
+ break;
+
+ case CAUSE_Q850_CALLREJ:
+ e = "Call rejected";
+ break;
+
+ case CAUSE_Q850_NUCHNG:
+ e = "Number changed";
+ break;
+
+ case CAUSE_Q850_NONSELUC:
+ e = "Non-selected user clearing";
+ break;
+
+ case CAUSE_Q850_DSTOOORDR:
+ e = "Destination out of order";
+ break;
+
+ case CAUSE_Q850_INVNUFMT:
+ e = "Invalid number format";
+ break;
+
+ case CAUSE_Q850_FACREJ:
+ e = "Facility rejected";
+ break;
+
+ case CAUSE_Q850_STENQRSP:
+ e = "Response to STATUS ENQUIRY";
+ break;
+
+ case CAUSE_Q850_NORMUNSP:
+ e = "Normal, unspecified";
+ break;
+
+ case CAUSE_Q850_NOCAVAIL:
+ e = "No circuit / channel available";
+ break;
+
+ case CAUSE_Q850_NETOOORDR:
+ e = "Network out of order";
+ break;
+
+ case CAUSE_Q850_PFMCDOOSERV:
+ e = "Permanent frame mode connection out of service";
+ break;
+
+ case CAUSE_Q850_PFMCOPER:
+ e = "Permanent frame mode connection operational";
+ break;
+
+ case CAUSE_Q850_TMPFAIL:
+ e = "Temporary failure";
+ break;
+
+ case CAUSE_Q850_SWEQCONG:
+ e = "Switching equipment congestion";
+ break;
+
+ case CAUSE_Q850_ACCINFDIS:
+ e = "Access information discarded";
+ break;
+
+ case CAUSE_Q850_REQCNOTAV:
+ e = "Requested circuit/channel not available";
+ break;
+
+ case CAUSE_Q850_PRECALBLK:
+ e = "Precedence call blocked";
+ break;
+
+ case CAUSE_Q850_RESUNAVAIL:
+ e = "Resources unavailable, unspecified";
+ break;
+
+ case CAUSE_Q850_QOSUNAVAIL:
+ e = "Quality of service unavailable";
+ break;
+
+ case CAUSE_Q850_REQSERVNS:
+ e = "Requested facility not subscribed";
+ break;
+
+ case CAUSE_Q850_OCBARRCUG:
+ e = "Outgoing calls barred within CUG";
+ break;
+
+ case CAUSE_Q850_ICBARRCUG:
+ e = "Incoming calls barred within CUG";
+ break;
+
+ case CAUSE_Q850_BCAPNAUTH:
+ e = "Bearer capability not authorized";
+ break;
+
+ case CAUSE_Q850_BCAPNAVAIL:
+ e = "Bearer capability not presently available";
+ break;
+
+ case CAUSE_Q850_INCSTOACISC:
+ e = "Inconsistenciy in designated outg. access info and subscriber class";
+ break;
+
+ case CAUSE_Q850_SOONOTAVAIL:
+ e = "Service or option not available, unspecified";
+ break;
+
+ case CAUSE_Q850_BCAPNOTIMPL:
+ e = "Bearer capability not implemented";
+ break;
+
+ case CAUSE_Q850_CHTYPNIMPL:
+ e = "Channel type not implemented";
+ break;
+
+ case CAUSE_Q850_REQFACNIMPL:
+ e = "Requested facility not implemented";
+ break;
+
+ case CAUSE_Q850_ORDINBCAVL:
+ e = "Only restricted digital information bearer capability is available";
+ break;
+
+ case CAUSE_Q850_SOONOTIMPL:
+ e = "Service or option not implemented, unspecified";
+ break;
+
+ case CAUSE_Q850_INVCLRFVAL:
+ e = "Invalid call reference value";
+ break;
+
+ case CAUSE_Q850_IDCHDNOEX:
+ e = "Identified channel does not exist";
+ break;
+
+ case CAUSE_Q850_SUSCAEXIN:
+ e = "A suspended call exists, but this call identity does not";
+ break;
+
+ case CAUSE_Q850_CLIDINUSE:
+ e = "Call identity in use";
+ break;
+
+ case CAUSE_Q850_NOCLSUSP:
+ e = "No call suspended";
+ break;
+
+ case CAUSE_Q850_CLIDCLRD:
+ e = "Call having the requested call identity has been cleared";
+ break;
+
+ case CAUSE_Q850_UNOTMEMCUG:
+ e = "User not member of CUG";
+ break;
+
+ case CAUSE_Q850_INCDEST:
+ e = "Incompatible destination";
+ break;
+
+ case CAUSE_Q850_NONEXCUG:
+ e = "Non-existent CUG";
+ break;
+
+ case CAUSE_Q850_INVNTWSEL:
+ e = "Invalid transit network selection";
+ break;
+
+ case CAUSE_Q850_INVMSG:
+ e = "Invalid message, unspecified";
+ break;
+
+ case CAUSE_Q850_MIEMISS:
+ e = "Mandatory information element is missing";
+ break;
+
+ case CAUSE_Q850_MSGTNI:
+ e = "Message type non-existent or not implemented";
+ break;
+
+ case CAUSE_Q850_MSGNCMPT:
+ e = "Msg incompatible with call state/message type non-existent/not implemented";
+ break;
+
+ case CAUSE_Q850_IENENI:
+ e = "Information element/parameter non-existent or not implemented";
+ break;
+
+ case CAUSE_Q850_INVIEC:
+ e = "Invalid information element contents";
+ break;
+
+ case CAUSE_Q850_MSGNCWCS:
+ e = "Message not compatible with call state";
+ break;
+
+ case CAUSE_Q850_RECOTIMEXP:
+ e = "Recovery on timer expiry";
+ break;
+
+ case CAUSE_Q850_PARMNENIPO:
+ e = "Parameter non-existent or not implemented, passed on";
+ break;
+
+ case CAUSE_Q850_MSGUNRDPRM:
+ e = "Message with unrecognized parameter, discarded";
+ break;
+
+ case CAUSE_Q850_PROTERR:
+ e = "Protocol error, unspecified";
+ break;
+
+ case CAUSE_Q850_INTWRKU:
+ e = "Interworking, unspecified";
+ break;
+
+ default:
+ e = "ERROR, unknown cause value!";
+ break;
+ }
+
+ sprintf(error_message, "%d: %s (Q.850)", code, e);
+ return(error_message);
+}
+
+/* EOF */
diff --git a/usr.sbin/i4b/isdndecode/pcause.h b/usr.sbin/i4b/isdndecode/pcause.h
new file mode 100644
index 0000000..6b6627b
--- /dev/null
+++ b/usr.sbin/i4b/isdndecode/pcause.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * pcause.h - Q.850 causes definitions
+ * -----------------------------------
+ *
+ * $Id: pcause.h,v 1.2 1998/12/18 17:09:38 hm Exp $
+ *
+ * last edit-date: [Fri Dec 18 18:13:23 1998]
+ *
+ *---------------------------------------------------------------------------*/
+
+char *print_cause_q850(unsigned char code);
+
+/* Q.850 causes */
+
+#define CAUSE_Q850_SHUTDN 0x00 /* normal D-channel shutdown */
+#define CAUSE_Q850_NUNALLC 0x01 /* Unallocated (unassigned) number */
+#define CAUSE_Q850_NRTTN 0x02 /* No route to specified transit network */
+#define CAUSE_Q850_NRTDST 0x03 /* No route to destination */
+#define CAUSE_Q850_SSINFTN 0x04 /* Send special information tone */
+#define CAUSE_Q850_MDIALTP 0x05 /* Misdialled trunk prefix */
+#define CAUSE_Q850_CHUNACC 0x06 /* Channel unacceptable */
+#define CAUSE_Q850_CALLAWD 0x07 /* Call awarded and being delivered in an established channel */
+#define CAUSE_Q850_PREEMPT 0x08 /* Preemption */
+#define CAUSE_Q850_PREECRR 0x09 /* Preemption - circuit reserved for reuse */
+#define CAUSE_Q850_NCCLR 0x10 /* Normal call clearing */
+#define CAUSE_Q850_USRBSY 0x11 /* User busy */
+#define CAUSE_Q850_NOUSRRSP 0x12 /* No user responding */
+#define CAUSE_Q850_NOANSWR 0x13 /* No answer from user (user alerted) */
+#define CAUSE_Q850_SUBSABS 0x14 /* Subscriber absent */
+#define CAUSE_Q850_CALLREJ 0x15 /* Call rejected */
+#define CAUSE_Q850_NUCHNG 0x16 /* Number changed */
+#define CAUSE_Q850_NONSELUC 0x1A /* Non-selected user clearing */
+#define CAUSE_Q850_DSTOOORDR 0x1B /* Destination out of order */
+#define CAUSE_Q850_INVNUFMT 0x1C /* Invalid number format */
+#define CAUSE_Q850_FACREJ 0x1D /* Facility rejected */
+#define CAUSE_Q850_STENQRSP 0x1E /* Response to STATUS ENQUIRY */
+#define CAUSE_Q850_NORMUNSP 0x1F /* Normal, unspecified */
+#define CAUSE_Q850_NOCAVAIL 0x22 /* No circuit / channel available */
+#define CAUSE_Q850_NETOOORDR 0x26 /* Network out of order */
+#define CAUSE_Q850_PFMCDOOSERV 0x27 /* Permanent frame mode connection out of service */
+#define CAUSE_Q850_PFMCOPER 0x28 /* Permanent frame mode connection operational */
+#define CAUSE_Q850_TMPFAIL 0x29 /* Temporary failure */
+#define CAUSE_Q850_SWEQCONG 0x2A /* Switching equipment congestion */
+#define CAUSE_Q850_ACCINFDIS 0x2B /* Access information discarded */
+#define CAUSE_Q850_REQCNOTAV 0x2C /* Requested circuit/channel not available */
+#define CAUSE_Q850_PRECALBLK 0x2E /* Precedence call blocked */
+#define CAUSE_Q850_RESUNAVAIL 0x2F /* Resources unavailable, unspecified */
+#define CAUSE_Q850_QOSUNAVAIL 0x31 /* Quality of service unavailable */
+#define CAUSE_Q850_REQSERVNS 0x32 /* Requested facility not subscribed */
+#define CAUSE_Q850_OCBARRCUG 0x35 /* Outgoing calls barred within CUG */
+#define CAUSE_Q850_ICBARRCUG 0x36 /* Incoming calls barred within CUG */
+#define CAUSE_Q850_BCAPNAUTH 0x39 /* Bearer capability not authorized */
+#define CAUSE_Q850_BCAPNAVAIL 0x3A /* Bearer capability not presently available */
+#define CAUSE_Q850_INCSTOACISC 0x3E /* Inconsistenciy in designated outgoing access information and subscriber class */
+#define CAUSE_Q850_SOONOTAVAIL 0x3F /* Service or option not available, unspecified */
+#define CAUSE_Q850_BCAPNOTIMPL 0x41 /* Bearer capability not implemented */
+#define CAUSE_Q850_CHTYPNIMPL 0x42 /* Channel type not implemented */
+#define CAUSE_Q850_REQFACNIMPL 0x45 /* Requested facility not implemented */
+#define CAUSE_Q850_ORDINBCAVL 0x46 /* Only restricted digital information bearer capability is available */
+#define CAUSE_Q850_SOONOTIMPL 0x4F /* Service or option not implemented, unspecified */
+#define CAUSE_Q850_INVCLRFVAL 0x51 /* Invalid call reference value */
+#define CAUSE_Q850_IDCHDNOEX 0x52 /* Identified channel does not exist */
+#define CAUSE_Q850_SUSCAEXIN 0x53 /* A suspended call exists, but this call identity does not */
+#define CAUSE_Q850_CLIDINUSE 0x54 /* Call identity in use */
+#define CAUSE_Q850_NOCLSUSP 0x55 /* No call suspended */
+#define CAUSE_Q850_CLIDCLRD 0x56 /* Call having the requested call identity has been cleared */
+#define CAUSE_Q850_UNOTMEMCUG 0x57 /* User not member of CUG */
+#define CAUSE_Q850_INCDEST 0x58 /* Incompatible destination */
+#define CAUSE_Q850_NONEXCUG 0x5A /* Non-existent CUG */
+#define CAUSE_Q850_INVNTWSEL 0x5B /* Invalid transit network selection */
+#define CAUSE_Q850_INVMSG 0x5F /* Invalid message, unspecified */
+#define CAUSE_Q850_MIEMISS 0x60 /* Mandatory information element is missing */
+#define CAUSE_Q850_MSGTNI 0x61 /* Message type non-existent or not implemented */
+#define CAUSE_Q850_MSGNCMPT 0x62 /* Message not compatible with call state or message type non-existent or not implemented */
+#define CAUSE_Q850_IENENI 0x63 /* Information element/parameter non-existent or not implemented */
+#define CAUSE_Q850_INVIEC 0x64 /* Invalid information element contents */
+#define CAUSE_Q850_MSGNCWCS 0x65 /* Message not compatible with call state */
+#define CAUSE_Q850_RECOTIMEXP 0x66 /* Recovery on timer expiry */
+#define CAUSE_Q850_PARMNENIPO 0x67 /* Parameter non-existent or not implemented, passed on */
+#define CAUSE_Q850_MSGUNRDPRM 0x6E /* Message with unrecognized parameter, discarded */
+#define CAUSE_Q850_PROTERR 0x6F /* Protocol error, unspecified */
+#define CAUSE_Q850_INTWRKU 0x7F /* Interworking, unspecified */
+
+/* EOF */
diff --git a/usr.sbin/i4b/isdnmonitor/Makefile b/usr.sbin/i4b/isdnmonitor/Makefile
new file mode 100644
index 0000000..9d3811b
--- /dev/null
+++ b/usr.sbin/i4b/isdnmonitor/Makefile
@@ -0,0 +1,8 @@
+PROG = isdnmonitor
+SRCS = main.c
+MAN8 = isdnmonitor.8
+
+# compile debug support
+COPTS += -DDEBUG
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/i4b/isdnmonitor/isdnmonitor.8 b/usr.sbin/i4b/isdnmonitor/isdnmonitor.8
new file mode 100644
index 0000000..9bcb783
--- /dev/null
+++ b/usr.sbin/i4b/isdnmonitor/isdnmonitor.8
@@ -0,0 +1,40 @@
+.\" Copyright (c) 1998 Martin Husemann <martin@rumolt.teuto.de>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. The name of the author may not be used to endorse or promote products
+.\" derived from this software withough specific prior written permission
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $Id: isdnmonitor.8,v 1.2 1998/08/10 13:55:29 hm Exp $
+.\"
+.\" last edit-date: [Fri Jan 30 22:49:48 1998]
+.\"
+.\" -mh writing manual pages
+.\"
+.\"
+.Dd April 18, 1998
+.Dt isdnmonitor 8
+.Sh NAME
+.Nm isdnmonitor
+.Nd raw sample and test client for isdnd network monitoring
+.Sh DESCRIPTION
+The
+.Nm
+is not intended for real world use. It will be replaced
+by something with a better user interface as soon as the monitoring
+subsystem is functional.
diff --git a/usr.sbin/i4b/isdnmonitor/main.c b/usr.sbin/i4b/isdnmonitor/main.c
new file mode 100644
index 0000000..73ae8fe
--- /dev/null
+++ b/usr.sbin/i4b/isdnmonitor/main.c
@@ -0,0 +1,675 @@
+/*
+ * Copyright (c) 1998 Martin Husemann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 4. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software and/or documentation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * i4b daemon - network monitor client
+ * -----------------------------------
+ *
+ * $Id: main.c,v 1.9 1998/10/27 10:54:23 hm Exp $
+ *
+ * last edit-date: [Tue Oct 27 11:53:12 1998]
+ *
+ * -mh created
+ * -hm checking in
+ * -hm porting to HPUX
+ * -mh all events the fullscreen mode displays now as monitor event
+ *
+ *---------------------------------------------------------------------------*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <time.h>
+#include <errno.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <machine/i4b_ioctl.h>
+
+#ifdef __hpux
+#define AF_LOCAL AF_UNIX
+#endif
+
+#ifdef DEBUG
+#include <ctype.h>
+#endif
+
+#include "monitor.h"
+
+/*
+ * Local function prototypes
+ */
+static int connect_local(const char *sockpath);
+static int connect_remote(const char *host, int portno);
+static void usage();
+static void mloop();
+static void handle_input();
+static void print_menu();
+static void print_logevent(time_t tstamp, int prio, const char * what, const char * msg);
+static void print_charge(time_t tstamp, int channel, int units, int estimated);
+static void print_connect(time_t tstamp, int dir, int channel, const char * cfgname, const char * devname, const char * remphone, const char * locphone);
+static void print_disconnect(time_t tstamp, int channel);
+static void print_updown(time_t tstamp, int channel, int isup);
+static void handle_event(BYTE *msg, int len);
+#ifdef DEBUG
+static void dump_event(BYTE *msg, int len);
+#endif
+
+/*
+ * Global variables
+ */
+static int dumpall = 0;
+static int monsock = -1;
+static int state = 0;
+static int sub_state = 0;
+static int sub_state_count = 0;
+
+static int major = 0;
+static int minor = 0;
+static int nctrl = 0;
+static u_int32_t rights = 0;
+
+/*
+ * Parse command line, startup monitor client
+ */
+int main(int argc, char **argv)
+{
+ char * sockpath = NULL;
+ char * hostname = NULL;
+ int portno = DEF_MONPORT;
+ int i;
+
+ while ((i = getopt(argc, argv, "dh:p:l:")) != EOF)
+ {
+ switch (i)
+ {
+ case 'd':
+ dumpall = 1;
+ break;
+ case 'h':
+ hostname = optarg;
+ break;
+ case 'l':
+ sockpath = optarg;
+ break;
+ case 'p':
+ if ((sscanf(optarg, "%i", &portno)) != 1)
+ usage();
+ break;
+ default:
+ usage();
+ break;
+ }
+ }
+
+ if (hostname && sockpath)
+ {
+ fprintf(stderr, "Error: can not use local socket path on remote machine\n"
+ "conflicting options -h and -l!\n");
+ return 1;
+ }
+
+ if (sockpath)
+ {
+ monsock = connect_local(sockpath);
+ }
+ else if (hostname)
+ {
+ monsock = connect_remote(hostname, portno);
+ }
+ else
+ {
+ usage();
+ }
+
+ if (monsock == -1)
+ {
+ fprintf(stderr, "Could not connect to i4b isdn daemon.\n");
+ return 1;
+ }
+
+ signal(SIGPIPE, SIG_IGN);
+ mloop();
+
+ close(monsock);
+
+ return 0;
+}
+
+/*
+ * Display usage and exit
+ */
+static void usage()
+{
+ fprintf(stderr, "usage:\n"
+ " isdnmonitor [-d] -h (host) -p (port)\n"
+ "or\n"
+ " isdnmonitor [-d] -l (path)\n"
+ "where (host) is the hostname and (port) the port number of\n"
+ "the isdnd to be monitored and (path) is the pathname of the\n"
+ "local domain socket used to communicate with a daemon on the\n"
+ "local machine.\n"
+ "Options are:\n"
+ " -d dump all incoming packets as hexdump\n"
+ );
+ exit(0);
+}
+
+/*
+ * Connect via tcp/ip.
+ * Return socket if successfull, -1 on error.
+ */
+static int connect_remote(const char *host, int portno)
+{
+ struct sockaddr_in sa;
+ struct hostent *h;
+ int remotesockfd;
+
+ h = gethostbyname(host);
+
+ if (!h)
+ {
+ fprintf(stderr, "could not resolve hostname '%s'\n", host);
+ exit(1);
+ }
+
+ remotesockfd = socket(AF_INET, SOCK_STREAM, 0);
+
+ if (remotesockfd == -1)
+ {
+ fprintf(stderr, "could not create remote monitor socket: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ memset(&sa, 0, sizeof sa);
+
+#ifdef BSD4_4
+ sa.sin_len = sizeof sa;
+#endif
+ sa.sin_family = AF_INET;
+ sa.sin_port = htons(portno);
+
+ memcpy(&sa.sin_addr.s_addr, h->h_addr_list[0], sizeof sa.sin_addr.s_addr);
+
+ if (connect(remotesockfd, (struct sockaddr *)&sa, sizeof sa) == -1)
+ {
+ fprintf(stderr, "could not connect remote monitor: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ return remotesockfd;
+}
+
+/*
+ * Connect local.
+ * Return socket on success, -1 on failure.
+ */
+static int connect_local(const char *sockpath)
+{
+ int s;
+ struct sockaddr_un sa;
+
+ /* check path length */
+ if (strlen(sockpath) >= sizeof sa.sun_path)
+ {
+ fprintf(stderr, "pathname to long for local socket: %s\n",
+ sockpath);
+ exit(1);
+ }
+
+ /* create and setup socket */
+ s = socket(AF_LOCAL, SOCK_STREAM, 0);
+
+ if (s == -1)
+ {
+ fprintf(stderr, "could not create local monitor socket:%s\n", strerror(errno));
+ exit(1);
+ }
+
+ memset(&sa, 0, sizeof sa);
+
+#ifndef __hpux
+ sa.sun_len = sizeof sa;
+#endif
+
+ sa.sun_family = AF_LOCAL;
+ strcpy(sa.sun_path, sockpath);
+
+ if (connect(s, (struct sockaddr *)&sa, sizeof sa))
+ {
+ fprintf(stderr, "could not connect local monitor socket [%s]: %s\n", sockpath, strerror(errno));
+ }
+
+ return s;
+}
+
+/*
+ * main event loop
+ */
+static void mloop()
+{
+ for (;;)
+ {
+ fd_set rd, wr, ex;
+
+ FD_ZERO(&rd);
+ FD_ZERO(&wr);
+ FD_ZERO(&ex);
+ FD_SET(fileno(stdin), &rd);
+ FD_SET(monsock, &rd);
+
+ select(monsock+1, &rd, &wr, &ex, NULL);
+
+ if (FD_ISSET(fileno(stdin), &rd))
+ {
+ handle_input();
+ }
+
+ if (FD_ISSET(monsock, &rd))
+ {
+ BYTE buf[1024];
+ u_long u;
+ int bytes, ret;
+
+ /* Network transfer may deliver two or more packets concatenated.
+ * Peek at the header and read only one event at a time... */
+
+ ioctl(monsock, FIONREAD, &u);
+
+ if (u < I4B_MON_EVNT_HDR)
+ continue; /* not enough data there yet */
+
+ bytes = recv(monsock, buf, I4B_MON_EVNT_HDR, MSG_PEEK);
+
+ if (bytes < I4B_MON_EVNT_HDR)
+ continue; /* errh? something must be wrong... */
+
+ bytes = I4B_GET_2B(buf, I4B_MON_EVNT_LEN);
+
+ if (bytes >= sizeof buf)
+ break;
+
+ /* now we know the size, it fits, so lets read it! */
+
+ ret = read(monsock, buf, bytes);
+
+ if (ret == 0)
+ {
+ printf("remote isdnd has closed our connection\n");
+ break;
+ }
+ else if (ret < 0)
+ {
+ printf("error reading from isdnd: %s", strerror(errno));
+ break;
+ }
+#ifdef DEBUG
+ if (dumpall)
+ dump_event(buf, ret);
+#endif
+ handle_event(buf, ret);
+ }
+ }
+}
+
+#ifdef DEBUG
+/*
+ * Dump a complete event packet.
+ */
+static void dump_event(BYTE *msg, int len)
+{
+ int i;
+
+ printf("event dump:");
+
+ for (i = 0; i < len; i++)
+ {
+ if (i % 8 == 0)
+ printf("\n%02x: ", i);
+ printf("%02x %c ", msg[i], isprint(msg[i]) ? msg[i] : '.');
+ }
+ printf("\n");
+}
+#endif
+
+static void print_logevent(time_t tstamp, int prio, const char * what, const char * msg)
+{
+ char buf[256];
+ strftime(buf, sizeof buf, I4B_TIME_FORMAT, localtime(&tstamp));
+ printf("log: %s prio %d what=%s msg=%s\n",
+ buf, prio, what, msg);
+}
+
+static void print_charge(time_t tstamp, int channel, int units, int estimated)
+{
+ char buf[256];
+ strftime(buf, sizeof buf, I4B_TIME_FORMAT, localtime(&tstamp));
+ printf("%s: channel %d, charge = %d%s\n",
+ buf, channel, units, estimated ? " (estimated)" : "");
+}
+
+/*
+ * Print a connect event.
+ * A real monitor would allocate state info for "channel" on this
+ * event.
+ */
+static void print_connect(
+ time_t tstamp, /* server time of event */
+ int outgoing, /* 0 = incoming, 1 = outgoing */
+ int channel, /* channel no, used to identify this connection until disconnect */
+ const char * cfgname, /* name of config entry/connection */
+ const char * devname, /* device used (e.g. isp0) */
+ const char * remphone, /* phone no of remote side */
+ const char * locphone) /* local phone no */
+{
+ char buf[256];
+ strftime(buf, sizeof buf, I4B_TIME_FORMAT, localtime(&tstamp));
+
+ if (outgoing)
+ printf("%s: calling out to '%s' [from msn: '%s']",
+ buf, remphone, locphone);
+ else
+ printf("%s: incoming call from '%s' [to msn: '%s']",
+ buf, remphone, locphone);
+ printf(", channel %d, config '%s' on device '%s'\n",
+ channel, cfgname, devname);
+}
+
+/*
+ * Print a disconnect event.
+ * A real monitor could free the "per connection" state
+ * for this channel now
+ */
+static void print_disconnect(time_t tstamp, int channel)
+{
+ char buf[256];
+ strftime(buf, sizeof buf, I4B_TIME_FORMAT, localtime(&tstamp));
+ printf("%s: channel %d disconnected\n",
+ buf, channel);
+}
+
+/*
+ * Print an up- or down event
+ */
+static void print_updown(time_t tstamp, int channel, int isup)
+{
+ char buf[256];
+ strftime(buf, sizeof buf, I4B_TIME_FORMAT, localtime(&tstamp));
+ printf("%s: channel %d is %s\n",
+ buf, channel, isup ? "up" : "down");
+}
+
+/*
+ * Dispatch one message received from the daemon.
+ */
+static void handle_event(BYTE *msg, int len)
+{
+ BYTE cmd[I4B_MON_ICLIENT_SIZE];
+ int local;
+ u_int32_t net;
+ u_int32_t mask;
+ u_int32_t who;
+
+ switch (state)
+ {
+ case 0: /* initial data */
+
+ major = I4B_GET_2B(msg, I4B_MON_IDATA_VERSMAJOR);
+ minor = I4B_GET_2B(msg, I4B_MON_IDATA_VERSMINOR);
+ nctrl = I4B_GET_2B(msg, I4B_MON_IDATA_NUMCTRL);
+ rights = I4B_GET_4B(msg, I4B_MON_IDATA_CLACCESS);
+
+ printf("remote protocol version is %02d.%02d, %d controller(s) found, our rights = %x\n",
+ major, minor, nctrl, rights);
+
+ if (nctrl > 0)
+ {
+ state = 1;
+ sub_state = 0;
+ }
+ else
+ {
+ state = 2;
+
+ /* show menu for the first time */
+ print_menu();
+ }
+
+ /* set maximum event mask */
+ I4B_PREP_CMD(cmd, I4B_MON_CCMD_SETMASK);
+ I4B_PUT_2B(cmd, I4B_MON_ICLIENT_VERMAJOR, MPROT_VERSION);
+ I4B_PUT_2B(cmd, I4B_MON_ICLIENT_VERMINOR, MPROT_REL);
+ I4B_PUT_4B(cmd, I4B_MON_ICLIENT_EVENTS, ~0U);
+
+ write(monsock, cmd, sizeof cmd);
+
+ break;
+
+ case 1: /* initial controller list */
+ printf("controller %d: %s\n", sub_state++, msg+I4B_MON_ICTRL_NAME);
+
+ if (sub_state >= nctrl)
+ {
+ state = 2; /* end of list reached */
+ sub_state = 0;
+
+ /* show menu for the first time */
+ print_menu();
+ }
+ break;
+
+ case 2: /* any event */
+
+ switch (I4B_GET_2B(msg, I4B_MON_EVNT))
+ {
+ case I4B_MON_DRINI_CODE:
+ state = 3; /* list of rights entries will follow */
+ sub_state = 0;
+ sub_state_count = I4B_GET_2B(msg, I4B_MON_DRINI_COUNT);
+ printf("monitor rights:\n");
+ break;
+
+ case I4B_MON_DCINI_CODE:
+ state = 4;
+ sub_state = 0;
+ sub_state_count = I4B_GET_2B(msg, I4B_MON_DCINI_COUNT);
+ printf("monitor connections:\n");
+ break;
+
+ case I4B_MON_LOGEVNT_CODE:
+ print_logevent(I4B_GET_4B(msg, I4B_MON_LOGEVNT_TSTAMP),
+ I4B_GET_4B(msg, I4B_MON_LOGEVNT_PRIO),
+ msg+I4B_MON_LOGEVNT_WHAT,
+ msg+I4B_MON_LOGEVNT_MSG);
+ break;
+
+ case I4B_MON_CHRG_CODE:
+ print_charge(I4B_GET_4B(msg, I4B_MON_CHRG_TSTAMP),
+ I4B_GET_4B(msg, I4B_MON_CHRG_CHANNEL),
+ I4B_GET_4B(msg, I4B_MON_CHRG_UNITS),
+ I4B_GET_4B(msg, I4B_MON_CHRG_ESTIMATED));
+ break;
+
+ case I4B_MON_CONNECT_CODE:
+ print_connect(
+ I4B_GET_4B(msg, I4B_MON_CONNECT_TSTAMP),
+ I4B_GET_4B(msg, I4B_MON_CONNECT_DIR),
+ I4B_GET_4B(msg, I4B_MON_CONNECT_CHANNEL),
+ msg+I4B_MON_CONNECT_CFGNAME,
+ msg+I4B_MON_CONNECT_DEVNAME,
+ msg+I4B_MON_CONNECT_REMPHONE,
+ msg+I4B_MON_CONNECT_LOCPHONE);
+ break;
+
+ case I4B_MON_DISCONNECT_CODE:
+ print_disconnect(
+ I4B_GET_4B(msg, I4B_MON_DISCONNECT_TSTAMP),
+ I4B_GET_4B(msg, I4B_MON_DISCONNECT_CHANNEL));
+ break;
+
+ case I4B_MON_UPDOWN_CODE:
+ print_updown(
+ I4B_GET_4B(msg, I4B_MON_UPDOWN_TSTAMP),
+ I4B_GET_4B(msg, I4B_MON_UPDOWN_CHANNEL),
+ I4B_GET_4B(msg, I4B_MON_UPDOWN_ISUP));
+ break;
+
+ default:
+ printf("unknown event code: %d\n", I4B_GET_2B(msg, I4B_MON_EVNT));
+ }
+ break;
+
+ case 3: /* one record in a list of monitor rights */
+ rights = I4B_GET_4B(msg, I4B_MON_DR_RIGHTS);
+ net = I4B_GET_4B(msg, I4B_MON_DR_NET);
+ mask = I4B_GET_4B(msg, I4B_MON_DR_MASK);
+ local = I4B_GET_1B(msg, I4B_MON_DR_LOCAL);
+
+ if (local)
+ {
+ printf("\tlocal: rights = %x\n", rights);
+ }
+ else
+ {
+ printf("\tfrom: %d.%d.%d.%d, mask %d.%d.%d.%d, rights = %x\n",
+ (net >> 24) & 0x00ff, (net >> 16) & 0x00ff, (net >> 8) & 0x00ff, net & 0x00ff,
+ (mask >> 24) & 0x00ff, (mask >> 16) & 0x00ff, (mask >> 8) & 0x00ff, mask & 0x00ff,
+ rights);
+ }
+
+ sub_state++;
+
+ if (sub_state >= sub_state_count)
+ {
+ state = 2;
+ print_menu();
+ }
+ break;
+
+ case 4:
+ who = I4B_GET_4B(msg, I4B_MON_DC_WHO);
+ rights = I4B_GET_4B(msg, I4B_MON_DC_RIGHTS);
+
+ printf("\tfrom: %d.%d.%d.%d, rights = %x\n",
+ (who >> 24) & 0x00ff, (who >> 16) & 0x00ff, (who >> 8) & 0x00ff, who & 0x00ff,
+ rights);
+
+ sub_state++;
+
+ if (sub_state >= sub_state_count)
+ {
+ state = 2;
+ print_menu();
+ }
+ break;
+
+ default:
+ printf("unknown event from remote: local state = %d, evnt = %x, len = %d\n",
+ state, I4B_GET_2B(msg, I4B_MON_EVNT), len);
+ }
+}
+
+/*
+ * Process input from user
+ */
+static void handle_input()
+{
+ char buf[1024];
+ int channel;
+
+ fgets(buf, sizeof buf, stdin);
+
+ switch (atoi(buf))
+ {
+ case 1:
+ {
+ BYTE cmd[I4B_MON_DUMPRIGHTS_SIZE];
+ I4B_PREP_CMD(cmd, I4B_MON_DUMPRIGHTS_CODE);
+ write(monsock, cmd, I4B_MON_DUMPRIGHTS_SIZE);
+ }
+ break;
+
+ case 2:
+ {
+ BYTE cmd[I4B_MON_DUMPMCONS_SIZE];
+ I4B_PREP_CMD(cmd, I4B_MON_DUMPMCONS_CODE);
+ write(monsock, cmd, I4B_MON_DUMPMCONS_SIZE);
+ }
+ break;
+
+ case 3:
+ {
+ BYTE cmd[I4B_MON_CFGREREAD_SIZE];
+ I4B_PREP_CMD(cmd, I4B_MON_CFGREREAD_CODE);
+ write(monsock, cmd, I4B_MON_CFGREREAD_SIZE);
+ }
+ break;
+
+ case 4:
+ {
+ BYTE cmd[I4B_MON_HANGUP_SIZE];
+ I4B_PREP_CMD(cmd, I4B_MON_HANGUP_CODE);
+ printf("Which channel do you wish to hangup? ");
+ fgets(buf, sizeof buf, stdin);
+ channel = atoi(buf);
+ I4B_PUT_4B(cmd, I4B_MON_HANGUP_CHANNEL, channel);
+ write(monsock, cmd, I4B_MON_HANGUP_SIZE);
+ }
+ break;
+
+ case 9:
+ close(monsock);
+ exit(0);
+ break;
+
+ default:
+ print_menu();
+ break;
+ }
+}
+
+/*
+ * Display menu
+ */
+static void print_menu()
+{
+ printf("Menu: <1> display rights, <2> display monitor connections,\n");
+ printf(" <3> reread config file, <4> hangup \n");
+ printf(" <9> quit isdnmonitor\n");
+}
diff --git a/usr.sbin/i4b/isdnmonitor/monitor.h b/usr.sbin/i4b/isdnmonitor/monitor.h
new file mode 100644
index 0000000..0025449
--- /dev/null
+++ b/usr.sbin/i4b/isdnmonitor/monitor.h
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 1998 Martin Husemann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 4. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software and/or documentation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * i4b daemon - network monitor protocl definition
+ * -----------------------------------------------
+ *
+ * $Id: monitor.h,v 1.4 1998/08/10 13:55:32 hm Exp $
+ *
+ * last edit-date: [Mon Aug 3 06:52:06 1998]
+ *
+ * -mh created
+ * -hm checking in
+ * -hm ported to HPUX 10.10
+ *
+ *---------------------------------------------------------------------------*/
+
+#ifndef MONITOR_H
+#define MONITOR_H
+
+#define DEF_MONPORT 451 /* default monitor TCP port */
+
+#ifdef __hpux
+#define u_int8_t ubit8
+#define u_int32_t ubit32
+#endif
+#ifdef _WIN32
+#define u_int8_t BYTE
+#define u_in32_t DWORD
+#endif
+
+/*
+ * The monitor client connects to the isdnd daemon process via a tcp/ip
+ * connection from a remote machine or via a local (unix domain) socket.
+ * The daemon accepts multiple connections and verifies access rights.
+ * On connection establishment the daemon sends initial data telling
+ * the client the current configuration: number and type of available
+ * controllers, current connections, channel and interface states
+ * and the clients access privileges. The client sends an event mask
+ * telling the daemon which events it is interested in. If the client
+ * has appropriate rights he may send commands to the daemon.
+ *
+ * All multi-byte values are in network byte order!
+ */
+
+/* All data packets transfered are declared as arrays of BYTE */
+#define BYTE u_int8_t
+
+/* max stringlength used in this protocol */
+#define I4B_MAX_MON_STRING 256
+
+/* max command size from client to server */
+#define I4B_MAX_MON_CLIENT_CMD 16
+
+/* Version of the monitor protocol described here */
+#define MPROT_VERSION 0 /* major version no */
+#define MPROT_REL 1 /* release no */
+/*
+ * We intend to keep different versions of monitor client and isdnd
+ * interoperable as long as possible. We do not, however, even try
+ * to do this during early alpha or beta release phases. If you run
+ * developement versions at this stage, make sure all your clients
+ * and servers run the same version!
+ */
+
+/*
+ * Client access rights
+ */
+#define I4B_CA_COMMAND_FULL 1 /* may send any command */
+#define I4B_CA_COMMAND_RESTRICTED 2 /* may send 'harmless' commands */
+#define I4B_CA_EVNT_CHANSTATE 16 /* may watch b-channel states */
+#define I4B_CA_EVNT_CALLIN 32 /* may watch incoming calls */
+#define I4B_CA_EVNT_CALLOUT 64 /* may watch outgoing calls */
+#define I4B_CA_EVNT_I4B 128 /* may watch isdnd actions */
+
+/*
+ * General layout of a command packet. All commands have this common
+ * prefix. It is prepared by the macro I4B_PREP_CMD (s.b.)
+ */
+#define I4B_MON_CMD 0 /* 2 byte: command code */
+#define I4B_MON_CMD_LEN 2 /* 2 byte: packet length */
+#define I4B_MON_CMD_HDR 4 /* size of header */
+
+/*
+ * Currently events look the same as commands. We do not make
+ * any guarantee this will remain the same, so a different set
+ * of macros is used when describing events. Events are prepared
+ * by I4B_PREP_EVNT (s.b.)
+ */
+#define I4B_MON_EVNT 0 /* 2 byte: event code */
+#define I4B_MON_EVNT_LEN 2 /* 2 byte: packet length */
+#define I4B_MON_EVNT_HDR 4 /* size of header */
+
+/* Initial data send by daemon after connection is established */
+#define I4B_MON_IDATA_SIZE I4B_MON_EVNT_HDR+10
+#define I4B_MON_IDATA_CODE 0 /* event code */
+#define I4B_MON_IDATA_VERSMAJOR I4B_MON_EVNT_HDR+0 /* 2 byte: isdnd major version */
+#define I4B_MON_IDATA_VERSMINOR I4B_MON_EVNT_HDR+2 /* 2 byte: isdnd minor version */
+#define I4B_MON_IDATA_NUMCTRL I4B_MON_EVNT_HDR+4 /* 2 byte: number of controllers */
+#define I4B_MON_IDATA_CLACCESS I4B_MON_EVNT_HDR+6 /* 4 byte: client rights */
+
+/* followed by this for every controller */
+#define I4B_MON_ICTRL_SIZE I4B_MON_EVNT_HDR+I4B_MAX_MON_STRING+8
+#define I4B_MON_ICTRL_CODE 1 /* event code */
+#define I4B_MON_ICTRL_NAME I4B_MON_EVNT_HDR+0 /* string: name of controller */
+#define I4B_MON_ICTRL_BUSID I4B_MON_EVNT_HDR+I4B_MAX_MON_STRING+0 /* 2 byte: isdn bus id (reservered) */
+#define I4B_MON_ICTRL_FLAGS I4B_MON_EVNT_HDR+I4B_MAX_MON_STRING+2 /* 4 byte: controller flags (not yet defined) */
+#define I4B_MON_ICTRL_NCHAN I4B_MON_EVNT_HDR+I4B_MAX_MON_STRING+6 /* 2 byte: number of b channels on this controller */
+
+/* The client sets it's protocol version and event mask (usualy once after
+ * connection establishement) */
+#define I4B_MON_CCMD_SETMASK 0x7e /* command code */
+#define I4B_MON_ICLIENT_SIZE I4B_MON_CMD_HDR+8
+#define I4B_MON_ICLIENT_VERMAJOR I4B_MON_CMD_HDR+0 /* 2 byte: protocol major version (always 0 for now) */
+#define I4B_MON_ICLIENT_VERMINOR I4B_MON_CMD_HDR+2 /* 2 byte: protocol minor version (always 0 for now) */
+#define I4B_MON_ICLIENT_EVENTS I4B_MON_CMD_HDR+4 /* 4 byte: client event mask */
+
+/* The client requests a list of monitor rights */
+#define I4B_MON_DUMPRIGHTS_CODE 1
+#define I4B_MON_DUMPRIGHTS_SIZE I4B_MON_CMD_HDR /* no parameters */
+
+/* in response to a I4B_MON_DUMPRIGHTS_CODE command, the daemon sends
+ * this event: */
+#define I4B_MON_DRINI_CODE 2 /* event code */
+#define I4B_MON_DRINI_SIZE I4B_MON_EVNT_HDR+2 /* size of packet */
+#define I4B_MON_DRINI_COUNT I4B_MON_EVNT_HDR+0 /* 2 byte: number of records */
+
+/* followed by this for each record anounced above */
+#define I4B_MON_DR_CODE 3
+#define I4B_MON_DR_SIZE I4B_MON_EVNT_HDR+13
+#define I4B_MON_DR_RIGHTS I4B_MON_EVNT_HDR+0 /* 4 byte: rights mask */
+#define I4B_MON_DR_NET I4B_MON_EVNT_HDR+4 /* 4 byte: network address */
+#define I4B_MON_DR_MASK I4B_MON_EVNT_HDR+8 /* 4 byte: network mask */
+#define I4B_MON_DR_LOCAL I4B_MON_EVNT_HDR+12 /* 1 byte: non-zero if local socket */
+
+/* The client requests a list of monitor connections */
+#define I4B_MON_DUMPMCONS_CODE 2
+#define I4B_MON_DUMPMCONS_SIZE I4B_MON_CMD_HDR /* no parameters */
+
+/* in response to a I4B_MON_DUMPMCONS_CODE command, the daemon sends
+ * this event: */
+#define I4B_MON_DCINI_CODE 4 /* event code */
+#define I4B_MON_DCINI_SIZE I4B_MON_EVNT_HDR+2 /* size of packet */
+#define I4B_MON_DCINI_COUNT I4B_MON_EVNT_HDR+0 /* 2 byte: number of records */
+
+/* followed by this for each record anounced above */
+#define I4B_MON_DC_CODE 5
+#define I4B_MON_DC_SIZE I4B_MON_EVNT_HDR+8
+#define I4B_MON_DC_RIGHTS I4B_MON_EVNT_HDR+0 /* 4 byte: rights mask */
+#define I4B_MON_DC_WHO I4B_MON_EVNT_HDR+4 /* 4 byte: network address */
+
+/* The client requests a config file rescan */
+#define I4B_MON_CFGREREAD_CODE 3
+#define I4B_MON_CFGREREAD_SIZE I4B_MON_CMD_HDR /* no parameters */
+
+/* The client requests to hangup a connection */
+#define I4B_MON_HANGUP_CODE 4
+#define I4B_MON_HANGUP_SIZE I4B_MON_CMD_HDR+4
+#define I4B_MON_HANGUP_CHANNEL I4B_MON_CMD_HDR+0 /* channel to drop */
+
+/* The daemon sends a logfile event */
+#define I4B_MON_LOGEVNT_CODE 6
+#define I4B_MON_LOGEVNT_SIZE I4B_MON_EVNT_HDR+8+2*I4B_MAX_MON_STRING
+#define I4B_MON_LOGEVNT_TSTAMP I4B_MON_EVNT_HDR+0 /* 4 byte: timestamp */
+#define I4B_MON_LOGEVNT_PRIO I4B_MON_EVNT_HDR+4 /* 4 byte: syslog priority */
+#define I4B_MON_LOGEVNT_WHAT I4B_MON_EVNT_HDR+8 /* followed by 2 strings: 'what' and 'message' */
+#define I4B_MON_LOGEVNT_MSG I4B_MON_EVNT_HDR+8+I4B_MAX_MON_STRING
+
+/* The daemon sends a charge event */
+#define I4B_MON_CHRG_CODE 7
+#define I4B_MON_CHRG_SIZE I4B_MON_EVNT_HDR+16
+#define I4B_MON_CHRG_TSTAMP I4B_MON_EVNT_HDR+0 /* 4 byte: timestamp */
+#define I4B_MON_CHRG_CHANNEL I4B_MON_EVNT_HDR+4 /* 4 byte: channel charged */
+#define I4B_MON_CHRG_UNITS I4B_MON_EVNT_HDR+8 /* 4 byte: new charge value */
+#define I4B_MON_CHRG_ESTIMATED I4B_MON_EVNT_HDR+12 /* 4 byte: 0 = charge by network, 1 = calculated estimate */
+
+/* The daemon sends a connect event */
+#define I4B_MON_CONNECT_CODE 8
+#define I4B_MON_CONNECT_SIZE I4B_MON_EVNT_HDR+12+4*I4B_MAX_MON_STRING
+#define I4B_MON_CONNECT_TSTAMP I4B_MON_EVNT_HDR+0 /* 4 byte: time stamp */
+#define I4B_MON_CONNECT_DIR I4B_MON_EVNT_HDR+4 /* 4 byte: direction (0 = incoming, 1 = outgoing) */
+#define I4B_MON_CONNECT_CHANNEL I4B_MON_EVNT_HDR+8 /* 4 byte: channel connected */
+#define I4B_MON_CONNECT_CFGNAME I4B_MON_EVNT_HDR+12 /* name of config entry */
+#define I4B_MON_CONNECT_DEVNAME I4B_MON_EVNT_HDR+12+I4B_MAX_MON_STRING /* name of device used for connection */
+#define I4B_MON_CONNECT_REMPHONE I4B_MON_EVNT_HDR+12+2*I4B_MAX_MON_STRING /* remote phone no. */
+#define I4B_MON_CONNECT_LOCPHONE I4B_MON_EVNT_HDR+12+3*I4B_MAX_MON_STRING /* local phone no. */
+
+/* The daemon sends a disconnect event */
+#define I4B_MON_DISCONNECT_CODE 9
+#define I4B_MON_DISCONNECT_SIZE I4B_MON_EVNT_HDR+8
+#define I4B_MON_DISCONNECT_TSTAMP I4B_MON_EVNT_HDR+0 /* 4 byte: time stamp */
+#define I4B_MON_DISCONNECT_CHANNEL I4B_MON_EVNT_HDR+4 /* 4 byte: channel disconnected */
+
+/* The daemon sends an up/down event */
+#define I4B_MON_UPDOWN_CODE 10
+#define I4B_MON_UPDOWN_SIZE I4B_MON_EVNT_HDR+12
+#define I4B_MON_UPDOWN_TSTAMP I4B_MON_EVNT_HDR+0 /* 4 byte: time stamp */
+#define I4B_MON_UPDOWN_CHANNEL I4B_MON_EVNT_HDR+4 /* 4 byte: channel disconnected */
+#define I4B_MON_UPDOWN_ISUP I4B_MON_EVNT_HDR+8 /* 4 byte: interface is up */
+
+/* macros for setup/decoding of protocol packets */
+
+/* clear a record */
+#define I4B_CLEAR(r) memset(&(r), 0, sizeof(r));
+
+/* prepare a record as event or command */
+#define I4B_PREP_EVNT(r, e) { \
+ I4B_CLEAR(r); \
+ I4B_PUT_2B(r, I4B_MON_EVNT, e); \
+ I4B_PUT_2B(r, I4B_MON_EVNT_LEN, sizeof(r)); \
+}
+#define I4B_PREP_CMD(r, c) { \
+ I4B_CLEAR(r); \
+ I4B_PUT_2B(r, I4B_MON_CMD, c); \
+ I4B_PUT_2B(r, I4B_MON_CMD_LEN, sizeof(r)); \
+}
+
+/* put 1, 2 or 4 bytes in network byte order into a record at offset off */
+#define I4B_PUT_1B(r, off, val) { ((BYTE*)(r))[off] = (val) & 0x00ff; }
+#define I4B_PUT_2B(r, off, val) { I4B_PUT_1B(r, off, val >> 8); I4B_PUT_1B(r, off+1, val); }
+#define I4B_PUT_4B(r, off, val) { I4B_PUT_1B(r, off, val >> 24); I4B_PUT_1B(r, off+1, val >> 16); I4B_PUT_1B(r, off+2, val >> 8); I4B_PUT_1B(r, off+3, val); }
+
+/* get 1, 2 or 4 bytes in network byte order from a record at offset off */
+#define I4B_GET_1B(r, off) (((BYTE*)(r))[off])
+#define I4B_GET_2B(r, off) ((((BYTE*)(r))[off]) << 8) | (((BYTE*)(r))[off+1])
+#define I4B_GET_4B(r, off) ((((BYTE*)(r))[off]) << 24) | ((((BYTE*)(r))[off+1]) << 16) | ((((BYTE*)(r))[off+2]) << 8) | (((BYTE*)(r))[off+3])
+
+/* put a string into recor r at offset off, make sure it's not to long
+ * and proper terminate it */
+#define I4B_PUT_STR(r, off, str) { \
+ strncpy(r+off, str, I4B_MAX_MON_STRING); \
+ r[off+I4B_MAX_MON_STRING-1] = (BYTE)0; }
+
+#endif /* MONITOR_H */
+
diff --git a/usr.sbin/i4b/isdntel/Makefile b/usr.sbin/i4b/isdntel/Makefile
new file mode 100644
index 0000000..c44fc80
--- /dev/null
+++ b/usr.sbin/i4b/isdntel/Makefile
@@ -0,0 +1,6 @@
+PROG = isdntel
+SRCS = main.c display.c files.c alias.c
+LDADD += -lncurses
+MAN8 = isdntel.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/i4b/isdntel/alias.c b/usr.sbin/i4b/isdntel/alias.c
new file mode 100644
index 0000000..fa02ea9
--- /dev/null
+++ b/usr.sbin/i4b/isdntel/alias.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * isdntel - isdn4bsd telephone answering machine support
+ * ======================================================
+ *
+ * $Id: alias.c,v 1.5 1998/12/05 18:03:51 hm Exp $
+ *
+ * last edit-date: [Sat Dec 5 18:15:02 1998]
+ *
+ *----------------------------------------------------------------------------*/
+
+#include "defs.h"
+#include "alias.h"
+
+static struct alias *firsta = NULL;
+
+#define MAXBUFSZ 256
+
+/*---------------------------------------------------------------------------*
+ * read in and init aliases
+ *---------------------------------------------------------------------------*/
+void
+init_alias(char *filename)
+{
+ FILE *fp;
+ char buffer[MAXBUFSZ + 1];
+ char number[MAXBUFSZ + 1];
+ char name[MAXBUFSZ + 1];
+ char *s, *d;
+ struct alias *newa = NULL;
+ struct alias *lasta = NULL;
+
+ if((fp = fopen(filename, "r")) == NULL)
+ fatal("cannot open aliasfile %s!", filename);
+
+ while((fgets(buffer, MAXBUFSZ, fp)) != NULL)
+ {
+ if(buffer[0] == '#' || buffer[0] == ' ' ||
+ buffer[0] == '\t' || buffer[0] == '\n')
+ {
+ continue;
+ }
+
+ s = buffer;
+ d = number;
+
+ while(*s && (isdigit(*s)))
+ *d++ = *s++;
+
+ *d = '\0';
+
+ while(*s && (isspace(*s)))
+ s++;
+
+ d = name;
+
+ while(*s && (isprint(*s)))
+ *d++ = *s++;
+
+ *d = '\0';
+
+ if((strlen(number) > 1) && (strlen(name) > 1))
+ {
+ if((newa = (struct alias *) malloc(sizeof(struct alias))) == NULL)
+ fatal("malloc failed for struct alias");
+ if((newa->number = (char *) malloc(strlen(number)+1)) == NULL)
+ fatal("malloc failed for number alias");
+ if((newa->name = (char *) malloc(strlen(name)+1)) == NULL)
+ fatal("malloc failed for name alias");
+ strcpy(newa->name, name);
+ strcpy(newa->number, number);
+ newa->next = NULL;
+
+ if(firsta == NULL)
+ {
+ firsta = newa;
+ }
+ else
+ {
+ lasta->next = newa;
+ }
+ lasta = newa;
+ }
+ }
+ fclose(fp);
+}
+
+/*---------------------------------------------------------------------------*
+ * read in and init aliases
+ *---------------------------------------------------------------------------*/
+char *
+get_alias(char *number)
+{
+ struct alias *ca = NULL;
+
+ if(firsta == NULL)
+ return(NULL);
+
+ ca = firsta;
+
+ for(;;)
+ {
+ if(strlen(number) == strlen(ca->number))
+ {
+ if(!(strcmp(number, ca->number)))
+ return(ca->name);
+ }
+ if(ca->next == NULL)
+ break;
+ ca = ca->next;
+ }
+ return(NULL);
+}
+
+/* EOF */
diff --git a/usr.sbin/i4b/isdntel/alias.h b/usr.sbin/i4b/isdntel/alias.h
new file mode 100644
index 0000000..98b91da
--- /dev/null
+++ b/usr.sbin/i4b/isdntel/alias.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * isdn4bsd common alias file handling header
+ * ==========================================
+ *
+ * $Id: alias.h,v 1.3 1998/12/05 18:03:52 hm Exp $
+ *
+ * last edit-date: [Sat Dec 5 18:15:13 1998]
+ *
+ *----------------------------------------------------------------------------*/
+
+#ifndef _ALIAS_H_
+#define _ALIAS_H_
+
+#define ALIASFILE "/etc/isdn/isdntel.alias"
+
+struct alias {
+ char *number; /* telephone number string */
+ char *name; /* name string */
+ struct alias *next; /* ptr to next alias */
+};
+
+#endif /* _ALIAS_H_ */
+
+/* EOF */
diff --git a/usr.sbin/i4b/isdntel/defs.h b/usr.sbin/i4b/isdntel/defs.h
new file mode 100644
index 0000000..e9233c3
--- /dev/null
+++ b/usr.sbin/i4b/isdntel/defs.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * isdntel - isdn4bsd telephone answering support
+ * ==============================================
+ *
+ * $Id: defs.h,v 1.6 1998/12/05 18:03:53 hm Exp $
+ *
+ * last edit-date: [Sat Dec 5 18:15:26 1998]
+ *
+ *----------------------------------------------------------------------------*/
+
+#include <ncurses.h>
+#include <stdio.h>
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <sys/time.h>
+#if defined(__FreeBSD__) && __FreeBSD__ >= 3
+#include <dirent.h>
+#else
+#include <sys/dir.h>
+#endif
+#include <sys/param.h>
+
+#define VERSION "1" /* version number */
+#define REL "11" /* release number */
+
+#define GOOD 0
+#define ERROR (-1)
+#define WARNING (-2)
+
+#define SPOOLDIR "/var/isdn"
+#define PLAYCMD "cat %s | alaw2ulaw >/dev/audio"
+
+/* reread timeout in seconds */
+
+#define REREADTIMEOUT 60
+
+/* window dimensions */
+
+#define START_O 3 /* main window start */
+
+#define DAT_POS 0
+#define TIM_POS (DAT_POS+10)
+#define DST_POS (TIM_POS+8)
+#define SRC_POS (DST_POS+17)
+#define ALI_POS (SRC_POS+17)
+#define SEC_POS (ALI_POS+21)
+#define LAST_POS (SEC_POS+5)
+
+/* fullscreen mode menu window */
+
+#define WMITEMS 5 /* no of items */
+#define WMENU_LEN 18 /* window width */
+#define WMENU_HGT (WMITEMS+4) /* window height */
+#define WMENU_TITLE "Command"
+#define WMENU_POSLN 8 /* window position: lines */
+#define WMENU_POSCO 20 /* window position: columns */
+
+#define CR 0x0d
+#define LF 0x0a
+#define TAB 0x09
+#define CNTRL_D 0x04
+#define CNTRL_L 0x0c
+
+struct onefile {
+ char *fname; /* filename */
+ char *date;
+ char *time;
+ char *srcnumber;
+ char *dstnumber;
+ char *seconds;
+ char *alias;
+ int len;
+ struct onefile *next; /* ptr to next entry */
+ struct onefile *prev; /* prt to previous entry */
+};
+
+#ifdef MAIN
+
+int curses_ready = 0; /* flag, curses display is initialized */
+
+struct onefile *cur_file = NULL;/* the CURRENT filename */
+struct onefile *first = NULL; /* init dir-list head-ptr */
+struct onefile *last = NULL; /* init dir-list tail-ptr */
+
+WINDOW *main_w; /* curses main window pointer */
+
+int nofiles = 0;
+int cur_pos = 0;
+
+char *spooldir = SPOOLDIR;
+char *playstring = PLAYCMD;
+
+#else
+
+extern int curses_ready;
+
+extern struct onefile *cur_file;
+extern struct onefile *first;
+extern struct onefile *last;
+
+extern WINDOW *main_w;
+
+extern int nofiles;
+extern int cur_pos;
+
+extern char *spooldir;
+extern char *playstring;
+
+#endif
+
+extern void init_alias( char *filename );
+extern void init_files( int inipos );
+extern void init_screen ( void );
+extern void do_menu ( void );
+extern int fill_list( void );
+extern char *get_alias( char *number );
+extern int main ( int argc, char **argv );
+extern void do_quit ( int exitval );
+extern void fatal ( char *fmt, ... );
+extern void error ( char *fmt, ... );
+extern void play ( struct onefile * );
+extern void delete ( struct onefile * );
+extern void reread( void );
+
+/* EOF */
diff --git a/usr.sbin/i4b/isdntel/display.c b/usr.sbin/i4b/isdntel/display.c
new file mode 100644
index 0000000..1cc0034
--- /dev/null
+++ b/usr.sbin/i4b/isdntel/display.c
@@ -0,0 +1,252 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * isdntel - isdn4bsd telephone answering machine support
+ * ======================================================
+ *
+ * $Id: display.c,v 1.4 1998/12/05 18:03:55 hm Exp $
+ *
+ * last edit-date: [Sat Dec 5 18:15:40 1998]
+ *
+ *----------------------------------------------------------------------------*/
+
+#include "defs.h"
+
+static char *helpstr = "Enter Control-D to exit program or RETURN for command window";
+
+/*---------------------------------------------------------------------------*
+ * init curses fullscreen display
+ *---------------------------------------------------------------------------*/
+void
+init_screen(void)
+{
+ char buffer[512];
+
+ initscr(); /* curses init */
+
+ if((COLS < 80) || (LINES < 24))
+ fatal(0, "ERROR, minimal screensize must be 80x24, is %dx%d, terminating!", COLS, LINES);
+
+
+ if((main_w = newwin(LINES-START_O-2, COLS, START_O, 0)) == NULL)
+ fatal("ERROR, curses init main window, terminating!");
+
+ raw(); /* raw input */
+ noecho(); /* do not echo input */
+ keypad(stdscr, TRUE); /* use special keys */
+ keypad(main_w, TRUE); /* use special keys */
+ scrollok(main_w, TRUE);
+
+ sprintf(buffer, " isdntel %s.%s ", VERSION, REL);
+
+ move(0, 0);
+ standout();
+ hline(ACS_HLINE, 5);
+ move(0, 5);
+ addstr(buffer);
+ move(0, 5 + strlen(buffer));
+ hline(ACS_HLINE, 256);
+ standend();
+
+ move(1, 0);
+ addstr("Date Time Called Party Calling Party Alias Length");
+ /* 31.12.96 16:45:12 1234567890123456 1234567890123456 12345678901234567890 123456 */
+
+ move(2, 0);
+ hline(ACS_HLINE, 256);
+
+ move(LINES-2, 0);
+ hline(ACS_HLINE, 256);
+
+ mvaddstr(LINES-1, (COLS / 2) - (strlen(helpstr) / 2), helpstr);
+
+ refresh();
+
+ wrefresh(main_w);
+
+ curses_ready = 1;
+}
+
+/*---------------------------------------------------------------------------*
+ * curses menu for fullscreen command mode
+ *---------------------------------------------------------------------------*/
+void
+do_menu(void)
+{
+ static char *menu[WMITEMS] =
+ {
+ "Play File",
+#define PLAY 0
+ "Delete File",
+#define DELETE 1
+ "Re-Read Spool",
+#define REREAD 2
+ "Refresh Screen",
+#define REFRESH 3
+ "Exit Program",
+#define EXIT 4
+ };
+
+ WINDOW *menu_w;
+ int c;
+ int mpos;
+
+ /* create a new window in the lower screen area */
+
+ if((menu_w = newwin(WMENU_HGT, WMENU_LEN, WMENU_POSLN, WMENU_POSCO )) == NULL)
+ return;
+
+ keypad(menu_w, TRUE); /* use special keys */
+
+ /* draw border around the window */
+
+ box(menu_w, 0, 0);
+
+ /* add a title */
+
+ wstandout(menu_w);
+ mvwaddstr(menu_w, 0, (WMENU_LEN / 2) - (strlen(WMENU_TITLE) / 2), WMENU_TITLE);
+ wstandend(menu_w);
+
+ /* fill the window with the menu options */
+
+ for(mpos=0; mpos <= (WMITEMS-1); mpos++)
+ mvwaddstr(menu_w, mpos + 2, 2, menu[mpos]);
+
+ /* highlight the first menu option */
+
+ mpos = 0;
+ wstandout(menu_w);
+ mvwaddstr(menu_w, mpos + 2, 2, menu[mpos]);
+ wstandend(menu_w);
+
+ /* input loop */
+
+ for(;;)
+ {
+ wrefresh(menu_w);
+
+ c = wgetch(menu_w);
+
+ switch(c)
+ {
+ case TAB:
+ case KEY_DOWN: /* down-move cursor */
+ case ' ':
+ mvwaddstr(menu_w, mpos + 2, 2, menu[mpos]);
+ mpos++;
+ if(mpos >= WMITEMS)
+ mpos = 0;
+ wstandout(menu_w);
+ mvwaddstr(menu_w, mpos + 2, 2, menu[mpos]);
+ wstandend(menu_w);
+ break;
+
+ case KEY_UP: /* up-move cursor */
+ mvwaddstr(menu_w, mpos + 2, 2, menu[mpos]);
+ if(mpos)
+ mpos--;
+ else
+ mpos = WMITEMS-1;
+ wstandout(menu_w);
+ mvwaddstr(menu_w, mpos + 2, 2, menu[mpos]);
+ wstandend(menu_w);
+ break;
+
+ case 'R':
+ case 'r':
+ wrefresh(curscr);
+ goto mexit;
+
+ case 'E':
+ case 'e':
+ case 'Q':
+ case 'q':
+ case 'X':
+ case 'x':
+ do_quit(0);
+ goto mexit;
+ break;
+
+ case 'P':
+ case 'p':
+ play(cur_file);
+ goto mexit;
+ break;
+
+ case 'D':
+ case 'd':
+ delete(cur_file);
+ goto mexit;
+ break;
+
+ case CR:
+ case LF: /* exec highlighted option */
+#ifdef KEY_ENTER
+ case KEY_ENTER:
+#endif
+ switch(mpos)
+ {
+ case PLAY:
+ play(cur_file);
+ goto mexit;
+ break;
+ case DELETE:
+ delete(cur_file);
+ goto mexit;
+ break;
+ case REREAD:
+ reread();
+ goto mexit;
+ break;
+ case REFRESH:
+ wrefresh(curscr);
+ break;
+ case EXIT:
+ do_quit(0);
+ break;
+ }
+ goto mexit;
+ break;
+
+ default:
+ goto mexit;
+ break;
+ }
+ }
+
+mexit:
+ /* delete the menu window */
+
+ delwin(menu_w);
+
+ /* re-display the original lower window contents */
+
+ touchwin(main_w);
+ wrefresh(main_w);
+}
+
+/* EOF */
diff --git a/usr.sbin/i4b/isdntel/files.c b/usr.sbin/i4b/isdntel/files.c
new file mode 100644
index 0000000..ea153f5
--- /dev/null
+++ b/usr.sbin/i4b/isdntel/files.c
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * isdntel - isdn4bsd telephone answering machine support
+ * ======================================================
+ *
+ * $Id: files.c,v 1.6 1998/12/05 18:03:56 hm Exp $
+ *
+ * last edit-date: [Sat Dec 5 18:15:57 1998]
+ *
+ *----------------------------------------------------------------------------*/
+
+#include "defs.h"
+
+/*---------------------------------------------------------------------------*
+ * create a doubly linked list in sorted order, return pointer to new
+ * first element of list
+ *---------------------------------------------------------------------------*/
+struct onefile *store
+ (register struct onefile *new, /* new entry to store into list */
+ register struct onefile *top) /* current first entry in list */
+{
+ register struct onefile *old, *p;
+
+ if (last == NULL) /* enter very first element ? */
+ {
+ new->next = NULL;
+ new->prev = NULL;
+ last = new; /* init last */
+ return (new); /* return new first */
+ }
+ p = top; /* p = old first element */
+ old = NULL;
+ while (p)
+ {
+ if ((strcmp(p->fname, new->fname)) < 0) /* current less new ? */
+ {
+ old = p;
+ p = p->next;
+ }
+ else
+ { /* current >= new */
+
+ if (p->prev)
+ {
+ p->prev->next = new;
+ new->next = p;
+ new->prev = p->prev;
+ p->prev = new;
+ return (top);
+ }
+ new->next = p;
+ new->prev = NULL;
+ p->prev = new;
+ return (new);
+ }
+ }
+ old->next = new;
+ new->next = NULL;
+ new->prev = old;
+ last = new;
+ return (first);
+}
+
+/*---------------------------------------------------------------------------*
+ * read current directory and build up a doubly linked sorted list
+ *---------------------------------------------------------------------------*/
+int
+fill_list(void)
+{
+#if defined(__FreeBSD__) && __FreeBSD__ >= 3
+ register struct dirent *dp;
+#else
+ register struct direct *dp;
+#endif
+ register struct onefile *new_entry;
+ register DIR *dirp;
+ int flcnt = 0;
+ char tmp[80];
+ char *s, *d;
+
+ if ((dirp = opendir(spooldir)) == NULL)
+ fatal("cannot open spooldirectory %s!\n", spooldir);
+
+ for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp))
+ {
+ if(!isdigit(*(dp->d_name)))
+ continue;
+
+ if ((new_entry = (struct onefile *) malloc(sizeof(struct onefile))) == NULL)
+ {
+ fatal("files.c, fill_list(): structure onefile malloc failed");
+ }
+
+ /* alloc filename memory and copy name into it */
+
+ if ((new_entry->fname = (char *) malloc(strlen(dp->d_name) + 1)) == NULL)
+ {
+ fatal("files.c, fill_list(): malloc filename string memory failed");
+ }
+
+ strcpy(new_entry->fname, dp->d_name);
+
+ /* fill in remaining fields from filename */
+
+ tmp[0] = dp->d_name[4]; /* day msb */
+ tmp[1] = dp->d_name[5]; /* day lsb */
+ tmp[2] = '.';
+ tmp[3] = dp->d_name[2]; /* month msb */
+ tmp[4] = dp->d_name[3]; /* month lsb */
+ tmp[5] = '.';
+ tmp[6] = dp->d_name[0]; /* year msb */
+ tmp[7] = dp->d_name[1]; /* year lsb */
+ tmp[8] = '\0';
+
+ if((new_entry->date = (char *) malloc(strlen(tmp) + 1)) == NULL)
+ {
+ fatal("files.c, fill_list(): malloc date string memory failed");
+ }
+
+ strcpy(new_entry->date, tmp);
+
+ tmp[0] = dp->d_name[6]; /* hour msb */
+ tmp[1] = dp->d_name[7]; /* hour lsb */
+ tmp[2] = ':';
+ tmp[3] = dp->d_name[8]; /* minute msb */
+ tmp[4] = dp->d_name[9]; /* minute lsb */
+ tmp[5] = ':';
+ tmp[6] = dp->d_name[10]; /* second msb */
+ tmp[7] = dp->d_name[11]; /* second lsb */
+ tmp[8] = '\0';
+
+ if((new_entry->time = (char *) malloc(strlen(tmp) + 1)) == NULL)
+ {
+ fatal("files.c, fill_list(): malloc time string memory failed");
+ }
+
+ strcpy(new_entry->time, tmp);
+
+ /* destination number */
+
+ s = &dp->d_name[13];
+ d = &tmp[0];
+
+ while(*s && (*s != '-'))
+ *d++ = *s++;
+
+ *d = '\0';
+
+ if((new_entry->dstnumber = (char *) malloc(strlen(tmp) + 1)) == NULL)
+ {
+ fatal("files.c, fill_list(): malloc dstnumber string memory failed");
+ }
+
+ strcpy(new_entry->dstnumber, tmp);
+
+ /* source number */
+
+ s++;
+ d = &tmp[0];
+
+ while(*s && (*s != '-'))
+ *d++ = *s++;
+
+ *d = '\0';
+
+ if((new_entry->srcnumber = (char *) malloc(strlen(tmp) + 1)) == NULL)
+ {
+ fatal("files.c, fill_list(): malloc srcnumber string memory failed");
+ }
+
+ strcpy(new_entry->srcnumber, tmp);
+
+ /* length in seconds */
+
+ s++;
+ d = &tmp[0];
+
+ while(*s && (*s != '-'))
+ *d++ = *s++;
+
+ *d = '\0';
+
+ if((new_entry->seconds = (char *) malloc(strlen(tmp) + 1)) == NULL)
+ {
+ fatal("files.c, fill_list(): malloc seconds string memory failed");
+ }
+
+ strcpy(new_entry->seconds, tmp);
+
+ /* search for alias and add if found */
+
+ new_entry->alias = get_alias(new_entry->srcnumber);
+
+ /* sort entry into linked list */
+
+ first = store(new_entry, first);
+
+ flcnt++; /* increment file count */
+ }
+ closedir(dirp); /* close current dir */
+ return(flcnt); /* ok return */
+}
+
+/*---------------------------------------------------------------------------*
+ * free the current malloc'ed list
+ *---------------------------------------------------------------------------*/
+void
+free_list(void)
+{
+ register struct onefile *dir;
+ register struct onefile *tmp;
+
+ dir = first; /* start of linked list */
+
+ while (dir) /* free all */
+ {
+ tmp = dir->next; /* save ptr to next entry */
+ free(dir->fname); /* free filename space */
+ free(dir->date);
+ free(dir->time);
+ free(dir->srcnumber);
+ free(dir->dstnumber);
+ free(dir->seconds);
+ free(dir); /* free struct space */
+ dir = tmp; /* ptr = ptr to next entry */
+ }
+ first = NULL; /* first ptr = NULL */
+ last = NULL; /* last ptr = NULL */
+}
+
+/*---------------------------------------------------------------------------*
+ * delete a file
+ *---------------------------------------------------------------------------*/
+void
+delete(struct onefile *this)
+{
+ char buffer[MAXPATHLEN+1];
+
+ if(this == NULL)
+ return;
+
+ sprintf(buffer, "%s", this->fname);
+
+ unlink(buffer);
+
+ free_list();
+
+ wclear(main_w);
+
+ init_files(cur_pos);
+}
+
+/*---------------------------------------------------------------------------*
+ * reread the spool directory
+ *---------------------------------------------------------------------------*/
+void
+reread(void)
+{
+ free_list();
+
+ wclear(main_w);
+
+ init_files(cur_pos);
+}
+
+/*---------------------------------------------------------------------------*
+ * play a file
+ *---------------------------------------------------------------------------*/
+void
+play(struct onefile *this)
+{
+ char buffer[MAXPATHLEN+1];
+
+ if(this == NULL)
+ return;
+
+ sprintf(buffer, playstring, this->fname);
+
+ system(buffer);
+}
+
+/*---------------------------------- EOF -------------------------------------*/
diff --git a/usr.sbin/i4b/isdntel/isdntel.8 b/usr.sbin/i4b/isdntel/isdntel.8
new file mode 100644
index 0000000..d87c848
--- /dev/null
+++ b/usr.sbin/i4b/isdntel/isdntel.8
@@ -0,0 +1,94 @@
+.\"
+.\" Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" last edit-date: [Sat Dec 5 18:16:19 1998]
+.\"
+.\" $Id: isdntel.8,v 1.6 1998/12/05 18:03:58 hm Exp $
+.\"
+.Dd July 11, 1998
+.Dt isdntel 8
+.Sh NAME
+.Nm isdntel
+.Nd isdn4bsd telephone answering management utility
+.Sh SYNOPSIS
+.Nm isdntel
+.Op Fl a Ar aliasfile
+.Op Fl d Ar spooldir
+.Op Fl p Ar playcommand
+.Op Fl t Ar timeout
+.Sh DESCRIPTION
+.Nm
+is used to provide an "answering machine" functionality for incoming
+telephone voice messages.
+.Pp
+The following options are supported:
+.Bl -tag -width Ds
+.It Fl a
+Use
+.Ar aliasfile
+as the pathname for an aliasfile containing aliases for phone numbers. The
+default path is
+.Em /etc/isdn/isdntel.alias .
+The format of an alias entry is the number string followed by one or more
+spaces or tabs. The rest of the line is taken as the alias string. Comments
+are introduced by a leading blank, tab or "#" character.
+.It Fl d
+Use
+.Ar spooldir
+as the directory where the incoming voice messages are stored by the
+"answ" script called by
+.Xr isdnd 8 .
+This defaults to the directory
+.Em /var/isdn .
+The format of a voice message filename is:
+.Pp
+.Dl YYMMDDhhmmss-dest_number-source_number-length_in_secs
+.It Fl p
+Use
+.Ar playcommand
+as the command string to execute for playing a voice message to some audio
+output facility. The characters
+.Em %s
+are replaced by the currently selected filename. The default string is
+.Em cat %s | alaw2ulaw >/dev/audio
+.It Fl t
+The value for
+.Ar timeout
+specifies the time in seconds the program rereads the spool directory
+when there is no keyboard activity.
+.El
+.Pp
+The screen output should be obvious. If in doubt, consult the source.
+.Sh SEE ALSO
+.Xr isdnd 8
+.Xr isdnd.rc 5
+.Xr i4btel 4
+
+.Sh BUGS
+Still two or more left.
+
+.Sh AUTHOR
+The
+.Nm
+utility and this manual page were written by Hellmuth Michaelis (hm@kts.org)
diff --git a/usr.sbin/i4b/isdntel/main.c b/usr.sbin/i4b/isdntel/main.c
new file mode 100644
index 0000000..fd6a3b2
--- /dev/null
+++ b/usr.sbin/i4b/isdntel/main.c
@@ -0,0 +1,395 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * isdntel - isdn4bsd telephone answering machine support
+ * ======================================================
+ *
+ * $Id: main.c,v 1.6 1998/12/05 18:03:59 hm Exp $
+ *
+ * last edit-date: [Sat Dec 5 18:16:33 1998]
+ *
+ *----------------------------------------------------------------------------*/
+
+#define MAIN
+#include "defs.h"
+#include "alias.h"
+
+static void usage( void );
+
+static int top_dis = 0;
+static int bot_dis = 0;
+static int cur_pos_scr = 0;
+
+static void makecurrent(int cur_pos, struct onefile *cur_file, int cold);
+
+/*---------------------------------------------------------------------------*
+ * program entry
+ *---------------------------------------------------------------------------*/
+int
+main(int argc, char **argv)
+{
+ int i;
+ int kchar;
+
+ char *spooldir = SPOOLDIR;
+ char *playstring = PLAYCMD;
+ char *aliasfile = ALIASFILE;
+ int rrtimeout = REREADTIMEOUT;
+
+ extern char *optarg;
+
+ while ((i = getopt(argc, argv, "a:d:p:t:?")) != EOF)
+ {
+ switch (i)
+ {
+ case 'a':
+ aliasfile = optarg;
+ break;
+
+ case 'd':
+ spooldir = optarg;
+ break;
+
+ case 'p':
+ playstring = optarg;
+ break;
+
+ case 't':
+ if(isdigit(*optarg))
+ {
+ rrtimeout = strtoul(optarg, NULL, 10);
+ }
+ else
+ {
+ usage();
+ }
+ break;
+
+ case '?':
+ default:
+ usage();
+ break;
+ }
+ }
+
+ if(rrtimeout < 10)
+ rrtimeout = 10;
+
+ if((chdir(spooldir)) != 0)
+ fatal("cannot change directory to spooldir %s!", spooldir);
+
+ init_alias(aliasfile);
+
+ init_screen();
+
+ init_files(0);
+
+ /* go into loop */
+
+ for (;;)
+ {
+ fd_set set;
+ struct timeval timeout;
+
+ FD_ZERO(&set);
+ FD_SET(STDIN_FILENO, &set);
+ timeout.tv_sec = rrtimeout;
+ timeout.tv_usec = 0;
+
+ /* if no char is available within timeout, reread spool */
+
+ if((select(STDIN_FILENO + 1, &set, NULL, NULL, &timeout)) <= 0)
+ {
+ reread();
+ continue;
+ }
+
+ kchar = wgetch(main_w); /* get char */
+
+ switch (kchar)
+ {
+ case CR:
+ case LF:
+#ifdef KEY_ENTER
+ case KEY_ENTER:
+#endif
+ do_menu();
+ break;
+
+ case KEY_UP: /* up-move cursor */
+ if(cur_file && cur_file->prev)
+ {
+ cur_file = cur_file->prev;
+ cur_pos--;
+ }
+ break;
+
+
+ case TAB:
+ case KEY_DOWN: /* down-move cursor */
+ if(cur_file && cur_file->next)
+ {
+ cur_file = cur_file->next;
+ cur_pos++;
+ }
+ break;
+
+ case KEY_HOME: /* move cursor to first dir */
+ break;
+
+ case KEY_LL: /* move cursor to last file */
+ break;
+
+ case CNTRL_D:
+ do_quit(0);
+ break;
+
+ case CNTRL_L: /* refresh */
+ touchwin(curscr);
+ wrefresh(curscr);
+ break;
+
+ }
+ makecurrent(cur_pos, cur_file, 0);
+ }
+
+ do_quit(0);
+
+ return(0);
+}
+
+/*---------------------------------------------------------------------------*
+ * handle horizontal selection bar movement
+ *---------------------------------------------------------------------------*/
+static void
+makecurrent(int cur_pos, struct onefile *cur_file, int cold)
+{
+ static int lastpos;
+ static struct onefile *lastfile;
+ char buffer[256];
+
+ /* un-higlight current horizontal bar */
+
+ if(!cold && lastfile && cur_file)
+ {
+ sprintf(buffer, "%s %s %-16s %-16s %-20s %-6s%*s",
+ lastfile->date, lastfile->time,
+ lastfile->dstnumber, lastfile->srcnumber,
+ lastfile->alias == NULL ? "-/-" : lastfile->alias,
+ lastfile->seconds,
+ COLS - LAST_POS - 2, "");
+
+ wattroff(main_w, A_REVERSE);
+ mvwprintw(main_w, lastpos, 0, "%s", buffer);
+ wattroff(main_w, A_REVERSE);
+ }
+
+ if(cur_file == NULL)
+ {
+ lastpos = cur_pos_scr;
+ lastfile = cur_file;
+ return;
+ }
+
+ /* have to scroll up or down ? */
+
+ if(cur_pos >= bot_dis)
+ {
+ /* scroll up */
+
+ wscrl(main_w, 1);
+
+ bot_dis++;
+ top_dis++;
+ cur_pos_scr = LINES-START_O-3;
+ }
+ else if(cur_pos < top_dis)
+ {
+ /* scroll down */
+
+ wscrl(main_w, -1);
+
+ bot_dis--;
+ top_dis--;
+ cur_pos_scr = 0;
+ }
+ else
+ {
+ cur_pos_scr = cur_pos - top_dis;
+ }
+
+ sprintf(buffer, "%s %s %-16s %-16s %-20s %-6s%*s",
+ cur_file->date, cur_file->time,
+ cur_file->dstnumber, cur_file->srcnumber,
+ cur_file->alias == NULL ? "-/-" : cur_file->alias,
+ cur_file->seconds,
+ COLS - LAST_POS - 2, "");
+
+ wattron(main_w, A_REVERSE);
+ mvwprintw(main_w, cur_pos_scr, 0, "%s", buffer);
+ wattroff(main_w, A_REVERSE);
+
+ lastpos = cur_pos_scr;
+ lastfile = cur_file;
+
+ wrefresh(main_w);
+}
+
+/*---------------------------------------------------------------------------*
+ * exit program
+ *---------------------------------------------------------------------------*/
+void
+do_quit(int exitval)
+{
+ move(LINES-1, 0);
+ clrtoeol();
+ refresh();
+ endwin();
+ exit(exitval);
+}
+
+/*---------------------------------------------------------------------------*
+ * usage display and exit
+ *---------------------------------------------------------------------------*/
+static void
+usage(void)
+{
+ fprintf(stderr, "\n");
+ fprintf(stderr, "isdntel - isdn telephone answering management support utility (version %s.%s)\n", VERSION, REL);
+ fprintf(stderr, " usage: isdntel -a <filename> -d <directory> -p <command> -t <timeout>\n");
+ fprintf(stderr, " -a <filename> use filename as alias file\n");
+ fprintf(stderr, " -d <directory> use directory as spool directory\n");
+ fprintf(stderr, " -p <command> specify commandline for play command\n");
+ fprintf(stderr, " -t <timeout> spool directory reread timeout in seconds\n");
+ fprintf(stderr, "\n");
+ exit(1);
+}
+
+/*---------------------------------------------------------------------------*
+ * fatal error exit
+ *---------------------------------------------------------------------------*/
+void
+fatal(char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ if(curses_ready)
+ {
+ move(LINES-1, 0);
+ clrtoeol();
+ refresh();
+ endwin();
+ }
+
+ fprintf(stderr, "\nFatal error: ");
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n\n");
+
+ va_end(ap);
+
+ exit(1);
+}
+
+/*---------------------------------------------------------------------------*
+ * error printing
+ *---------------------------------------------------------------------------*/
+void
+error(char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ if(curses_ready)
+ {
+ wprintw(main_w, "ERROR: ");
+ vwprintw(main_w, fmt, ap);
+ wprintw(main_w, "\n");
+ wrefresh(main_w);
+ }
+ else
+ {
+ fprintf(stderr, "ERROR: ");
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+ }
+
+ va_end(ap);
+}
+
+/*---------------------------------------------------------------------------*
+ * read files and fill display
+ *---------------------------------------------------------------------------*/
+void
+init_files(int inipos)
+{
+ int i;
+
+ nofiles = fill_list();
+
+ top_dis = 0;
+ bot_dis = 0;
+
+ cur_file = first;
+
+ cur_pos = 0;
+ cur_pos_scr = 0;
+
+ if(nofiles == 0)
+ return;
+
+ for(i=0; (i < nofiles) && (i < (LINES-START_O-2)); i++)
+ {
+ mvwprintw(main_w, i, 0, "%s %s", cur_file->date, cur_file->time);
+ mvwprintw(main_w, i, DST_POS, "%s", cur_file->dstnumber);
+ mvwprintw(main_w, i, SRC_POS, "%s", cur_file->srcnumber);
+ mvwprintw(main_w, i, ALI_POS,"%s", cur_file->alias == NULL ? "-/-" : cur_file->alias);
+ mvwprintw(main_w, i, SEC_POS,"%s", cur_file->seconds);
+
+ bot_dis++;
+
+ if((cur_file = cur_file->next) == NULL)
+ break;
+ }
+
+ cur_file = first;
+
+ if(inipos)
+ {
+ for(i=0; i < inipos; i++)
+ {
+ if(cur_file->next != NULL)
+ cur_file = cur_file->next;
+ else
+ break;
+ }
+ }
+ makecurrent(cur_pos, cur_file, 1);
+}
+
+/* EOF */
diff --git a/usr.sbin/i4b/isdntelctl/Makefile b/usr.sbin/i4b/isdntelctl/Makefile
new file mode 100644
index 0000000..b38f206
--- /dev/null
+++ b/usr.sbin/i4b/isdntelctl/Makefile
@@ -0,0 +1,5 @@
+PROG = isdntelctl
+SRCS = main.c
+MAN8 = isdntelctl.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/i4b/isdntelctl/isdntelctl.8 b/usr.sbin/i4b/isdntelctl/isdntelctl.8
new file mode 100644
index 0000000..2bd45d2
--- /dev/null
+++ b/usr.sbin/i4b/isdntelctl/isdntelctl.8
@@ -0,0 +1,78 @@
+.\"
+.\" Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id: isdntelctl.8,v 1.4 1998/12/14 10:31:55 hm Exp $
+.\"
+.\" last edit-date: [Mon Dec 14 11:34:51 1998]
+.\"
+.Dd December 14, 1998
+.Dt isdntelctl 8
+.Sh NAME
+.Nm isdntelctl
+.Nd control isdn4bsd telephone sound format conversion
+.Sh SYNOPSIS
+.Nm
+.Op Fl c
+.Op Fl g
+.Op Fl u Ar unit
+.Op Fl A
+.Op Fl U
+.Sh DESCRIPTION
+.Nm isdntelctl
+is part of the isdn4bsd package and is used to configure the sound format
+conversion facilities of the /dev/i4btel interfaces.
+.Pp
+The following options are available:
+.Bl -tag -width Ds
+.It Fl c
+Clear the telephone input queue.
+.It Fl g
+Get the sound format currently in use.
+.It Fl u
+Set the /dev/i4btel unit number. The default value is zero to access
+device /dev/i4btel0.
+.It Fl A
+Set sound format to A-Law.
+.It Fl U
+Set sound format to u-Law.
+.Pp
+.Sh FILES
+/dev/i4btel<n>
+
+.Sh STANDARDS
+A-Law and u-Law are specified in ITU Recommendation G.711.
+
+.Sh EXAMPLES
+The command:
+.Bd -literal -offset indent
+isdntelctl -g
+.Ed
+.Pp
+displays the currently used sound format for device /dev/i4btel0.
+
+.Sh AUTHOR
+The
+.Nm
+utility and this manpage were written by Hellmuth Michaelis. He can be
+contacted at hm@kts.org.
diff --git a/usr.sbin/i4b/isdntelctl/main.c b/usr.sbin/i4b/isdntelctl/main.c
new file mode 100644
index 0000000..4309b24
--- /dev/null
+++ b/usr.sbin/i4b/isdntelctl/main.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * isdntelctl - i4b set telephone interface options
+ * ------------------------------------------------
+ *
+ * $Id: main.c,v 1.4 1998/12/14 10:31:57 hm Exp $
+ *
+ * last edit-date: [Sat Dec 5 18:17:17 1998]
+ *
+ *---------------------------------------------------------------------------*/
+
+#include <stdio.h>
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <machine/i4b_tel_ioctl.h>
+
+static void usage ( void );
+
+#define I4BTELDEVICE "/dev/i4btel"
+
+int opt_get = 0;
+int opt_unit = 0;
+int opt_U = 0;
+int opt_A = 0;
+int opt_C = 0;
+
+/*---------------------------------------------------------------------------*
+ * program entry
+ *---------------------------------------------------------------------------*/
+int
+main(int argc, char **argv)
+{
+ int c;
+ int ret;
+ int telfd;
+ char namebuffer[128];
+
+ while ((c = getopt(argc, argv, "cgu:AU?")) != EOF)
+ {
+ switch(c)
+ {
+ case 'c':
+ opt_C = 1;
+ break;
+
+ case 'g':
+ opt_get = 1;
+ break;
+
+ case 'u':
+ opt_unit = atoi(optarg);
+ if(opt_unit < 0 || opt_unit > 9)
+ usage();
+ break;
+
+ case 'A':
+ opt_A = 1;
+ break;
+
+ case 'U':
+ opt_U = 1;
+ break;
+
+ case '?':
+ default:
+ usage();
+ break;
+ }
+ }
+
+ if(opt_get == 0 && opt_U == 0 && opt_A && opt_C == 0)
+ {
+ opt_get = 1;
+ }
+
+ if((opt_get + opt_U + opt_A + opt_C) > 1)
+ {
+ usage();
+ }
+
+ sprintf(namebuffer,"%s%d", I4BTELDEVICE, opt_unit);
+
+ if((telfd = open(namebuffer, O_RDWR)) < 0)
+ {
+ fprintf(stderr, "isdntelctl: cannot open %s: %s\n", namebuffer, strerror(errno));
+ exit(1);
+ }
+
+ if(opt_get)
+ {
+ int format;
+
+ if((ret = ioctl(telfd, I4B_TEL_GETAUDIOFMT, &format)) < 0)
+ {
+ fprintf(stderr, "ioctl I4B_TEL_GETAUDIOFMT failed: %s", strerror(errno));
+ exit(1);
+ }
+
+ if(format == CVT_NONE)
+ {
+ printf("device %s uses A-Law sound format\n", namebuffer);
+ }
+ else if(format == CVT_ALAW2ULAW)
+ {
+ printf("device %s uses u-Law sound format\n", namebuffer);
+ }
+ else
+ {
+ printf("ERROR, device %s uses unknown format %d!\n", namebuffer, format);
+ }
+ exit(0);
+ }
+
+ if(opt_A)
+ {
+ int format = CVT_NONE;
+
+ if((ret = ioctl(telfd, I4B_TEL_SETAUDIOFMT, &format)) < 0)
+ {
+ fprintf(stderr, "ioctl I4B_TEL_SETAUDIOFMT failed: %s", strerror(errno));
+ exit(1);
+ }
+ exit(0);
+ }
+
+ if(opt_U)
+ {
+ int format = CVT_ALAW2ULAW;
+
+ if((ret = ioctl(telfd, I4B_TEL_SETAUDIOFMT, &format)) < 0)
+ {
+ fprintf(stderr, "ioctl I4B_TEL_SETAUDIOFMT failed: %s", strerror(errno));
+ exit(1);
+ }
+ exit(0);
+ }
+ if(opt_C)
+ {
+ int dummy;
+ if((ret = ioctl(telfd, I4B_TEL_EMPTYINPUTQUEUE, &dummy)) < 0)
+ {
+ fprintf(stderr, "ioctl I4B_TEL_EMPTYINPUTQUEUE failed: %s", strerror(errno));
+ exit(1);
+ }
+ exit(0);
+ }
+ return(0);
+}
+
+/*---------------------------------------------------------------------------*
+ * usage display and exit
+ *---------------------------------------------------------------------------*/
+static void
+usage(void)
+{
+ fprintf(stderr, "\n");
+ fprintf(stderr, "isdntelctl - i4b telephone i/f control, compiled %s %s\n",__DATE__, __TIME__);
+ fprintf(stderr, "usage: isdndebug -e -h -g -l <layer> -m -r -s <value> -u <unit> -z -H\n");
+ fprintf(stderr, " -g get current settings\n");
+ fprintf(stderr, " -u unit specify unit number\n");
+ fprintf(stderr, " -A set interface to A-Law coding\n");
+ fprintf(stderr, " -U set interface to u-Law coding\n");
+ fprintf(stderr, " -c clear input queue\n");
+ fprintf(stderr, "\n");
+ exit(1);
+}
+
+/* EOF */
diff --git a/usr.sbin/i4b/isdntest/Makefile b/usr.sbin/i4b/isdntest/Makefile
new file mode 100644
index 0000000..c1240cc
--- /dev/null
+++ b/usr.sbin/i4b/isdntest/Makefile
@@ -0,0 +1,8 @@
+PROG = isdntest
+SRCS = main.c
+MAN8 = isdntest.8
+
+install:
+ @echo isdntest is not installed automatically
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/i4b/isdntest/isdntest.8 b/usr.sbin/i4b/isdntest/isdntest.8
new file mode 100644
index 0000000..7e03523
--- /dev/null
+++ b/usr.sbin/i4b/isdntest/isdntest.8
@@ -0,0 +1,103 @@
+.\"
+.\" Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id: isdntest.8,v 1.6 1998/12/16 13:39:47 hm Exp $
+.\"
+.\" last edit-date: [Sat Dec 5 18:17:35 1998]
+.\"
+.Dd July 9, 1998
+.Dt isdntest 8
+.Sh NAME
+.Nm isdntest
+.Nd isdn4bsd debugging and verification tool
+.Sh SYNOPSIS
+.Nm
+.Op Fl c Ar unit
+.Op Fl h
+.Op Fl i Ar number
+.Op Fl o Ar number
+.Op Fl w
+.Sh DESCRIPTION
+.Nm isdntest
+is part of the isdn4bsd package and may be used as a stimulation tool
+for debugging the isdn4bsd kernel functionality.
+.Pp
+NOTE:
+.Nm Isdntest
+must be run
+.Em instead
+of the
+.Xr isdnd 8
+daemon and can not be used while the daemon runs.
+.Pp
+The following options are available:
+.Bl -tag -width Ds
+.It Fl c
+Use controller unit number for test.
+.It Fl h
+Use HDLC as the B channel layer 1 protocol instead of no protocol.
+.It Fl i
+Use number to verify the incoming number.
+.It Fl o
+Use number as the outgoing number to dial.
+.It Fl w
+Wait for keyboard input for terminating the call.
+.El
+.Pp
+The
+.Nm
+utility is currently of not much use for end users, it is primarily a debugging
+tool for development and is part of the release in the hope, that someone
+enhances it as a real self test and setup-verification tool!
+.Pp
+.Nm Isdntest
+does almost no error checking and error recovery, so unexpected
+hangs or crashes may occur.
+
+.Sh EXAMPLES
+For the following example, it is assumed that a machine with isdn4bsd
+installed is connected to an S0 bus and that one of the valid MSN's (MSN = Multiple Subscriber Number
+= telephone number) on this bus is
+.Em 42 .
+The
+.Xr isdnd 8
+.Em must
+not currently running on that machine! Executing:
+.Bd -literal -offset indent
+isdntest -i 42 -o 42
+.Ed
+.Pp
+will setup an outgoing call from that machine to itself, connect to itself
+and disconnect after 5 seconds.
+.Nm Isdntest
+has to be finished by the user by entering Control-C.
+.Pp
+.Sh FILES
+/dev/i4b
+
+.Sh AUTHOR
+The
+.Nm
+utility and this manpage were written by Hellmuth Michaelis. He can be
+contacted at hm@kts.org.
diff --git a/usr.sbin/i4b/isdntest/main.c b/usr.sbin/i4b/isdntest/main.c
new file mode 100644
index 0000000..8e75be2
--- /dev/null
+++ b/usr.sbin/i4b/isdntest/main.c
@@ -0,0 +1,738 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * main.c - i4b selftest utility
+ * -----------------------------
+ *
+ * $Id: main.c,v 1.9 1998/12/05 18:04:06 hm Exp $
+ *
+ * last edit-date: [Sat Dec 5 18:18:17 1998]
+ *
+ *---------------------------------------------------------------------------*/
+
+#include <stdio.h>
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <machine/i4b_ioctl.h>
+#include <machine/i4b_cause.h>
+
+static void kbdrdhdl ( void );
+static void isdnrdhdl (int isdnfd );
+
+void handle_connect_ind(unsigned char *ptr);
+void handle_disconnect(unsigned char *ptr);
+void handle_connect_active_ind(unsigned char *ptr);
+
+int connect_response(int isdnfd, unsigned int cdid, int response);
+int disconnect_request(int isdnfd, unsigned int cdid);
+unsigned int get_cdid(int isdnfd);
+int connect_request(int isdnfd, unsigned int cdid);
+int do_test(void);
+static void cleanup(void);
+static void usage(void);
+void setup_wrfix(int len, unsigned char *buf);
+int check_rd(int len, unsigned char *wbuf, unsigned char *rdbuf);
+
+static int isdnfd;
+char outgoingnumber[32];
+char incomingnumber[32];
+int debug_level = 0;
+
+#define I4BDEVICE "/dev/i4b"
+#define DATADEV0 "/dev/i4brbch0"
+#define DATAUNIT0 0
+#define DATADEV1 "/dev/i4brbch1"
+#define DATAUNIT1 1
+
+unsigned int out_cdid = CDID_UNUSED;
+unsigned int in_cdid = CDID_UNUSED;
+
+int waitchar = 0;
+int usehdlc = 0;
+int controller = 0;
+int dotest = 0;
+
+/*---------------------------------------------------------------------------*
+ * program entry
+ *---------------------------------------------------------------------------*/
+int
+main(int argc, char **argv)
+{
+ int i;
+ int c;
+ fd_set set;
+ int ret;
+ char *ptr;
+
+ incomingnumber[0] = '\0';
+ outgoingnumber[0] = '\0';
+
+ while ((c = getopt(argc, argv, "c:d:hi:o:t:w?")) != EOF)
+ {
+ switch(c)
+ {
+ case 'c':
+ if(isdigit(*optarg))
+ {
+ controller = strtoul(optarg, NULL, 10);
+ }
+ else
+ {
+ fprintf(stderr, "Error: option -c requires a numeric argument!\n");
+ usage();
+ }
+ break;
+
+ case 'd':
+ if(isdigit(*optarg))
+ {
+ debug_level = strtoul(optarg, NULL, 10);
+ }
+ else
+ {
+ fprintf(stderr, "Error: option -d requires a numeric argument!\n");
+ usage();
+ }
+ break;
+
+ case 'o':
+ i = 0;
+ ptr = optarg;
+
+ while(*ptr)
+ {
+ if(isdigit(*ptr))
+ {
+ outgoingnumber[i++] = *ptr++;
+ }
+ else
+ {
+ fprintf(stderr, "Error: option -o requires a numeric argument!\n");
+ usage();
+ }
+ }
+ outgoingnumber[i] = '\0';
+ break;
+
+ case 'i':
+ i = 0;
+ ptr = optarg;
+
+ while(*ptr)
+ {
+ if(isdigit(*ptr))
+ {
+ incomingnumber[i++] = *ptr++;
+ }
+ else
+ {
+ fprintf(stderr, "Error: option -i requires a numeric argument!\n");
+ usage();
+ }
+ }
+ incomingnumber[i] = '\0';
+ break;
+
+ case 'w':
+ waitchar = 1;
+ break;
+
+ case 'h':
+ usehdlc = 1;
+ break;
+
+ case 't':
+ if(isdigit(*optarg))
+ {
+ dotest = strtoul(optarg, NULL, 10);
+ }
+ else
+ {
+ fprintf(stderr, "Error: option -t requires a numeric argument!\n");
+ usage();
+ }
+ break;
+
+ case '?':
+ default:
+ usage();
+ break;
+ }
+ }
+
+ if((strlen(incomingnumber) == 0) || (strlen(outgoingnumber) == 0))
+ usage();
+
+ fprintf(stderr, "isdntest: accepting calls from telephone number [%s] \n", incomingnumber);
+ fprintf(stderr, "isdntest: calling out telephone number [%s] \n", outgoingnumber);
+
+ if((atexit(cleanup)) != 0)
+ {
+ fprintf(stderr, "isdntest: atexit error: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ /* open isdn device */
+
+ if((isdnfd = open(I4BDEVICE, O_RDWR)) < 0)
+ {
+ fprintf(stderr, "\nisdntest: cannot open %s: %s\n", I4BDEVICE, strerror(errno));
+ fprintf(stderr, " isdnd is probably running, to use isdntest,\n");
+ fprintf(stderr, " terminate isdnd and then run isdntest again!\n");
+ exit(1);
+ }
+
+ if((out_cdid = get_cdid(isdnfd)) == 0)
+ {
+ fprintf(stderr, "isdntest: error getting cdid: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ if((connect_request(isdnfd, out_cdid)) == -1)
+ {
+ fprintf(stderr, "isdntest: error, outgoing call failed!\n");
+ exit(1);
+ }
+
+ for(;;)
+ {
+ FD_ZERO(&set);
+
+ FD_SET(0, &set);
+
+ FD_SET(isdnfd, &set);
+
+ ret = select(isdnfd + 1, &set, NULL, NULL, NULL);
+
+ if(ret > 0)
+ {
+ if(FD_ISSET(isdnfd, &set))
+ isdnrdhdl(isdnfd);
+
+ if(FD_ISSET(0, &set))
+ kbdrdhdl();
+ }
+ else
+ {
+ fprintf(stderr, "isdntest: select error: %s\n", strerror(errno));
+ }
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * data from keyboard available
+ *---------------------------------------------------------------------------*/
+static void
+kbdrdhdl(void)
+{
+ cleanup();
+ exit(2);
+}
+
+/*---------------------------------------------------------------------------*
+ * data from /dev/isdn available, read and process them
+ *---------------------------------------------------------------------------*/
+static void
+isdnrdhdl(int isdnfd)
+{
+ static unsigned char buf[1024];
+ int len;
+
+ if((len = read(isdnfd, buf, 1024 - 1)) > 0)
+ {
+ switch (buf[0])
+ {
+ case MSG_CONNECT_IND:
+ handle_connect_ind(&buf[0]);
+ break;
+
+ case MSG_CONNECT_ACTIVE_IND:
+ handle_connect_active_ind(&buf[0]);
+ break;
+
+ case MSG_DISCONNECT_IND:
+ handle_disconnect(&buf[0]);
+ break;
+
+ default:
+ if(debug_level)
+ fprintf(stderr, "isdntest: unknown message 0x%x = %c\n", buf[0], buf[0]);
+ break;
+ }
+ }
+ else
+ {
+ fprintf(stderr, "isdntest: read error, errno = %d, length = %d", errno, len);
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * usage display and exit
+ *---------------------------------------------------------------------------*/
+static void
+usage(void)
+{
+ fprintf(stderr, "\n");
+ fprintf(stderr, "isdntest - i4b selftest, compiled %s %s\n",__DATE__, __TIME__);
+ fprintf(stderr, "usage: isdntest -c <ctrl> -h -i <telno> -o <telno>\n");
+ fprintf(stderr, " -c <ctrl> specify controller to use\n");
+ fprintf(stderr, " -h use HDLC as Bchannel protocol\n");
+ fprintf(stderr, " -i <telno> incoming telephone number\n");
+ fprintf(stderr, " -o <telno> outgoing telephone number\n");
+ fprintf(stderr, " -w wait for keyboard entry to disconnect\n");
+ fprintf(stderr, " -t num send test pattern num times\n");
+ fprintf(stderr, "\n");
+ exit(1);
+}
+
+/*---------------------------------------------------------------------------*
+ * initiate an outgoing connection
+ *---------------------------------------------------------------------------*/
+int
+connect_request(int isdnfd, unsigned int cdid)
+{
+ msg_connect_req_t mcr;
+ int ret;
+
+ bzero(&mcr, sizeof(msg_connect_req_t));
+
+ mcr.controller = controller;
+ mcr.channel = CHAN_ANY; /* any channel */
+ mcr.cdid = cdid; /* cdid from get_cdid() */
+
+ if(usehdlc)
+ mcr.bprot = BPROT_RHDLC;/* b channel protocol */
+ else
+ mcr.bprot = BPROT_NONE; /* b channel protocol */
+
+ mcr.driver = BDRV_RBCH; /* raw b channel driver */
+ mcr.driver_unit = DATAUNIT0; /* raw b channel driver unit */
+
+ strcpy(mcr.dst_telno, outgoingnumber);
+ strcpy(mcr.src_telno, incomingnumber);
+
+ if((ret = ioctl(isdnfd, I4B_CONNECT_REQ, &mcr)) < 0)
+ {
+ fprintf(stderr, "ioctl I4B_CONNECT_REQ failed: %s", strerror(errno));
+ return(-1);
+ }
+ fprintf(stderr, "isdntest: calling out to telephone number [%s] \n", outgoingnumber);
+ return(0);
+}
+
+/*---------------------------------------------------------------------------*
+ * handle setup indicator
+ *---------------------------------------------------------------------------*/
+void
+handle_connect_ind(unsigned char *ptr)
+{
+ msg_connect_ind_t *msi = (msg_connect_ind_t *)ptr;
+
+ fprintf(stderr, "isdntest: incoming SETUP: from %s to %s\n",
+ msi->src_telno,
+ msi->dst_telno);
+
+ fprintf(stderr, " channel %d, controller %d, bprot %d, cdid %d\n",
+ msi->channel,
+ msi->controller,
+ msi->bprot,
+ msi->header.cdid);
+
+ in_cdid = msi->header.cdid;
+
+ if(strcmp(msi->dst_telno, outgoingnumber))
+ {
+ msg_connect_resp_t msr;
+ int ret;
+
+ fprintf(stderr, "isdntest: ignoring incoming SETUP: my number [%s] != outgoing [%s]\n",
+ msi->dst_telno, outgoingnumber);
+
+ msr.cdid = in_cdid;
+ msr.response = SETUP_RESP_DNTCRE;
+
+ if((ret = ioctl(isdnfd, I4B_CONNECT_RESP, &msr)) < 0)
+ {
+ fprintf(stderr, "ioctl I4B_CONNECT_RESP ignore failed: %s", strerror(errno));
+ exit(1);
+ }
+
+ }
+ else
+ {
+ msg_connect_resp_t msr;
+ int ret;
+
+ fprintf(stderr, "isdntest: accepting call, sending CONNECT_RESPONSE .....\n");
+
+ msr.cdid = in_cdid;
+ msr.response = SETUP_RESP_ACCEPT;
+
+ if(usehdlc)
+ msr.bprot = BPROT_RHDLC;
+ else
+ msr.bprot = BPROT_NONE;
+
+ msr.driver = BDRV_RBCH;
+ msr.driver_unit = DATAUNIT1;
+
+ if((ret = ioctl(isdnfd, I4B_CONNECT_RESP, &msr)) < 0)
+ {
+ fprintf(stderr, "ioctl I4B_CONNECT_RESP accept failed: %s", strerror(errno));
+ exit(1);
+ }
+ }
+}
+
+#define SLEEPTIME 5
+
+/*---------------------------------------------------------------------------*
+ * handle connection active
+ *---------------------------------------------------------------------------*/
+void
+handle_connect_active_ind(unsigned char *ptr)
+{
+ msg_connect_active_ind_t *msi = (msg_connect_active_ind_t *)ptr;
+ int i;
+
+ fprintf(stderr, "isdntest: connection active, cdid %d\n", msi->header.cdid);
+
+ if(out_cdid == msi->header.cdid)
+ {
+ if(waitchar)
+ {
+ fprintf(stderr, "isdntest: press any key to disconnect ...%c%c%c\n", 0x07, 0x07, 0x07);
+ getchar();
+ }
+ else
+ {
+ if(dotest)
+ {
+ do_test();
+ }
+ else
+ {
+ fprintf(stderr, "isdntest: %d secs delay until disconnect:", SLEEPTIME);
+
+ for(i=0; i < SLEEPTIME;i++)
+ {
+ fprintf(stderr, " .");
+ sleep(1);
+ }
+ fprintf(stderr, "\n");
+ }
+ cleanup();
+ }
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * handle disconnect indication
+ *---------------------------------------------------------------------------*/
+void
+handle_disconnect(unsigned char *ptr)
+{
+ msg_disconnect_ind_t *mdi = (msg_disconnect_ind_t *)ptr;
+
+ if(mdi->header.cdid == out_cdid)
+ {
+ fprintf(stderr, "isdntest: incoming disconnect indication, cdid %d (out_cdid), cause %d\n",
+ mdi->header.cdid, mdi->cause);
+
+ out_cdid = CDID_UNUSED;
+ }
+ else if(mdi->header.cdid == in_cdid)
+ {
+ fprintf(stderr, "isdntest: incoming disconnect indication, cdid %d (in_cdid), cause %d\n",
+ mdi->header.cdid, mdi->cause);
+ in_cdid = CDID_UNUSED;
+ }
+ else
+ {
+ fprintf(stderr, "isdntest: incoming disconnect indication, cdid %d (???), cause %d\n",
+ mdi->header.cdid, mdi->cause);
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * hang up
+ *---------------------------------------------------------------------------*/
+int
+disconnect_request(int isdnfd, unsigned int cdid)
+{
+ msg_discon_req_t mdr;
+ int ret;
+
+ mdr.cdid = cdid;
+ mdr.cause = (CAUSET_I4B << 8) | CAUSE_I4B_NORMAL;
+
+ if((ret = ioctl(isdnfd, I4B_DISCONNECT_REQ, &mdr)) < 0)
+ {
+ fprintf(stderr, "ioctl I4B_DISCONNECT_REQ failed: %s", strerror(errno));
+ return(-1);
+ }
+ fprintf(stderr, "isdntest: sending disconnect request\n");
+ return(0);
+}
+
+/*---------------------------------------------------------------------------*
+ * get cdid from kernel
+ *---------------------------------------------------------------------------*/
+unsigned int
+get_cdid(int isdnfd)
+{
+ msg_cdid_req_t mcr;
+ int ret;
+
+ mcr.cdid = 0;
+
+ if((ret = ioctl(isdnfd, I4B_CDID_REQ, &mcr)) < 0)
+ {
+ fprintf(stderr, "ioctl I4B_CDID_REQ failed: %s", strerror(errno));
+ return(0);
+ }
+ fprintf(stderr, "isdntest: got cdid %d from kernel\n", mcr.cdid);
+ return(mcr.cdid);
+}
+
+/*---------------------------------------------------------------------------*
+ * make shure all cdid's are inactive before leaving
+ *---------------------------------------------------------------------------*/
+void cleanup(void)
+{
+ int len;
+ char buf[1024];
+
+ if(out_cdid != CDID_UNUSED)
+ {
+ fprintf(stderr, "isdntest: cleanup, send disconnect req for out_cdid %d, in_cdid %d\n", out_cdid, in_cdid);
+ disconnect_request(isdnfd, out_cdid);
+ }
+
+ while((out_cdid != CDID_UNUSED) || (in_cdid != CDID_UNUSED))
+ {
+ fprintf(stderr, "isdntest: cleanup, out_cdid %d, in_cdid %d\n", out_cdid, in_cdid);
+
+ if((len = read(isdnfd, buf, 1024 - 1)) > 0)
+ {
+ switch (buf[0])
+ {
+ case MSG_CONNECT_IND:
+ handle_connect_ind(&buf[0]);
+ break;
+
+ case MSG_CONNECT_ACTIVE_IND:
+ handle_connect_active_ind(&buf[0]);
+ break;
+
+ case MSG_DISCONNECT_IND:
+ handle_disconnect(&buf[0]);
+ break;
+
+ default:
+ fprintf(stderr, "isdntest: unknown message 0x%x = %c\n", buf[0], buf[0]);
+ break;
+ }
+ }
+ else
+ {
+ fprintf(stderr, "isdntest: read error, errno = %d, length = %d", errno, len);
+ }
+ }
+ fprintf(stderr, "isdntest: exit cleanup, out_cdid %d, in_cdid %d\n", out_cdid, in_cdid);
+}
+
+/*---------------------------------------------------------------------------*
+ * test the b-channels
+ *---------------------------------------------------------------------------*/
+int do_test(void)
+{
+
+#define FPH 0x3c
+#define FPL 0x66
+
+ int fd0, fd1;
+ unsigned char wrbuf[2048];
+ unsigned char rdbuf[2048];
+ int sz;
+ fd_set set;
+ struct timeval timeout;
+ int ret;
+ int frame;
+ int errcnt;
+ int frm_len;
+ int bytecnt = 0;
+ time_t start_time;
+ time_t cur_time;
+ time_t run_time;
+
+ if((fd0 = open(DATADEV0, O_RDWR)) == -1)
+ {
+ fprintf(stderr, "open of %s failed: %s", DATADEV0, strerror(errno));
+ return(-1);
+ }
+
+ if((fd1 = open(DATADEV1, O_RDWR)) == -1)
+ {
+ fprintf(stderr, "open of %s failed: %s", DATADEV1, strerror(errno));
+ return(-1);
+ }
+
+ printf("\n");
+ frame = 0;
+ errcnt = 0;
+
+ frm_len = 2;
+
+ start_time = time(NULL);
+
+ printf(" frame size errors totalbytes bps elapsedtime\n");
+
+ for(;dotest > 0; dotest--)
+ {
+ setup_wrfix(frm_len, &wrbuf[0]);
+
+ frame++;
+
+ bytecnt += frm_len;
+
+ printf("%6d %4d", frame, frm_len);
+ fflush(stdout);
+
+ if((sz = write(fd0, wrbuf, frm_len)) != frm_len)
+ {
+ fprintf(stderr, "write (%d of %d bytes) to %s failed: %s\n", sz, frm_len, DATADEV0, strerror(errno));
+ }
+
+ timeout.tv_sec = 2;
+ timeout.tv_usec = 0;
+
+ FD_ZERO(&set);
+
+ FD_SET(0, &set);
+ FD_SET(fd1, &set);
+
+ ret = select(fd1+1, &set, NULL, NULL, &timeout);
+
+ if(ret > 0)
+ {
+ if(FD_ISSET(fd1, &set))
+ {
+ if((sz = read(fd1, rdbuf, 2048)) != frm_len)
+ {
+ fprintf(stderr, "read (%d bytes) from %s failed: %s\n", sz, DATADEV1, strerror(errno));
+ }
+
+ cur_time = time(NULL);
+ run_time = difftime(cur_time, start_time);
+
+ if(run_time == 0)
+ run_time = 1;
+
+ printf(" %6d %10d %4d %2.2d:%2.2d:%2.2d \r",
+ errcnt, bytecnt,
+ (int)((int)bytecnt/(int)run_time),
+ (int)run_time/3600, (int)run_time/60, (int)run_time%60);
+ fflush(stdout);
+
+ errcnt += check_rd(frm_len, &wrbuf[0], &rdbuf[0]);
+
+#ifdef NOTDEF
+ for(i=0; i<sz; i++)
+ {
+ printf("0x%02x ", (unsigned char)rdbuf[i]);
+ }
+ printf("\n");
+#endif
+ }
+
+ if(FD_ISSET(0, &set))
+ {
+ return(0);
+ printf("\n\n");
+ }
+ }
+ else
+ {
+ fprintf(stderr, "isdntest, do_test: select error: %s\n", strerror(errno));
+ }
+
+ frm_len = frm_len*2;
+ if(frm_len > 2048)
+ frm_len = 2;
+
+ }
+ printf("\n\n");
+ return(0);
+}
+
+void
+setup_wrfix(int len, unsigned char *buf)
+{
+ register int i;
+
+ for(i=0; i<len;)
+ {
+ *buf = FPH;
+ buf++;
+ *buf = FPL;
+ buf++;
+ i+=2;
+ }
+}
+
+int
+check_rd(int len, unsigned char *wbuf, unsigned char *rbuf)
+{
+ register int i;
+ int ret = 0;
+
+ for(i=0; i<len; i++)
+ {
+ if(*wbuf != *rbuf)
+ {
+ fprintf(stderr, "\nERROR, byte %d, written 0x%02x, read 0x%02x\n", i, *wbuf, *rbuf);
+ ret++;
+ }
+ wbuf++;
+ rbuf++;
+ }
+ return(ret);
+}
+
+
+/* EOF */
diff --git a/usr.sbin/i4b/isdntrace/1tr6.c b/usr.sbin/i4b/isdntrace/1tr6.c
new file mode 100644
index 0000000..1c8c184
--- /dev/null
+++ b/usr.sbin/i4b/isdntrace/1tr6.c
@@ -0,0 +1,754 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * 1tr6.c - print 1TR6 protocol traces
+ * -----------------------------------
+ *
+ * $Id: 1tr6.c,v 1.4 1998/12/05 18:04:08 hm Exp $
+ *
+ * last edit-date: [Sat Dec 5 18:18:38 1998]
+ *
+ *---------------------------------------------------------------------------*/
+
+#include "trace.h"
+
+static int p_1tr6address(char *pbuf, unsigned char buf[]);
+static int p_1tr6cause(char *pbuf, unsigned char buf[]);
+
+/*---------------------------------------------------------------------------*
+ * decode the (german) national specific 1TR6 protocol
+ *---------------------------------------------------------------------------*/
+void
+decode_1tr6(char *pbuf, int n, int off, unsigned char *buf, int raw)
+{
+ int codeset = 0;
+ int oldcodeset = 0;
+ int codelock = 0;
+
+ int pd;
+ int len;
+ int j;
+ int i;
+
+ if(n <= 0)
+ return;
+
+ *pbuf = '\0';
+
+ if(raw)
+ {
+ for (i = 0; i < n; i += 16)
+ {
+ sprintf((pbuf+strlen(pbuf)),"Dump:%.3d ", i+off);
+ for (j = 0; j < 16; j++)
+ if (i + j < n)
+ sprintf((pbuf+strlen(pbuf)),"%02x ", buf[i + j]);
+ else
+ sprintf((pbuf+strlen(pbuf))," ");
+ sprintf((pbuf+strlen(pbuf))," ");
+ for (j = 0; j < 16 && i + j < n; j++)
+ if (isprint(buf[i + j]))
+ sprintf((pbuf+strlen(pbuf)),"%c", buf[i + j]);
+ else
+ sprintf((pbuf+strlen(pbuf)),".");
+ sprintf((pbuf+strlen(pbuf)),"\n");
+ }
+ }
+
+ sprintf((pbuf+strlen(pbuf)), "1TR6: ");
+
+ /* protocol discriminator */
+
+ i = 0;
+
+ pd = buf[i];
+
+ switch(pd)
+ {
+ case 0x40:
+ sprintf((pbuf+strlen(pbuf)), "pd=N0, ");
+ break;
+ case 0x41:
+ sprintf((pbuf+strlen(pbuf)), "pd=N1, ");
+ break;
+ default:
+ sprintf((pbuf+strlen(pbuf)), "pd=UNDEF (0x%02x), ",pd);
+ break;
+ }
+
+ /* call reference */
+
+ i++;
+
+ len = buf[i] & 0x0f;
+
+ switch(len)
+ {
+ case 1:
+ sprintf((pbuf+strlen(pbuf)), "cr=0x%02x %s, ", (buf[i+1] & 0x7f), (buf[i+1] & 0x80) ? "(from destination)" : "(from origination)");
+ break;
+ default:
+ sprintf((pbuf+strlen(pbuf)), "cr: LEN=%d %s 0x%02x 0x%02x, ", len, (buf[i+1] & 0x80) ? "org" : "dst", (buf[i+1] & 0x7f), (buf[i+2] & 0x7f));
+ break;
+ }
+
+ i += (len+1);
+
+ /* message type */
+
+ sprintf((pbuf+strlen(pbuf)), "message=");
+
+ if(pd == 0x40) /* protocol discriminator N0 */
+ {
+ switch(buf[i])
+ {
+ case 0x61:
+ sprintf((pbuf+strlen(pbuf)), "REGISTER INDICATION: ");
+ break;
+ case 0x62:
+ sprintf((pbuf+strlen(pbuf)), "CANCEL INDICATION: ");
+ break;
+ case 0x63:
+ sprintf((pbuf+strlen(pbuf)), "FACILITY STATUS: ");
+ break;
+ case 0x64:
+ sprintf((pbuf+strlen(pbuf)), "STATUS ACKNOWLEDGE: ");
+ break;
+ case 0x65:
+ sprintf((pbuf+strlen(pbuf)), "STATUS REJECT: ");
+ break;
+ case 0x66:
+ sprintf((pbuf+strlen(pbuf)), "FACILITY INFORMATION: ");
+ break;
+ case 0x67:
+ sprintf((pbuf+strlen(pbuf)), "INFORMATION ACKNOWLEDGE: ");
+ break;
+ case 0x68:
+ sprintf((pbuf+strlen(pbuf)), "INFORMATION REJECT: ");
+ break;
+ case 0x75:
+ sprintf((pbuf+strlen(pbuf)), "CLOSE: ");
+ break;
+ case 0x77:
+ sprintf((pbuf+strlen(pbuf)), "CLOSE ACKNOWLEDGE: ");
+ break;
+ default:
+ sprintf((pbuf+strlen(pbuf)), "ERROR: PD=0x40 MSG=0x%02x, ", buf[i]);
+ break;
+ }
+ }
+ else if(pd == 0x41)
+ {
+ switch(buf[i])
+ {
+ case 0x00:
+ sprintf((pbuf+strlen(pbuf)), "ESCAPE: ");
+ break;
+ case 0x01:
+ sprintf((pbuf+strlen(pbuf)), "ALERT: ");
+ break;
+ case 0x02:
+ sprintf((pbuf+strlen(pbuf)), "CALL SENT: ");
+ break;
+ case 0x07:
+ sprintf((pbuf+strlen(pbuf)), "CONNECT: ");
+ break;
+ case 0x0f:
+ sprintf((pbuf+strlen(pbuf)), "CONNECT ACKNOWLEDGE: ");
+ break;
+ case 0x05:
+ sprintf((pbuf+strlen(pbuf)), "SETUP: ");
+ break;
+ case 0x0d:
+ sprintf((pbuf+strlen(pbuf)), "SETUP ACKNOWLEDGE: ");
+ break;
+
+ case 0x26:
+ sprintf((pbuf+strlen(pbuf)), "RESUME: ");
+ break;
+ case 0x2e:
+ sprintf((pbuf+strlen(pbuf)), "RESUME ACKNOWLEDGE: ");
+ break;
+ case 0x22:
+ sprintf((pbuf+strlen(pbuf)), "RESUME REJECT: ");
+ break;
+ case 0x25:
+ sprintf((pbuf+strlen(pbuf)), "SUSPEND: ");
+ break;
+ case 0x2d:
+ sprintf((pbuf+strlen(pbuf)), "SUSPEND ACKNOWLEDGE: ");
+ break;
+ case 0x21:
+ sprintf((pbuf+strlen(pbuf)), "SUSPEND REJECT: ");
+ break;
+ case 0x20:
+ sprintf((pbuf+strlen(pbuf)), "USER INFORMATION: ");
+ break;
+
+ case 0x40:
+ sprintf((pbuf+strlen(pbuf)), "DETACH");
+ break;
+ case 0x45:
+ sprintf((pbuf+strlen(pbuf)), "DISCONNECT: ");
+ break;
+ case 0x4d:
+ sprintf((pbuf+strlen(pbuf)), "RELEASE: ");
+ break;
+ case 0x5a:
+ sprintf((pbuf+strlen(pbuf)), "RELEASE ACKNOWLEDGE");
+ break;
+
+ case 0x6e:
+ sprintf((pbuf+strlen(pbuf)), "CANCEL ACKNOWLEDGE: ");
+ break;
+ case 0x67:
+ sprintf((pbuf+strlen(pbuf)), "CANCEL REJECT: ");
+ break;
+ case 0x69:
+ sprintf((pbuf+strlen(pbuf)), "CONGESTION CONTROL: ");
+ break;
+ case 0x60:
+ sprintf((pbuf+strlen(pbuf)), "FACILITY: ");
+ break;
+ case 0x68:
+ sprintf((pbuf+strlen(pbuf)), "FACILITY ACKNOWLEDGE: ");
+ break;
+ case 0x66:
+ sprintf((pbuf+strlen(pbuf)), "FACILITY CANCEL: ");
+ break;
+ case 0x64:
+ sprintf((pbuf+strlen(pbuf)), "FACILITY REGISTER: ");
+ break;
+ case 0x65:
+ sprintf((pbuf+strlen(pbuf)), "FACILITY REJECT: ");
+ break;
+ case 0x6d:
+ sprintf((pbuf+strlen(pbuf)), "INFORMATION: ");
+ break;
+ case 0x6c:
+ sprintf((pbuf+strlen(pbuf)), "REGISTER ACKNOWLEDGE: ");
+ break;
+ case 0x6f:
+ sprintf((pbuf+strlen(pbuf)), "REGISTER REJECT: ");
+ break;
+ case 0x63:
+ sprintf((pbuf+strlen(pbuf)), "STATUS: ");
+ break;
+
+ default:
+ sprintf((pbuf+strlen(pbuf)), "ERROR: PD=0x41 MSG=0x%02x, ", buf[i]);
+ break;
+ }
+ }
+ else
+ {
+ sprintf((pbuf+strlen(pbuf)), "ERROR: PD=0x%02x MSG=0x%02x, ", pd, buf[i]);
+ }
+
+ /* other information elements */
+
+ i++;
+
+ for (; i < n;)
+ {
+ sprintf((pbuf+strlen(pbuf)), "\n ");
+
+ if(buf[i] & 0x80)
+ {
+ /* single octett info element */
+
+ switch(buf[i] & 0x70)
+ {
+ case 0x00: /* reserved */
+ sprintf((pbuf+strlen(pbuf)), "[reserved single octett info]");
+ break;
+
+ case 0x10: /* shift */
+ oldcodeset = codeset;
+ codeset = buf[i] & 0x07;
+ if(buf[i] & 0x08)
+ codelock = 0;
+ else
+ codelock = 1;
+ sprintf((pbuf+strlen(pbuf)), "[shift: codeset=%d lock=%d]", codeset, codelock);
+ break;
+
+ case 0x20: /* more data */
+ sprintf((pbuf+strlen(pbuf)), "[more data]");
+ break;
+
+ case 0x30: /* congestion level */
+ sprintf((pbuf+strlen(pbuf)), "[congestion level = %d]", buf[i] & 0x0f);
+ break;
+
+ default:
+ sprintf((pbuf+strlen(pbuf)), "[UNDEF SINGLE OCTET ELEMENT 0x%02x]", buf[i]);
+ break;
+ }
+
+ i++; /* next */
+
+ }
+ else
+ {
+ /* variable length info element */
+
+ if(codeset == 0)
+ {
+ switch(buf[i])
+ {
+ case 0x08:
+ sprintf((pbuf+strlen(pbuf)), "[cause: ");
+ i += p_1tr6cause(pbuf, &buf[i]);
+ goto next;
+ break;
+
+ case 0x0c:
+ sprintf((pbuf+strlen(pbuf)), "[connected address: ");
+ i += p_1tr6address(pbuf, &buf[i]);
+ goto next;
+ break;
+
+ case 0x10:
+ sprintf((pbuf+strlen(pbuf)), "[call identity: ");
+ break;
+ case 0x18:
+ sprintf((pbuf+strlen(pbuf)), "[channel id: channel=");
+ i += 2;
+ switch(buf[i] & 0x03)
+ {
+ case 0:
+ sprintf((pbuf+strlen(pbuf)), "no channel");
+ break;
+ case 1:
+ sprintf((pbuf+strlen(pbuf)), "B-1");
+ break;
+ case 2:
+ sprintf((pbuf+strlen(pbuf)), "B-2");
+ break;
+ case 3:
+ sprintf((pbuf+strlen(pbuf)), "any channel");
+ break;
+ }
+ if(buf[i] & 0x08)
+ sprintf((pbuf+strlen(pbuf)), " (exclusive)]");
+ else
+ sprintf((pbuf+strlen(pbuf)), " (preferred)]");
+ i++;
+ goto next;
+ break;
+ case 0x20:
+ sprintf((pbuf+strlen(pbuf)), "[network specific facilities: ");
+ i++;
+ len = buf[i];
+ i+=2;
+ switch(buf[i])
+ {
+ case 1:
+ sprintf((pbuf+strlen(pbuf)), "Sperre");
+ break;
+ case 2:
+ sprintf((pbuf+strlen(pbuf)), "AWS 1");
+ break;
+ case 3:
+ sprintf((pbuf+strlen(pbuf)), "AWS 2");
+ break;
+ case 0xe:
+ sprintf((pbuf+strlen(pbuf)), "Konferenz");
+ break;
+ case 0xf:
+ sprintf((pbuf+strlen(pbuf)), "B-Kan uebern.");
+ break;
+ case 0x10:
+ sprintf((pbuf+strlen(pbuf)), "aktvrg. ghlt. Vbdg.");
+ break;
+ case 0x11:
+ sprintf((pbuf+strlen(pbuf)), "3er Konf");
+ break;
+ case 0x12:
+ sprintf((pbuf+strlen(pbuf)), "1seitg D/G Wechsel");
+ break;
+ case 0x13:
+ sprintf((pbuf+strlen(pbuf)), "2seitig D/G Wechsel");
+ break;
+ case 0x14:
+ sprintf((pbuf+strlen(pbuf)), "Rufnr. identifiz.");
+ break;
+ case 0x15:
+ sprintf((pbuf+strlen(pbuf)), "GBG");
+ break;
+ case 0x17:
+ sprintf((pbuf+strlen(pbuf)), "ueberg. Ruf");
+ break;
+ case 0x1a:
+ sprintf((pbuf+strlen(pbuf)), "um/weitergel. Ruf");
+ break;
+ case 0x1b:
+ sprintf((pbuf+strlen(pbuf)), "unterdr. A-Rufnr.");
+ break;
+ case 0x1e:
+ sprintf((pbuf+strlen(pbuf)), "Verbdg. deaktivieren");
+ break;
+ case 0x1d:
+ sprintf((pbuf+strlen(pbuf)), "Verbdg. aktivieren");
+ break;
+ case 0x1f:
+ sprintf((pbuf+strlen(pbuf)), "SPV");
+ break;
+ case 0x23:
+ sprintf((pbuf+strlen(pbuf)), "Rueckw. 2seitg. DW");
+ break;
+ case 0x24:
+ sprintf((pbuf+strlen(pbuf)), "Anrufumltg. priv. Netz");
+ break;
+ default:
+ sprintf((pbuf+strlen(pbuf)), "undefined");
+ break;
+ }
+ i++;
+ sprintf((pbuf+strlen(pbuf)), ", serv=%d", buf[i]);
+ i++;
+ sprintf((pbuf+strlen(pbuf)), ", ainfo=%d", buf[i]);
+ i++;
+ len-=4;
+ for(j = 0; j < len; j++)
+ {
+ sprintf((pbuf+strlen(pbuf))," 0x%02x", buf[j+i]);
+ }
+ sprintf((pbuf+strlen(pbuf)),"]");
+ i += j;
+ goto next;
+ break;
+ case 0x28:
+ sprintf((pbuf+strlen(pbuf)), "[display: ");
+ break;
+ case 0x2c:
+ sprintf((pbuf+strlen(pbuf)), "[keypad: ");
+ break;
+ case 0x6c:
+ sprintf((pbuf+strlen(pbuf)), "[origination address: ");
+ i += p_1tr6address(pbuf, &buf[i]);
+ goto next;
+ break;
+ case 0x70:
+ sprintf((pbuf+strlen(pbuf)), "[destination address: ");
+ i += p_1tr6address(pbuf, &buf[i]);
+ goto next;
+ break;
+ case 0x7e:
+ sprintf((pbuf+strlen(pbuf)), "[user-user information: ");
+ break;
+ case 0x7f:
+ sprintf((pbuf+strlen(pbuf)), "[reserved: ");
+ break;
+ default:
+ sprintf((pbuf+strlen(pbuf)), "[UNKNOWN INFO-ELEMENT-ID");
+ break;
+ }
+ }
+ else if(codeset == 6)
+ {
+ switch(buf[i])
+ {
+ case 0x01:
+ sprintf((pbuf+strlen(pbuf)), "[service ind: serv=");
+ i+= 2;
+ switch(buf[i])
+ {
+ case 0x01:
+ sprintf((pbuf+strlen(pbuf)), "phone");
+ break;
+ case 0x02:
+ sprintf((pbuf+strlen(pbuf)), "a/b");
+ break;
+ case 0x03:
+ sprintf((pbuf+strlen(pbuf)), "X.21");
+ break;
+ case 0x04:
+ sprintf((pbuf+strlen(pbuf)), "fax g4");
+ break;
+ case 0x05:
+ sprintf((pbuf+strlen(pbuf)), "btx");
+ break;
+ case 0x07:
+ sprintf((pbuf+strlen(pbuf)), "64k data");
+ break;
+ case 0x08:
+ sprintf((pbuf+strlen(pbuf)), "X.25");
+ break;
+ case 0x09:
+ sprintf((pbuf+strlen(pbuf)), "teletex");
+ break;
+ case 0x0a:
+ sprintf((pbuf+strlen(pbuf)), "mixed");
+ break;
+ case 0x0d:
+ sprintf((pbuf+strlen(pbuf)), "temex");
+ break;
+ case 0x0e:
+ sprintf((pbuf+strlen(pbuf)), "picturephone");
+ break;
+ case 0x0f:
+ sprintf((pbuf+strlen(pbuf)), "btx (new)");
+ break;
+ case 0x10:
+ sprintf((pbuf+strlen(pbuf)), "videophone");
+ break;
+ default:
+ sprintf((pbuf+strlen(pbuf)), "undefined");
+ break;
+ }
+ i++;
+ sprintf((pbuf+strlen(pbuf)), ", ainfo=0x%02x]", buf[i]);
+ i++;
+ goto next;
+ break;
+ case 0x02:
+ sprintf((pbuf+strlen(pbuf)), "[charging information: ");
+ break;
+ case 0x03:
+ sprintf((pbuf+strlen(pbuf)), "[date: ");
+ i++;
+ len = buf[i];
+ i++;
+ for(j = 0; j < len; j++)
+ {
+ sprintf((pbuf+strlen(pbuf)),"%c", buf[j+i]);
+ }
+ sprintf((pbuf+strlen(pbuf)),"]");
+ i += j;
+ goto next;
+ break;
+ case 0x05:
+ sprintf((pbuf+strlen(pbuf)), "[facility select: ");
+ break;
+ case 0x06:
+ sprintf((pbuf+strlen(pbuf)), "[status of facilities: ");
+ break;
+ case 0x07:
+ sprintf((pbuf+strlen(pbuf)), "[status of called party: ");
+ i+=2;
+ switch(buf[i])
+ {
+ case 1:
+ sprintf((pbuf+strlen(pbuf)), "no information]");
+ break;
+ case 2:
+ sprintf((pbuf+strlen(pbuf)), "is being called]");
+ break;
+ default:
+ sprintf((pbuf+strlen(pbuf)), "undefined (0x%02x)]", buf[i]);
+ break;
+ }
+ i++;
+ goto next;
+ break;
+ case 0x08:
+ sprintf((pbuf+strlen(pbuf)), "[additional tx attributes: ");
+ i++;
+ len = buf[i];
+ i++;
+ for(j = 0; j < len; j++)
+ {
+ switch(buf[j+i] &0x70)
+ {
+ case 0:
+ sprintf((pbuf+strlen(pbuf)), "no satellite link");
+ break;
+ case 1:
+ sprintf((pbuf+strlen(pbuf)), "one satellite link");
+ break;
+ case 2:
+ sprintf((pbuf+strlen(pbuf)), "two satellite links");
+ break;
+ case 3:
+ sprintf((pbuf+strlen(pbuf)), "three satellite links");
+ break;
+ default:
+ sprintf((pbuf+strlen(pbuf)), "undefined value");
+ break;
+ }
+ if(buf[j+i] & 0x80)
+ sprintf((pbuf+strlen(pbuf)),"(flag=req)]");
+ else
+ sprintf((pbuf+strlen(pbuf)),"(flag=ind)]");
+ }
+ i += j;
+ goto next;
+ break;
+ default:
+ sprintf((pbuf+strlen(pbuf)), "[UNKNOWN INFO-ELEMENT-ID");
+ break;
+ }
+ }
+ else
+ {
+ sprintf((pbuf+strlen(pbuf)), "[ILLEGAL CODESET = 0x%02x", codeset);
+ }
+
+ i++; /* index -> length */
+
+ len = buf[i];
+
+ i++; /* index -> 1st param */
+
+ for(j = 0; j < len; j++)
+ {
+ sprintf((pbuf+strlen(pbuf))," 0x%02x", buf[j+i]);
+ }
+
+ sprintf((pbuf+strlen(pbuf)),"]");
+
+ i += len;
+
+next:
+
+ if(!codelock && (codeset != oldcodeset))
+ codeset = oldcodeset;
+ }
+ }
+ sprintf((pbuf+strlen(pbuf)),"\n");
+}
+
+/*---------------------------------------------------------------------------*
+ * decode and print the cause
+ *---------------------------------------------------------------------------*/
+static int
+p_1tr6cause(char *pbuf, unsigned char buf[])
+{
+ int j;
+ int len;
+ int i = 0;
+
+ i++; /* index -> length */
+
+ len = buf[i];
+
+ switch(len)
+ {
+ case 0:
+ sprintf((pbuf+strlen(pbuf)), "%s", print_cause_1tr6(0));
+ break;
+ case 1:
+ i++;
+ sprintf((pbuf+strlen(pbuf)), "%s", print_cause_1tr6(buf[i] & 0x7f));
+ break;
+ case 2:
+ i++;
+ sprintf((pbuf+strlen(pbuf)), "%s, location: ", print_cause_1tr6(buf[i] & 0x7f));
+ i++;
+ switch(buf[i] & 0x0f)
+ {
+ case 0x04:
+ sprintf((pbuf+strlen(pbuf)), "public network");
+ break;
+ case 0x05:
+ sprintf((pbuf+strlen(pbuf)), "private network");
+ break;
+ case 0x0f:
+ sprintf((pbuf+strlen(pbuf)), "no information");
+ break;
+ default:
+ sprintf((pbuf+strlen(pbuf)), "reserved (0x%02x)", buf[i] & 0x0f);
+ break;
+ }
+ break;
+ default:
+ i++; /* index -> length */
+ len = buf[i];
+ i++; /* index -> 1st param */
+ for(j = 0; j < len; j++)
+ {
+ sprintf((pbuf+strlen(pbuf))," 0x%02x", buf[j+i]);
+ }
+ break;
+ }
+ i++;
+ sprintf((pbuf+strlen(pbuf)),"]");
+ return(i);
+}
+
+/*---------------------------------------------------------------------------*
+ * decode and print the ISDN (telephone) number
+ *---------------------------------------------------------------------------*/
+static int
+p_1tr6address(char *pbuf, unsigned char buf[])
+{
+ int j;
+ int len;
+ int i = 0;
+ int tp;
+
+ i++; /* index -> length */
+ len = buf[i];
+ i++; /* index -> 1st param */
+ tp = buf[i];
+
+ i++;
+ len--;
+
+ for(j = 0; j < len; j++)
+ {
+ sprintf((pbuf+strlen(pbuf)),"%c", buf[j+i]);
+ }
+
+ switch((tp & 0x70) >> 4)
+ {
+ case 0:
+ sprintf((pbuf+strlen(pbuf)), " (type=unknown, ");
+ break;
+ case 1:
+ sprintf((pbuf+strlen(pbuf)), " (type=international, ");
+ break;
+ case 2:
+ sprintf((pbuf+strlen(pbuf)), " (type=national, ");
+ break;
+ default:
+ sprintf((pbuf+strlen(pbuf)), " (type=%d, ", ((tp & 0x70) >> 4));
+ break;
+ }
+
+ switch(tp & 0x0f)
+ {
+ case 0:
+ sprintf((pbuf+strlen(pbuf)), "plan=unknown)");
+ break;
+ case 1:
+ sprintf((pbuf+strlen(pbuf)), "plan=ISDN)");
+ break;
+ default:
+ sprintf((pbuf+strlen(pbuf)), "plan=%d)", (tp & 0x0f));
+ break;
+ }
+
+ sprintf((pbuf+strlen(pbuf)),"]");
+
+ i += j;
+
+ return(i);
+}
+
+/* EOF */
diff --git a/usr.sbin/i4b/isdntrace/Makefile b/usr.sbin/i4b/isdntrace/Makefile
new file mode 100644
index 0000000..150c18d
--- /dev/null
+++ b/usr.sbin/i4b/isdntrace/Makefile
@@ -0,0 +1,8 @@
+PROG = isdntrace
+SRCS = q921.c q931.c q931_util.c q932_fac.c 1tr6.c trace.c \
+ pcause_1tr6.c pcause_q850.c
+#CFLAGS += -Wall -g
+MAN8 = isdntrace.8
+
+.include <bsd.prog.mk>
+
diff --git a/usr.sbin/i4b/isdntrace/cable.txt b/usr.sbin/i4b/isdntrace/cable.txt
new file mode 100644
index 0000000..890d8d4
--- /dev/null
+++ b/usr.sbin/i4b/isdntrace/cable.txt
@@ -0,0 +1,60 @@
+ *---------------------------------------------------------------------------
+ *
+ * Custom cable to trace an ISDN S0 bus with two passive (!) ISDN boards
+ * ---------------------------------------------------------------------
+ *
+ * $Id: cable.txt,v 1.2 1998/01/22 20:39:49 hm Exp $
+ *
+ * last edit-date: [Thu Jan 22 19:57:50 1998]
+ *
+ * -hm documentation of analyze mode
+ *
+ *---------------------------------------------------------------------------*/
+
+The cable consists of a RJ-45 plug with both tx and rx connected and
+two jacks; the tx cables from the plug are wired to one jack and the
+rx cables from the plug are wired to the other jack.
+
+The computer must be equipped with two (!) supported passive cards and
+the cable from one card is plugged into one of the jacks while the cable
+to from the other card is plugged into the other jack.
+
+Now one card monitors the tx part of the S0 bus and the other card
+monitors the rx part.
+
+Which card functions as the rx side and which as the tx side can be
+specified as options to the isdntrace utility (-R and -T) which has
+to be run in analyzer mode (-a) to support this configuration.
+
+
+ 1
+ 2
+ 3
+ +--------------4 receiving-side board
+ S0-bus +--|--------------5 in computer (jack for
+ to analyze | | 6 cable to passive controller)
+ 8 | | 7
+ 7 | | 8
+ transmit - 6------------|--|--+
+ receive - 5------------+ | |
+ receive + 4---------------+ |
+ transmit + 3------------+ |
+ 2 | | 1
+ 1 | | 2
+ plug into | | 3
+ S0 bus +-----|-----------4 transmitting-side board
+ +-----------5 in computer (jack for
+ 6 cable to passive controller)
+ 7
+ 8
+
+
+
+ RJ-45 plug RJ-45 jack
+ view from the front view from the front
+ cable goes out to the rear
+
+ /--------- / ----------
+ | 87654321 | | 12345678 |
+ |__ __|/ |/_ /_|
+ |____|/ |/___|
diff --git a/usr.sbin/i4b/isdntrace/isdntrace.8 b/usr.sbin/i4b/isdntrace/isdntrace.8
new file mode 100644
index 0000000..62c5d07
--- /dev/null
+++ b/usr.sbin/i4b/isdntrace/isdntrace.8
@@ -0,0 +1,205 @@
+.\"
+.\" Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id: isdntrace.8,v 1.9 1998/12/05 18:04:10 hm Exp $
+.\"
+.\" last edit-date: [Sat Dec 5 18:18:59 1998]
+.\"
+.Dd October 19, 1998
+.Dt isdntrace 8
+.Sh NAME
+.Nm isdntrace
+.Nd isdn4bsd ISDN protocol trace utility
+.Sh SYNOPSIS
+.Nm isdntrace
+.Op Fl a
+.Op Fl b
+.Op Fl d
+.Op Fl f Ar filename
+.Op Fl h
+.Op Fl i
+.Op Fl l
+.Op Fl n Ar number
+.Op Fl o
+.Op Fl p Ar filename
+.Op Fl r
+.Op Fl u Ar number
+.Op Fl B
+.Op Fl F
+.Op Fl P
+.Op Fl R Ar unit
+.Op Fl T Ar unit
+.Sh DESCRIPTION
+.Nm isdntrace
+is part of the isdn4bsd package and is used to provide the user with a
+mnemonic display of the layers 1, 2 and 3 protocol activities on
+the D channel and hex dump of the B channel(s) activities.
+.Pp
+Together with two passive supported cards and an easy to build cable it can
+also be used to monitor the complete traffic on a S0 bus providing S0 bus
+analyzer features.
+.Pp
+The
+.Nm
+utility is only available for passive supported cards.
+.Pp
+The following options can be used:
+.Bl -tag -width Ds
+.It Fl a
+Run
+.Nm
+in analyzer mode by using two passive cards and a custom cable which can
+be build as described in the file
+.Em cable.txt
+in the isdn4bsd source distribution. One card acts as a receiver for the
+transmitting direction on the S0 bus while the other card acts as a receiver
+for the receiving direction on the S0 bus. Complete traffic monitoring is
+possible using this setup.
+.It Fl b
+switch B channel tracing on (default off).
+.It Fl d
+switch D channel tracing off (default on).
+.It Fl f
+Use
+.Ar filename
+as the name of a file into which to write tracing output (default filename is
+isdntrace<n> where n is the number of the unit to trace).
+.It Fl h
+switch display of header off (default on).
+.It Fl i
+print layer 1 (I.430) INFO signals to monitor layer 1 activity (default off).
+.It Fl l
+switch displaying of Layer 2 (Q.921) frames off (default on).
+.It Fl n
+This option takes a numeric argument specifying the minimum
+frame size in octetts a frame must have to be displayed. (default 0)
+.It Fl o
+switch off writing trace output to a file (default on).
+.It Fl p
+Use
+.Ar filename
+as the name of a file used for the -B and -P options (default filename
+is isdntracebin<n> where n is the number of the unit to trace).
+.It Fl r
+Switch off printing a raw hexadecimal dump of the packets preceding
+the decoded protocol information (default on).
+.It Fl u
+Use
+.Ar number
+as the unit number of the controller card to trace (default 0).
+.It Fl B
+Write undecoded binary trace data to a file for later or remote
+analyzing (default off).
+.It Fl F
+This option can only be used when option -P (playback from binary data file)
+is used. The -F option causes playback not to stop at end of file but rather
+to wait for additional data to be available from the input file.
+.Pp
+This option is useful when trace data is accumulated in binary format (to
+save disk space) but a monitoring functionality is desired.
+(default off).
+.It Fl P
+Read undecoded binary trace data from file instead from device (default off).
+.It Fl R
+Use
+.Ar unit
+as the receiving interface unit number in analyze mode.
+.It Fl T
+Use
+.Ar unit
+as the transmitting interface unit number in analyze mode.
+.El
+.Pp
+When the USR1 signal is sent to a
+.Nm
+process, the currently used logfiles are reopened, so that logfile
+rotation becomes possible.
+.Pp
+The trace output should be obvious. It is very handy to have the following
+standard texts available when tracing ISDN protocols:
+.Pp
+.Bl -tag -width Ds -compact -offset indent
+.It Ar I.430
+ISDN BRI layer 1 protocol description.
+.It Ar Q.921
+ISDN D-channel layer 2 protocol description.
+.It Ar Q.931
+ISDN D-channel layer 3 protocol description.
+.It Ar 1TR6
+German-specific ISDN layer 3 protocol description. (NOTICE: decoding
+of the 1TR6 protocol is included but not supported since i dont have
+any longer access to a 1TR6 based ISDN installation.)
+.El
+.Pp
+
+.Nm Isdntrace
+automatically detects the layer 3 protocol being used by looking at the
+Protocol Discriminator (see: Q.931/1993 pp. 53).
+.Pp
+
+
+.Sh FILES
+.Bl -tag -width daddeldi -compact
+.It Pa /dev/i4btrc<n>
+The devicefile(s) used to get the trace messages for ISDN card unit <n>
+out of the kernel.
+.El
+
+.Sh EXAMPLES
+The command:
+.Bd -literal -offset indent
+isdntrace -f /var/tmp/isdn.trace
+.Ed
+.Pp
+will start D channel tracing on passive controller 0 with all except B
+channel tracing enabled and logs everything into the output file
+/tmp/isdn.trace.
+
+.Sh SEE ALSO
+.Xr isdnd 8
+
+.Sh BUGS
+Still some or more left.
+
+.Sh STANDARDS
+ITU Recommendations I.430, Q.920, Q.921, Q.930, Q.931
+.Pp
+FTZ Richtlinie 1TR3, Band III
+.Pp
+ITU Recommendation Q.932 (03/93), Q.950 (03/93)
+.Pp
+ETSI Recommendation ETS 300 179 (10/92), ETS 300 180 (10/92)
+.Pp
+ETSI Recommendation ETS 300 181 (04/93), ETS 300 182 (04/93)
+.Pp
+ITU Recommendation X.208, X.209
+
+.Sh AUTHOR
+The
+.Nm
+utility was written by Gary Jennejohn and Hellmuth Michaelis.
+.Pp
+This manual page was written by Hellmuth Michaelis, he can be reached
+at hm@kts.org.
+
diff --git a/usr.sbin/i4b/isdntrace/pcause_1tr6.c b/usr.sbin/i4b/isdntrace/pcause_1tr6.c
new file mode 100644
index 0000000..42f244d
--- /dev/null
+++ b/usr.sbin/i4b/isdntrace/pcause_1tr6.c
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * printing cause values
+ * ---------------------
+ *
+ * $Id: pcause_1tr6.c,v 1.4 1998/12/23 10:03:55 hm Exp $
+ *
+ * last edit-date: [Wed Dec 23 10:57:11 1998]
+ *
+ *---------------------------------------------------------------------------*/
+
+#include "trace.h"
+#include "pcause_1tr6.h"
+
+char *
+print_cause_1tr6(unsigned char code)
+{
+ static char error_message[120];
+ char *e;
+
+ switch(code)
+ {
+ case CAUSE_1TR6_SHUTDN:
+ e = "normal D-channel shutdown";
+ break;
+
+ case CAUSE_1TR6_ICRV:
+ e = "invalid call reference value";
+ break;
+
+ case CAUSE_1TR6_BSNI:
+ e = "bearer service not implemented";
+ break;
+
+ case CAUSE_1TR6_CIDNE:
+ e = "call identity does not exist";
+ break;
+
+ case CAUSE_1TR6_CIIU:
+ e = "call identity in use";
+ break;
+
+ case CAUSE_1TR6_NCA:
+ e = "no channel available";
+ break;
+
+ case CAUSE_1TR6_RFNI:
+ e = "requested facility not implemented";
+ break;
+
+ case CAUSE_1TR6_RFNS:
+ e = "requested facility not subscribed";
+ break;
+
+ case CAUSE_1TR6_OCB:
+ e = "outgoing calls barred";
+ break;
+
+ case CAUSE_1TR6_UAB:
+ e = "user access busy";
+ break;
+
+ case CAUSE_1TR6_NECUG:
+ e = "non existent CUG";
+ break;
+
+ case CAUSE_1TR6_NECUG1:
+ e = "non existent CUG";
+ break;
+
+ case CAUSE_1TR6_SPV:
+ e = "kommunikationsbeziehung als SPV nicht erlaubt";
+ break;
+
+ case CAUSE_1TR6_DNO:
+ e = "destination not obtainable";
+ break;
+
+ case CAUSE_1TR6_NC:
+ e = "number changed";
+ break;
+
+ case CAUSE_1TR6_OOO:
+ e = "out of order";
+ break;
+
+ case CAUSE_1TR6_NUR:
+ e = "no user responding";
+ break;
+
+ case CAUSE_1TR6_UB:
+ e = "user busy";
+ break;
+
+ case CAUSE_1TR6_ICB:
+ e = "incoming calls barred";
+ break;
+
+ case CAUSE_1TR6_CR:
+ e = "call rejected";
+ break;
+
+ case CAUSE_1TR6_NCO:
+ e = "network congestion";
+ break;
+
+ case CAUSE_1TR6_RUI:
+ e = "remote user initiated";
+ break;
+
+ case CAUSE_1TR6_LPE:
+ e = "local procedure error";
+ break;
+
+ case CAUSE_1TR6_RPE:
+ e = "remote procedure error";
+ break;
+
+ case CAUSE_1TR6_RUS:
+ e = "remote user suspended";
+ break;
+
+ case CAUSE_1TR6_RUR:
+ e = "remote user resumed";
+ break;
+
+ case CAUSE_1TR6_UIDL:
+ e = "user info discharded locally";
+ break;
+
+ default:
+ e = "UNKNOWN error occured";
+ break;
+ }
+
+ sprintf(error_message, "0x%02x: %s", code & 0x7f, e);
+ return(error_message);
+}
+
+/* EOF */
diff --git a/usr.sbin/i4b/isdntrace/pcause_1tr6.h b/usr.sbin/i4b/isdntrace/pcause_1tr6.h
new file mode 100644
index 0000000..f327cc7
--- /dev/null
+++ b/usr.sbin/i4b/isdntrace/pcause_1tr6.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * pcause1tr6.h - 1TR6 causes definitions
+ * --------------------------------------
+ *
+ * $Id: pcause_1tr6.h,v 1.3 1998/12/05 18:04:13 hm Exp $
+ *
+ * last edit-date: [Sat Dec 5 18:19:39 1998]
+ *
+ *---------------------------------------------------------------------------*/
+
+char *print_cause_1tr6(unsigned char code);
+
+/* 1TR6 protocol causes */
+
+#define CAUSE_1TR6_SHUTDN 0x00 /* normal D-channel shutdown */
+#define CAUSE_1TR6_ICRV 0x01 /* invalid call reference value */
+#define CAUSE_1TR6_BSNI 0x03 /* bearer service not implemented */
+#define CAUSE_1TR6_CIDNE 0x07 /* call identity does not exist */
+#define CAUSE_1TR6_CIIU 0x08 /* call identity in use */
+#define CAUSE_1TR6_NCA 0x0A /* no channel available */
+#define CAUSE_1TR6_RFNI 0x10 /* requested facility not implemented */
+#define CAUSE_1TR6_RFNS 0x11 /* requested facility not subscribed */
+#define CAUSE_1TR6_OCB 0x20 /* outgoing calls barred */
+#define CAUSE_1TR6_UAB 0x21 /* user access busy */
+#define CAUSE_1TR6_NECUG 0x22 /* non existent CUG */
+#define CAUSE_1TR6_NECUG1 0x23 /* non existent CUG */
+#define CAUSE_1TR6_SPV 0x25 /* kommunikationsbeziehung als SPV nicht erlaubt */
+#define CAUSE_1TR6_DNO 0x35 /* destination not obtainable */
+#define CAUSE_1TR6_NC 0x38 /* number changed */
+#define CAUSE_1TR6_OOO 0x39 /* out of order */
+#define CAUSE_1TR6_NUR 0x3A /* no user responding */
+#define CAUSE_1TR6_UB 0x3B /* user busy */
+#define CAUSE_1TR6_ICB 0x3D /* incoming calls barred */
+#define CAUSE_1TR6_CR 0x3E /* call rejected */
+#define CAUSE_1TR6_NCO 0x59 /* network congestion */
+#define CAUSE_1TR6_RUI 0x5A /* remote user initiated */
+#define CAUSE_1TR6_LPE 0x70 /* local procedure error */
+#define CAUSE_1TR6_RPE 0x71 /* remote procedure error */
+#define CAUSE_1TR6_RUS 0x72 /* remote user suspended */
+#define CAUSE_1TR6_RUR 0x73 /* remote user resumed */
+#define CAUSE_1TR6_UIDL 0x7F /* user info discharded locally */
+
+/* EOF */
diff --git a/usr.sbin/i4b/isdntrace/pcause_q850.c b/usr.sbin/i4b/isdntrace/pcause_q850.c
new file mode 100644
index 0000000..1c98388
--- /dev/null
+++ b/usr.sbin/i4b/isdntrace/pcause_q850.c
@@ -0,0 +1,328 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * printing cause values
+ * ---------------------
+ *
+ * $Id: pcause_q850.c,v 1.4 1998/12/23 10:03:55 hm Exp $
+ *
+ * last edit-date: [Wed Dec 23 10:57:36 1998]
+ *
+ *---------------------------------------------------------------------------*/
+
+#include "trace.h"
+#include "pcause_q850.h"
+
+char *
+print_cause_q850(unsigned char code)
+{
+ static char error_message[120];
+ char *e;
+
+ switch(code)
+ {
+ case CAUSE_Q850_SHUTDN:
+ e = "normal D-channel shutdown";
+ break;
+
+ case CAUSE_Q850_NUNALLC:
+ e = "Unallocated (unassigned) number";
+ break;
+
+ case CAUSE_Q850_NRTTN:
+ e = "No route to specified transit network";
+ break;
+
+ case CAUSE_Q850_NRTDST:
+ e = "No route to destination";
+ break;
+
+ case CAUSE_Q850_SSINFTN:
+ e = "Send special information tone";
+ break;
+
+ case CAUSE_Q850_MDIALTP:
+ e = "Misdialled trunk prefix";
+ break;
+
+ case CAUSE_Q850_CHUNACC:
+ e = "Channel unacceptable";
+ break;
+
+ case CAUSE_Q850_CALLAWD:
+ e = "Call awarded and being delivered in an established channel";
+ break;
+
+ case CAUSE_Q850_PREEMPT:
+ e = "Preemption";
+ break;
+
+ case CAUSE_Q850_PREECRR:
+ e = "Preemption - circuit reserved for reuse";
+ break;
+
+ case CAUSE_Q850_NCCLR:
+ e = "Normal call clearing";
+ break;
+
+ case CAUSE_Q850_USRBSY:
+ e = "User busy";
+ break;
+
+ case CAUSE_Q850_NOUSRRSP:
+ e = "No user responding";
+ break;
+
+ case CAUSE_Q850_NOANSWR:
+ e = "No answer from user (user alerted)";
+ break;
+
+ case CAUSE_Q850_SUBSABS:
+ e = "Subscriber absent";
+ break;
+
+ case CAUSE_Q850_CALLREJ:
+ e = "Call rejected";
+ break;
+
+ case CAUSE_Q850_NUCHNG:
+ e = "Number changed";
+ break;
+
+ case CAUSE_Q850_NONSELUC:
+ e = "Non-selected user clearing";
+ break;
+
+ case CAUSE_Q850_DSTOOORDR:
+ e = "Destination out of order";
+ break;
+
+ case CAUSE_Q850_INVNUFMT:
+ e = "Invalid number format";
+ break;
+
+ case CAUSE_Q850_FACREJ:
+ e = "Facility rejected";
+ break;
+
+ case CAUSE_Q850_STENQRSP:
+ e = "Response to STATUS ENQUIRY";
+ break;
+
+ case CAUSE_Q850_NORMUNSP:
+ e = "Normal, unspecified";
+ break;
+
+ case CAUSE_Q850_NOCAVAIL:
+ e = "No circuit / channel available";
+ break;
+
+ case CAUSE_Q850_NETOOORDR:
+ e = "Network out of order";
+ break;
+
+ case CAUSE_Q850_PFMCDOOSERV:
+ e = "Permanent frame mode connection out of service";
+ break;
+
+ case CAUSE_Q850_PFMCOPER:
+ e = "Permanent frame mode connection operational";
+ break;
+
+ case CAUSE_Q850_TMPFAIL:
+ e = "Temporary failure";
+ break;
+
+ case CAUSE_Q850_SWEQCONG:
+ e = "Switching equipment congestion";
+ break;
+
+ case CAUSE_Q850_ACCINFDIS:
+ e = "Access information discarded";
+ break;
+
+ case CAUSE_Q850_REQCNOTAV:
+ e = "Requested circuit/channel not available";
+ break;
+
+ case CAUSE_Q850_PRECALBLK:
+ e = "Precedence call blocked";
+ break;
+
+ case CAUSE_Q850_RESUNAVAIL:
+ e = "Resources unavailable, unspecified";
+ break;
+
+ case CAUSE_Q850_QOSUNAVAIL:
+ e = "Quality of service unavailable";
+ break;
+
+ case CAUSE_Q850_REQSERVNS:
+ e = "Requested facility not subscribed";
+ break;
+
+ case CAUSE_Q850_OCBARRCUG:
+ e = "Outgoing calls barred within CUG";
+ break;
+
+ case CAUSE_Q850_ICBARRCUG:
+ e = "Incoming calls barred within CUG";
+ break;
+
+ case CAUSE_Q850_BCAPNAUTH:
+ e = "Bearer capability not authorized";
+ break;
+
+ case CAUSE_Q850_BCAPNAVAIL:
+ e = "Bearer capability not presently available";
+ break;
+
+ case CAUSE_Q850_INCSTOACISC:
+ e = "Inconsistenciy in designated outg. access info and subscriber class";
+ break;
+
+ case CAUSE_Q850_SOONOTAVAIL:
+ e = "Service or option not available, unspecified";
+ break;
+
+ case CAUSE_Q850_BCAPNOTIMPL:
+ e = "Bearer capability not implemented";
+ break;
+
+ case CAUSE_Q850_CHTYPNIMPL:
+ e = "Channel type not implemented";
+ break;
+
+ case CAUSE_Q850_REQFACNIMPL:
+ e = "Requested facility not implemented";
+ break;
+
+ case CAUSE_Q850_ORDINBCAVL:
+ e = "Only restricted digital information bearer capability is available";
+ break;
+
+ case CAUSE_Q850_SOONOTIMPL:
+ e = "Service or option not implemented, unspecified";
+ break;
+
+ case CAUSE_Q850_INVCLRFVAL:
+ e = "Invalid call reference value";
+ break;
+
+ case CAUSE_Q850_IDCHDNOEX:
+ e = "Identified channel does not exist";
+ break;
+
+ case CAUSE_Q850_SUSCAEXIN:
+ e = "A suspended call exists, but this call identity does not";
+ break;
+
+ case CAUSE_Q850_CLIDINUSE:
+ e = "Call identity in use";
+ break;
+
+ case CAUSE_Q850_NOCLSUSP:
+ e = "No call suspended";
+ break;
+
+ case CAUSE_Q850_CLIDCLRD:
+ e = "Call having the requested call identity has been cleared";
+ break;
+
+ case CAUSE_Q850_UNOTMEMCUG:
+ e = "User not member of CUG";
+ break;
+
+ case CAUSE_Q850_INCDEST:
+ e = "Incompatible destination";
+ break;
+
+ case CAUSE_Q850_NONEXCUG:
+ e = "Non-existent CUG";
+ break;
+
+ case CAUSE_Q850_INVNTWSEL:
+ e = "Invalid transit network selection";
+ break;
+
+ case CAUSE_Q850_INVMSG:
+ e = "Invalid message, unspecified";
+ break;
+
+ case CAUSE_Q850_MIEMISS:
+ e = "Mandatory information element is missing";
+ break;
+
+ case CAUSE_Q850_MSGTNI:
+ e = "Message type non-existent or not implemented";
+ break;
+
+ case CAUSE_Q850_MSGNCMPT:
+ e = "Msg incompatible with call state/message type non-existent/not implemented";
+ break;
+
+ case CAUSE_Q850_IENENI:
+ e = "Information element/parameter non-existent or not implemented";
+ break;
+
+ case CAUSE_Q850_INVIEC:
+ e = "Invalid information element contents";
+ break;
+
+ case CAUSE_Q850_MSGNCWCS:
+ e = "Message not compatible with call state";
+ break;
+
+ case CAUSE_Q850_RECOTIMEXP:
+ e = "Recovery on timer expiry";
+ break;
+
+ case CAUSE_Q850_PARMNENIPO:
+ e = "Parameter non-existent or not implemented, passed on";
+ break;
+
+ case CAUSE_Q850_MSGUNRDPRM:
+ e = "Message with unrecognized parameter, discarded";
+ break;
+
+ case CAUSE_Q850_PROTERR:
+ e = "Protocol error, unspecified";
+ break;
+
+ case CAUSE_Q850_INTWRKU:
+ e = "Interworking, unspecified";
+ break;
+
+ default:
+ e = "ERROR, unknown cause value!";
+ break;
+ }
+
+ sprintf(error_message, "%d: %s (Q.850)", code, e);
+ return(error_message);
+}
+
+/* EOF */
diff --git a/usr.sbin/i4b/isdntrace/pcause_q850.h b/usr.sbin/i4b/isdntrace/pcause_q850.h
new file mode 100644
index 0000000..a6b947f
--- /dev/null
+++ b/usr.sbin/i4b/isdntrace/pcause_q850.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * pcauseq850.h - Q.850 causes definitions
+ * ---------------------------------------
+ *
+ * $Id: pcause_q850.h,v 1.3 1998/12/05 18:04:18 hm Exp $
+ *
+ * last edit-date: [Sat Dec 5 18:20:05 1998]
+ *
+ *---------------------------------------------------------------------------*/
+
+char *print_cause_q850(unsigned char code);
+
+/* Q.850 causes */
+
+#define CAUSE_Q850_SHUTDN 0x00 /* normal D-channel shutdown */
+#define CAUSE_Q850_NUNALLC 0x01 /* Unallocated (unassigned) number */
+#define CAUSE_Q850_NRTTN 0x02 /* No route to specified transit network */
+#define CAUSE_Q850_NRTDST 0x03 /* No route to destination */
+#define CAUSE_Q850_SSINFTN 0x04 /* Send special information tone */
+#define CAUSE_Q850_MDIALTP 0x05 /* Misdialled trunk prefix */
+#define CAUSE_Q850_CHUNACC 0x06 /* Channel unacceptable */
+#define CAUSE_Q850_CALLAWD 0x07 /* Call awarded and being delivered in an established channel */
+#define CAUSE_Q850_PREEMPT 0x08 /* Preemption */
+#define CAUSE_Q850_PREECRR 0x09 /* Preemption - circuit reserved for reuse */
+#define CAUSE_Q850_NCCLR 0x10 /* Normal call clearing */
+#define CAUSE_Q850_USRBSY 0x11 /* User busy */
+#define CAUSE_Q850_NOUSRRSP 0x12 /* No user responding */
+#define CAUSE_Q850_NOANSWR 0x13 /* No answer from user (user alerted) */
+#define CAUSE_Q850_SUBSABS 0x14 /* Subscriber absent */
+#define CAUSE_Q850_CALLREJ 0x15 /* Call rejected */
+#define CAUSE_Q850_NUCHNG 0x16 /* Number changed */
+#define CAUSE_Q850_NONSELUC 0x1A /* Non-selected user clearing */
+#define CAUSE_Q850_DSTOOORDR 0x1B /* Destination out of order */
+#define CAUSE_Q850_INVNUFMT 0x1C /* Invalid number format */
+#define CAUSE_Q850_FACREJ 0x1D /* Facility rejected */
+#define CAUSE_Q850_STENQRSP 0x1E /* Response to STATUS ENQUIRY */
+#define CAUSE_Q850_NORMUNSP 0x1F /* Normal, unspecified */
+#define CAUSE_Q850_NOCAVAIL 0x22 /* No circuit / channel available */
+#define CAUSE_Q850_NETOOORDR 0x26 /* Network out of order */
+#define CAUSE_Q850_PFMCDOOSERV 0x27 /* Permanent frame mode connection out of service */
+#define CAUSE_Q850_PFMCOPER 0x28 /* Permanent frame mode connection operational */
+#define CAUSE_Q850_TMPFAIL 0x29 /* Temporary failure */
+#define CAUSE_Q850_SWEQCONG 0x2A /* Switching equipment congestion */
+#define CAUSE_Q850_ACCINFDIS 0x2B /* Access information discarded */
+#define CAUSE_Q850_REQCNOTAV 0x2C /* Requested circuit/channel not available */
+#define CAUSE_Q850_PRECALBLK 0x2E /* Precedence call blocked */
+#define CAUSE_Q850_RESUNAVAIL 0x2F /* Resources unavailable, unspecified */
+#define CAUSE_Q850_QOSUNAVAIL 0x31 /* Quality of service unavailable */
+#define CAUSE_Q850_REQSERVNS 0x32 /* Requested facility not subscribed */
+#define CAUSE_Q850_OCBARRCUG 0x35 /* Outgoing calls barred within CUG */
+#define CAUSE_Q850_ICBARRCUG 0x36 /* Incoming calls barred within CUG */
+#define CAUSE_Q850_BCAPNAUTH 0x39 /* Bearer capability not authorized */
+#define CAUSE_Q850_BCAPNAVAIL 0x3A /* Bearer capability not presently available */
+#define CAUSE_Q850_INCSTOACISC 0x3E /* Inconsistenciy in designated outgoing access information and subscriber class */
+#define CAUSE_Q850_SOONOTAVAIL 0x3F /* Service or option not available, unspecified */
+#define CAUSE_Q850_BCAPNOTIMPL 0x41 /* Bearer capability not implemented */
+#define CAUSE_Q850_CHTYPNIMPL 0x42 /* Channel type not implemented */
+#define CAUSE_Q850_REQFACNIMPL 0x45 /* Requested facility not implemented */
+#define CAUSE_Q850_ORDINBCAVL 0x46 /* Only restricted digital information bearer capability is available */
+#define CAUSE_Q850_SOONOTIMPL 0x4F /* Service or option not implemented, unspecified */
+#define CAUSE_Q850_INVCLRFVAL 0x51 /* Invalid call reference value */
+#define CAUSE_Q850_IDCHDNOEX 0x52 /* Identified channel does not exist */
+#define CAUSE_Q850_SUSCAEXIN 0x53 /* A suspended call exists, but this call identity does not */
+#define CAUSE_Q850_CLIDINUSE 0x54 /* Call identity in use */
+#define CAUSE_Q850_NOCLSUSP 0x55 /* No call suspended */
+#define CAUSE_Q850_CLIDCLRD 0x56 /* Call having the requested call identity has been cleared */
+#define CAUSE_Q850_UNOTMEMCUG 0x57 /* User not member of CUG */
+#define CAUSE_Q850_INCDEST 0x58 /* Incompatible destination */
+#define CAUSE_Q850_NONEXCUG 0x5A /* Non-existent CUG */
+#define CAUSE_Q850_INVNTWSEL 0x5B /* Invalid transit network selection */
+#define CAUSE_Q850_INVMSG 0x5F /* Invalid message, unspecified */
+#define CAUSE_Q850_MIEMISS 0x60 /* Mandatory information element is missing */
+#define CAUSE_Q850_MSGTNI 0x61 /* Message type non-existent or not implemented */
+#define CAUSE_Q850_MSGNCMPT 0x62 /* Message not compatible with call state or message type non-existent or not implemented */
+#define CAUSE_Q850_IENENI 0x63 /* Information element/parameter non-existent or not implemented */
+#define CAUSE_Q850_INVIEC 0x64 /* Invalid information element contents */
+#define CAUSE_Q850_MSGNCWCS 0x65 /* Message not compatible with call state */
+#define CAUSE_Q850_RECOTIMEXP 0x66 /* Recovery on timer expiry */
+#define CAUSE_Q850_PARMNENIPO 0x67 /* Parameter non-existent or not implemented, passed on */
+#define CAUSE_Q850_MSGUNRDPRM 0x6E /* Message with unrecognized parameter, discarded */
+#define CAUSE_Q850_PROTERR 0x6F /* Protocol error, unspecified */
+#define CAUSE_Q850_INTWRKU 0x7F /* Interworking, unspecified */
+
+/* EOF */
diff --git a/usr.sbin/i4b/isdntrace/q921.c b/usr.sbin/i4b/isdntrace/q921.c
new file mode 100644
index 0000000..df007a4
--- /dev/null
+++ b/usr.sbin/i4b/isdntrace/q921.c
@@ -0,0 +1,275 @@
+/*
+ * Copyright (c) 1996 Gary Jennejohn. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------*
+ *
+ * q.921.c - print Q.921 traces
+ * ----------------------------
+ *
+ * $Id: q921.c,v 1.2 1998/04/16 15:27:02 hm Exp $
+ *
+ * last edit-date: [Thu Apr 16 15:38:34 1998]
+ *
+ * -hm splitting
+ * -hm printing to buffer
+ * -hm slightly reformatted TEI management proc output
+ * -hm minor fixes
+ * -hm fixing response/command
+ * -hm fixing count off by one
+ * -hm dump only Q.921 part of frame
+ * -hm cleanup
+ *
+ *---------------------------------------------------------------------------*/
+
+#include "trace.h"
+
+/*---------------------------------------------------------------------------*
+ * decode LAPD (Q.921) protocol
+ *---------------------------------------------------------------------------*/
+int
+decode_lapd(char *pbuf, int n, unsigned char *buf, int dir, int raw, int printit)
+{
+ int sap, tei, cmd, p_f;
+ int cnt = 0;
+ int i;
+ char locbuf[32000];
+ char *lbufp = &locbuf[0];
+
+ *lbufp = '\0';
+ *pbuf = '\0';
+
+ sap = (buf[0] >> 2) & 0x3f;
+ cnt++;
+
+ tei = buf[1] >> 1;
+ cnt++;
+
+ if(dir == FROM_TE)
+ cmd = !(buf[0] & 2);
+ else
+ cmd = buf[0] & 2;
+
+ switch (sap)
+ {
+ /* SAPI control procedures */
+ case 0:
+ {
+ if(printit)
+ sprintf((lbufp+strlen(lbufp)), "Q921: SAP=%d (Call Control), %c, TEI=%d, ", sap, cmd?'C':'R', tei);
+
+ if((buf[2] & 0x01) == 0)
+ {
+ if(printit)
+ sprintf((lbufp+strlen(lbufp)), "I-Frame: ");
+
+ p_f = buf [3] & 1;
+
+ if(printit)
+ sprintf((lbufp+strlen(lbufp)), "N(S) %d N(R) %d P %d ", buf [2] >> 1, buf [3] >> 1, p_f);
+
+ cnt += 2;
+ }
+ else if((buf[2] & 0x03) == 0x01)
+ {
+ if(printit)
+ sprintf((lbufp+strlen(lbufp)), "S-Frame: ");
+
+ p_f = buf [3] & 1;
+ cmd = buf [2] & 0x0c;
+
+ if(printit)
+ {
+ if (cmd == 0)
+ sprintf((lbufp+strlen(lbufp)), "RR N(R) %d PF %d ", buf [3] >> 1, p_f);
+ if (cmd == 4)
+ sprintf((lbufp+strlen(lbufp)), "RNR N(R) %d PF %d ", buf [3] >> 1, p_f);
+ if (cmd == 8)
+ sprintf((lbufp+strlen(lbufp)), "REJ N(R) %d PF %d ", buf [3] >> 1, p_f);
+ }
+ cnt += 2;
+ }
+ else if((buf[2] & 0x03) == 0x03)
+ {
+ if(printit)
+ sprintf((lbufp+strlen(lbufp)), "U-Frame: ");
+
+ p_f = (buf [2] & 0x10) >> 4;
+ cmd = buf [2] & 0xec;
+
+ if(printit)
+ {
+ if (cmd == 0x6c)
+ sprintf((lbufp+strlen(lbufp)), "SABME PF %d ", p_f);
+ if (cmd == 0x0c)
+ sprintf((lbufp+strlen(lbufp)), "DM PF %d ", p_f);
+ if (cmd == 0)
+ sprintf((lbufp+strlen(lbufp)), "UI PF %d ", p_f);
+ if (cmd == 0x40)
+ sprintf((lbufp+strlen(lbufp)), "DISC PF %d ", p_f);
+ if (cmd == 0x60)
+ sprintf((lbufp+strlen(lbufp)), "UA PF %d ", p_f);
+ if (cmd == 0x84)
+ sprintf((lbufp+strlen(lbufp)), "FRMR PF %d ", p_f);
+ if (cmd == 0xac)
+ sprintf((lbufp+strlen(lbufp)), "XID PF %d ", p_f);
+ /* information field ??? */
+ }
+ cnt++;
+ }
+ break;
+ }
+
+ /* D channel X.25 */
+
+ case 16:
+ if(printit)
+ sprintf((lbufp+strlen(lbufp)), "Q921: SAP=%d (X.25), %c, TEI=%d, ", sap, cmd?'C':'R', tei);
+ cnt = n;
+ goto dump;
+
+ /* Loopback test */
+
+ case 32:
+ if(printit)
+ sprintf((lbufp+strlen(lbufp)), "Q921: SAP=%d (Loopbacktest), %c, TEI=%d, ", sap, cmd?'C':'R', tei);
+ cnt = n;
+ goto dump;
+
+ /* SAPI layer 2 management functions */
+
+ case 63:
+ {
+ if(printit)
+ sprintf((lbufp+strlen(lbufp)), "Q921: SAP=%d (TEI-Management), %c, TEI=%d, ", sap, cmd?'C':'R', tei);
+
+ if (tei != 127)
+ {
+ if(printit)
+ sprintf((lbufp+strlen(lbufp)), "ILLEGAL TEI\n");
+ cnt = n;
+ goto dump;
+ }
+
+ if (buf [2] != 3 && buf [3] != 0xf)
+ {
+ if(printit)
+ sprintf((lbufp+strlen(lbufp)), "invalid format!\n");
+ cnt = n;
+ goto dump;
+ }
+ cnt+= 2; /* UI + MEI */
+
+ if(printit)
+ sprintf((lbufp+strlen(lbufp)), "Ri=0x%04hx, ", *(short *)&buf[4]);
+ cnt += 2; /* Ri */
+
+ switch (buf[6])
+ {
+ case 1:
+ if(printit)
+ sprintf((lbufp+strlen(lbufp)), "IdRequest, Ai=%d", (buf [7] >> 1));
+ cnt += 2;
+ break;
+ case 2:
+ if(printit)
+ sprintf((lbufp+strlen(lbufp)), "IdAssign, Ai=%d", (buf [7] >> 1));
+ cnt += 2;
+ break;
+ case 3:
+ if(printit)
+ sprintf((lbufp+strlen(lbufp)), "IdDenied, Ai=%d", (buf [7] >> 1));
+ cnt += 2;
+ break;
+ case 4:
+ if(printit)
+ sprintf((lbufp+strlen(lbufp)), "IdCheckReq, Ai=%d", (buf [7] >> 1));
+ cnt += 2;
+ break;
+ case 5:
+ if(printit)
+ sprintf((lbufp+strlen(lbufp)), "IdCheckResp, Ai=%d", (buf [7] >> 1));
+ cnt += 2;
+ break;
+ case 6:
+ if(printit)
+ sprintf((lbufp+strlen(lbufp)), "IdRemove, Ai=%d", (buf [7] >> 1));
+ cnt += 2;
+ break;
+ case 7:
+ if(printit)
+ sprintf((lbufp+strlen(lbufp)), "IdVerify, Ai=%d", (buf [7] >> 1));
+ cnt += 2;
+ break;
+ default:
+ if(printit)
+ sprintf((lbufp+strlen(lbufp)), "Unknown Msg Type\n");
+ cnt = n;
+ goto dump;
+ }
+ break;
+ }
+
+ /* Illegal SAPI */
+
+ default:
+ if(printit)
+ sprintf((lbufp+strlen(lbufp)), "Q921: ERROR, SAP=%d (Illegal SAPI), %c, TEI=%d\n", sap, cmd?'C':'R', tei);
+ cnt = n;
+ goto dump;
+ }
+
+dump:
+ if(printit)
+ sprintf((lbufp+strlen(lbufp)), "\n");
+
+ if(raw && printit)
+ {
+ int j;
+ for (i = 0; i < cnt; i += 16)
+ {
+ sprintf((pbuf+strlen(pbuf)),"Dump:%.3d ", i);
+ for (j = 0; j < 16; j++)
+ if (i + j < cnt)
+ sprintf((pbuf+strlen(pbuf)),"%02x ", buf[i + j]);
+ else
+ sprintf((pbuf+strlen(pbuf))," ");
+ sprintf((pbuf+strlen(pbuf))," ");
+ for (j = 0; j < 16 && i + j < cnt; j++)
+ if (isprint(buf[i + j]))
+ sprintf((pbuf+strlen(pbuf)),"%c", buf[i + j]);
+ else
+ sprintf((pbuf+strlen(pbuf)),".");
+ sprintf((pbuf+strlen(pbuf)),"\n");
+ }
+ }
+
+ sprintf((pbuf+strlen(pbuf)),"%s", &locbuf[0]);
+
+ return (cnt);
+}
+
+/* EOF */
diff --git a/usr.sbin/i4b/isdntrace/q931.c b/usr.sbin/i4b/isdntrace/q931.c
new file mode 100644
index 0000000..3cc2a38
--- /dev/null
+++ b/usr.sbin/i4b/isdntrace/q931.c
@@ -0,0 +1,783 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * q931.c - print Q.931 traces
+ * ---------------------------
+ *
+ * $Id: q931.c,v 1.4 1998/12/05 18:04:19 hm Exp $
+ *
+ * last edit-date: [Sat Dec 5 18:20:31 1998]
+ *
+ *---------------------------------------------------------------------------*/
+
+#include "trace.h"
+
+/*---------------------------------------------------------------------------*
+ * decode Q.931 protocol
+ *---------------------------------------------------------------------------*/
+void
+decode_q931(char *pbuf, int n, int off, unsigned char *buf, int raw)
+{
+ int codeset = 0;
+ int codelock = 0;
+ int oldcodeset = 0;
+
+ int pd;
+ int len;
+ int j;
+ int i;
+
+ if(n <= 0)
+ return;
+
+ *pbuf = '\0';
+
+ if(raw)
+ {
+
+ for (i = 0; i < n; i += 16)
+ {
+ sprintf((pbuf+strlen(pbuf)),"Dump:%.3d ", i+off);
+ for (j = 0; j < 16; j++)
+ if (i + j < n)
+ sprintf((pbuf+strlen(pbuf)),"%02x ", buf[i + j]);
+ else
+ sprintf((pbuf+strlen(pbuf))," ");
+ sprintf((pbuf+strlen(pbuf))," ");
+ for (j = 0; j < 16 && i + j < n; j++)
+ if (isprint(buf[i + j]))
+ sprintf((pbuf+strlen(pbuf)),"%c", buf[i + j]);
+ else
+ sprintf((pbuf+strlen(pbuf)),".");
+ sprintf((pbuf+strlen(pbuf)),"\n");
+ }
+ }
+
+ i = 0;
+
+ sprintf((pbuf+strlen(pbuf)), "Q931: ");
+
+ /* protocol discriminator */
+
+ pd = buf[i];
+
+ if(pd >= 0x00 && pd <= 0x07)
+ sprintf((pbuf+strlen(pbuf)), "pd=User-User (0x%02x), ",pd);
+ else if(pd == 0x08)
+ sprintf((pbuf+strlen(pbuf)), "pd=Q.931/I.451, ");
+ else if(pd >= 0x10 && pd <= 0x3f)
+ sprintf((pbuf+strlen(pbuf)), "pd=Other Layer 3 or X.25 (0x%02x), ",pd);
+ else if(pd >= 0x40 && pd <= 0x4f)
+ sprintf((pbuf+strlen(pbuf)), "pd=National Use (0x%02x), ",pd);
+ else if(pd >= 0x50 && pd <= 0xfe)
+ sprintf((pbuf+strlen(pbuf)), "pd=Other Layer 3 or X.25 (0x%02x), ",pd);
+ else
+ sprintf((pbuf+strlen(pbuf)), "pd=Reserved (0x%02x), ",pd);
+
+ /* call reference */
+
+ i++;
+
+ len = buf[i] & 0x0f;
+
+ switch(len)
+ {
+ case 0:
+ sprintf((pbuf+strlen(pbuf)), "cr=Dummy, ");
+ break;
+ case 1:
+ sprintf((pbuf+strlen(pbuf)), "cr=0x%02x %s, ", (buf[i+1] & 0x7f), (buf[i+1] & 0x80) ? "(from destination)" : "(from origination)");
+ break;
+ case 2:
+ sprintf((pbuf+strlen(pbuf)), "cr=0x%02x 0x%02x %s, ", (buf[i+1] & 0x7f), (buf[i+2] & 0x7f), (buf[i+1] & 0x80) ? "(org)" : "(dst)");
+ break;
+ }
+
+ i += (len+1);
+
+ /* message type */
+
+ sprintf((pbuf+strlen(pbuf)), "message=");
+
+ switch(buf[i])
+ {
+ /* escape to nationally specific message type */
+
+ case 0x00:
+ sprintf((pbuf+strlen(pbuf)), "ESCAPE: ");
+ break;
+
+ /* call establishment */
+
+ case 0x01:
+ sprintf((pbuf+strlen(pbuf)), "ALERTING: ");
+ break;
+ case 0x02:
+ sprintf((pbuf+strlen(pbuf)), "CALL PROCEEDING: ");
+ break;
+ case 0x03:
+ sprintf((pbuf+strlen(pbuf)), "PROGRESS: ");
+ break;
+ case 0x05:
+ sprintf((pbuf+strlen(pbuf)), "SETUP: ");
+ break;
+ case 0x07:
+ sprintf((pbuf+strlen(pbuf)), "CONNECT: ");
+ break;
+ case 0x0d:
+ sprintf((pbuf+strlen(pbuf)), "SETUP ACKNOWLEDGE: ");
+ break;
+ case 0x0f:
+ sprintf((pbuf+strlen(pbuf)), "CONNECT ACKNOWLEDGE: ");
+ break;
+
+ /* call information phase */
+
+ case 0x20:
+ sprintf((pbuf+strlen(pbuf)), "USER INFORMATION: ");
+ break;
+ case 0x21:
+ sprintf((pbuf+strlen(pbuf)), "SUSPEND REJECT: ");
+ break;
+ case 0x22:
+ sprintf((pbuf+strlen(pbuf)), "RESUME REJECT: ");
+ break;
+ case 0x24:
+ sprintf((pbuf+strlen(pbuf)), "HOLD (Q.932): ");
+ break;
+ case 0x25:
+ sprintf((pbuf+strlen(pbuf)), "SUSPEND: ");
+ break;
+ case 0x26:
+ sprintf((pbuf+strlen(pbuf)), "RESUME: ");
+ break;
+ case 0x28:
+ sprintf((pbuf+strlen(pbuf)), "HOLD ACKNOWLEDGE (Q.932): ");
+ break;
+ case 0x2d:
+ sprintf((pbuf+strlen(pbuf)), "SUSPEND ACKNOWLEDGE: ");
+ break;
+ case 0x2e:
+ sprintf((pbuf+strlen(pbuf)), "RESUME ACKNOWLEDGE: ");
+ break;
+ case 0x30:
+ sprintf((pbuf+strlen(pbuf)), "HOLD REJECT (Q.932): ");
+ break;
+ case 0x31:
+ sprintf((pbuf+strlen(pbuf)), "RETRIEVE (Q.932): ");
+ break;
+ case 0x32:
+ sprintf((pbuf+strlen(pbuf)), "RETRIEVE ACKNOWLEDGE (Q.932): ");
+ break;
+ case 0x37:
+ sprintf((pbuf+strlen(pbuf)), "RETRIEVE REJECT (Q.932): ");
+ break;
+
+ /* call clearing */
+
+ case 0x40:
+ sprintf((pbuf+strlen(pbuf)), "DETACH: ");
+ break;
+ case 0x45:
+ sprintf((pbuf+strlen(pbuf)), "DISCONNECT: ");
+ break;
+ case 0x46:
+ sprintf((pbuf+strlen(pbuf)), "RESTART: ");
+ break;
+ case 0x48:
+ sprintf((pbuf+strlen(pbuf)), "DETACH ACKNOWLEDGE: ");
+ break;
+ case 0x4d:
+ sprintf((pbuf+strlen(pbuf)), "RELEASE: ");
+ break;
+ case 0x4e:
+ sprintf((pbuf+strlen(pbuf)), "RESTART ACKNOWLEDGE: ");
+ break;
+ case 0x5a:
+ sprintf((pbuf+strlen(pbuf)), "RELEASE COMPLETE: ");
+ break;
+
+ /* misc messages */
+
+ case 0x60:
+ sprintf((pbuf+strlen(pbuf)), "SEGMENT: ");
+ break;
+ case 0x62:
+ sprintf((pbuf+strlen(pbuf)), "FACILITY (Q.932): ");
+ break;
+ case 0x64:
+ sprintf((pbuf+strlen(pbuf)), "REGISTER (Q.932): ");
+ break;
+ case 0x68:
+ sprintf((pbuf+strlen(pbuf)), "CANCEL ACKNOWLEDGE: ");
+ break;
+ case 0x6a:
+ sprintf((pbuf+strlen(pbuf)), "FACILITY ACKNOWLEDGE: ");
+ break;
+ case 0x6c:
+ sprintf((pbuf+strlen(pbuf)), "REGISTER ACKNOWLEDGE: ");
+ break;
+ case 0x6e:
+ sprintf((pbuf+strlen(pbuf)), "NOTIFY: ");
+ break;
+ case 0x70:
+ sprintf((pbuf+strlen(pbuf)), "CANCEL REJECT: ");
+ break;
+ case 0x72:
+ sprintf((pbuf+strlen(pbuf)), "FACILITY REJECT: ");
+ break;
+ case 0x74:
+ sprintf((pbuf+strlen(pbuf)), "REGISTER REJECT: ");
+ break;
+ case 0x75:
+ sprintf((pbuf+strlen(pbuf)), "STATUS ENQIRY: ");
+ break;
+ case 0x79:
+ sprintf((pbuf+strlen(pbuf)), "CONGESTION CONTROL: ");
+ break;
+ case 0x7b:
+ sprintf((pbuf+strlen(pbuf)), "INFORMATION: ");
+ break;
+ case 0x7d:
+ sprintf((pbuf+strlen(pbuf)), "STATUS: ");
+ break;
+ default:
+ sprintf((pbuf+strlen(pbuf)), "UNDEFINED, TYPE=0x%02x, ", buf[i]);
+ break;
+ }
+
+ /* other information elements */
+
+ i++;
+
+ for (; i < n;)
+ {
+ sprintf((pbuf+strlen(pbuf)), "\n ");
+
+ if(buf[i] & 0x80)
+ {
+ /* single octett info element */
+
+ switch(buf[i] & 0x70)
+ {
+ case 0x00: /* reserved */
+ sprintf((pbuf+strlen(pbuf)), "[reserved single octett info]");
+ break;
+
+ case 0x10: /* shift */
+ oldcodeset = codeset;
+ codeset = buf[i] & 0x07;
+ if(buf[i] & 0x08)
+ codelock = 0;
+ else
+ codelock = 1;
+ sprintf((pbuf+strlen(pbuf)), "[shift: codeset=%d lock=%d]", codeset, codelock);
+ break;
+
+ case 0x20: /* more data */
+ if(buf[i] & 0x01)
+ sprintf((pbuf+strlen(pbuf)), "[sending complete]");
+ else
+ sprintf((pbuf+strlen(pbuf)), "[more data]");
+ break;
+
+ case 0x30: /* congestion level */
+ sprintf((pbuf+strlen(pbuf)), "[congestion level=");
+ switch(buf[i] & 0x0f)
+ {
+ case 0x00:
+ sprintf((pbuf+strlen(pbuf)), "rx-ready]");
+ break;
+ case 0x0f:
+ sprintf((pbuf+strlen(pbuf)), "rx-not-ready]");
+ break;
+ default:
+ sprintf((pbuf+strlen(pbuf)), "reserved (0x%02x)]", buf[i] & 0x0f);
+ break;
+ }
+ break;
+
+ case 0x50: /* repeat ind */
+ sprintf((pbuf+strlen(pbuf)), "[repeat indicator]");
+ break;
+
+ default:
+ sprintf((pbuf+strlen(pbuf)), "[UNKNOWN SINGLE OCTET ELEMENT 0x%02x]", buf[i]);
+ break;
+ }
+
+ i++; /* next */
+
+ }
+ else
+ {
+ /* variable length info element */
+
+ if(codeset == 0)
+ {
+ switch(buf[i])
+ {
+ case 0x00:
+ sprintf((pbuf+strlen(pbuf)), "[segmented message: ");
+ break;
+ case 0x04:
+ sprintf((pbuf+strlen(pbuf)), "[bearer capability: ");
+ i += p_q931bc(pbuf, &buf[i]);
+ goto next;
+ break;
+ case 0x08:
+ sprintf((pbuf+strlen(pbuf)), "[cause: ");
+ i += p_q931cause(pbuf, &buf[i]);
+ goto next;
+ break;
+ case 0x0c:
+ sprintf((pbuf+strlen(pbuf)), "[connected address (old): ");
+ break;
+ case 0x0d:
+ sprintf((pbuf+strlen(pbuf)), "[extended facility (Q.932: )");
+ break;
+ case 0x10:
+ sprintf((pbuf+strlen(pbuf)), "[call identity: ");
+ break;
+ case 0x14:
+ sprintf((pbuf+strlen(pbuf)), "[call state: ");
+ i++;
+ len = buf[i];
+ i++;
+ sprintf((pbuf+strlen(pbuf)), "Std=");
+ switch((buf[i] & 0x60) >> 5)
+ {
+ case 0:
+ sprintf((pbuf+strlen(pbuf)), "CCITT");
+ break;
+ case 1:
+ sprintf((pbuf+strlen(pbuf)), "ISO/IEC");
+ break;
+ case 2:
+ sprintf((pbuf+strlen(pbuf)), "National");
+ break;
+ case 3:
+ sprintf((pbuf+strlen(pbuf)), "Special");
+ break;
+ }
+ sprintf((pbuf+strlen(pbuf)), ", State=");
+
+ switch((buf[i] & 0x3f))
+ {
+ case 0:
+ sprintf((pbuf+strlen(pbuf)), "Null");
+ break;
+ case 1:
+ sprintf((pbuf+strlen(pbuf)), "Call initiated");
+ break;
+ case 2:
+ sprintf((pbuf+strlen(pbuf)), "Overlap sending");
+ break;
+ case 3:
+ sprintf((pbuf+strlen(pbuf)), "Outgoing call proceeding");
+ break;
+ case 4:
+ sprintf((pbuf+strlen(pbuf)), "Call delivered");
+ break;
+ case 6:
+ sprintf((pbuf+strlen(pbuf)), "Call present");
+ break;
+ case 7:
+ sprintf((pbuf+strlen(pbuf)), "Call received");
+ break;
+ case 8:
+ sprintf((pbuf+strlen(pbuf)), "Connect request");
+ break;
+ case 9:
+ sprintf((pbuf+strlen(pbuf)), "Incoming call proceeding");
+ break;
+ case 10:
+ sprintf((pbuf+strlen(pbuf)), "Active");
+ break;
+ case 11:
+ sprintf((pbuf+strlen(pbuf)), "Disconnect request");
+ break;
+ case 12:
+ sprintf((pbuf+strlen(pbuf)), "Disconnect indication");
+ break;
+ case 15:
+ sprintf((pbuf+strlen(pbuf)), "Suspend request");
+ break;
+ case 17:
+ sprintf((pbuf+strlen(pbuf)), "Resume request");
+ break;
+ case 19:
+ sprintf((pbuf+strlen(pbuf)), "Release request");
+ break;
+ case 22:
+ sprintf((pbuf+strlen(pbuf)), "Call abort");
+ break;
+ case 25:
+ sprintf((pbuf+strlen(pbuf)), "Overlap receiving");
+ break;
+ case 0x3d:
+ sprintf((pbuf+strlen(pbuf)), "Restart request");
+ break;
+ case 0x3e:
+ sprintf((pbuf+strlen(pbuf)), "Restart");
+ break;
+ default:
+ sprintf((pbuf+strlen(pbuf)), "ERROR: undefined/reserved");
+ break;
+ }
+ sprintf((pbuf+strlen(pbuf)), "]");
+ i++;
+ goto next;
+ break;
+ case 0x18:
+ sprintf((pbuf+strlen(pbuf)), "[channel id: channel=");
+ i++;
+ len = buf[i];
+ i++;
+ switch(buf[i] & 0x03)
+ {
+ case 0:
+ sprintf((pbuf+strlen(pbuf)), "no channel");
+ break;
+ case 1:
+ sprintf((pbuf+strlen(pbuf)), "B-1");
+ break;
+ case 2:
+ sprintf((pbuf+strlen(pbuf)), "B-2");
+ break;
+ case 3:
+ sprintf((pbuf+strlen(pbuf)), "any channel");
+ break;
+ }
+ if(buf[i] & 0x08)
+ sprintf((pbuf+strlen(pbuf)), " (exclusive)]");
+ else
+ sprintf((pbuf+strlen(pbuf)), " (preferred)]");
+ i++;
+ goto next;
+ break;
+ case 0x19:
+ sprintf((pbuf+strlen(pbuf)), "[data link connection id (Q.933): ");
+ break;
+ case 0x1c:
+ i += q932_facility(pbuf, &buf[i]);
+ goto next;
+ break;
+ case 0x1e:
+ sprintf((pbuf+strlen(pbuf)), "[progress ind: ");
+ i++;
+ len = buf[i];
+ i++;
+ sprintf((pbuf+strlen(pbuf)), "Std=");
+ switch((buf[i] & 0x60) >> 5)
+ {
+ case 0:
+ sprintf((pbuf+strlen(pbuf)), "CCITT");
+ break;
+ case 1:
+ sprintf((pbuf+strlen(pbuf)), "ISO/IEC");
+ break;
+ case 2:
+ sprintf((pbuf+strlen(pbuf)), "National");
+ break;
+ case 3:
+ sprintf((pbuf+strlen(pbuf)), "Local");
+ break;
+ }
+ sprintf((pbuf+strlen(pbuf)), ", Loc=");
+
+ switch((buf[i] & 0x0f))
+ {
+ case 0:
+ sprintf((pbuf+strlen(pbuf)), "User");
+ break;
+ case 1:
+ sprintf((pbuf+strlen(pbuf)), "Private network serving local user");
+ break;
+ case 2:
+ sprintf((pbuf+strlen(pbuf)), "Public network serving local user");
+ break;
+ case 3:
+ sprintf((pbuf+strlen(pbuf)), "Transit network");
+ break;
+ case 4:
+ sprintf((pbuf+strlen(pbuf)), "Public network serving remote user");
+ break;
+ case 5:
+ sprintf((pbuf+strlen(pbuf)), "Private network serving remote user");
+ break;
+ case 6:
+ sprintf((pbuf+strlen(pbuf)), "Network beyond interworking point");
+ break;
+ default:
+ sprintf((pbuf+strlen(pbuf)), "ERROR: undefined/reserved");
+ break;
+ }
+
+ i++;
+
+ sprintf((pbuf+strlen(pbuf)), "\n Description: ");
+
+ switch((buf[i] & 0x7f))
+ {
+ case 1:
+ sprintf((pbuf+strlen(pbuf)), "Call is not end-to-end ISDN");
+ break;
+ case 2:
+ sprintf((pbuf+strlen(pbuf)), "Destination address is non-ISDN");
+ break;
+ case 3:
+ sprintf((pbuf+strlen(pbuf)), "Origination address is non-ISDN");
+ break;
+ case 4:
+ sprintf((pbuf+strlen(pbuf)), "Call has returned to the ISDN");
+ break;
+ case 5:
+ sprintf((pbuf+strlen(pbuf)), "Interworking occured, Service change");
+ break;
+ case 8:
+ sprintf((pbuf+strlen(pbuf)), "In-band info or appropriate pattern now available");
+ break;
+ default:
+ sprintf((pbuf+strlen(pbuf)), "ERROR: undefined/reserved");
+ break;
+ }
+ sprintf((pbuf+strlen(pbuf)), "]");
+ i++;
+ goto next;
+ break;
+ case 0x20:
+ sprintf((pbuf+strlen(pbuf)), "[network specific facilities: ");
+ break;
+ case 0x24:
+ sprintf((pbuf+strlen(pbuf)), "[terminal capabilities: ");
+ break;
+ case 0x27:
+ sprintf((pbuf+strlen(pbuf)), "[notification ind: ");
+ break;
+ case 0x28:
+ sprintf((pbuf+strlen(pbuf)), "[display: ");
+ i++;
+ len = buf[i];
+ i++;
+ for(j = 0; j < len; j++)
+ {
+ sprintf((pbuf+strlen(pbuf)),"%c", buf[j+i]);
+ }
+ sprintf((pbuf+strlen(pbuf)),"]");
+ i += j;
+ goto next;
+ break;
+ case 0x29:
+ sprintf((pbuf+strlen(pbuf)), "[date/time: ");
+ i++;
+ len = buf[i];
+ i++;
+ j = 0;
+ sprintf((pbuf+strlen(pbuf)),"%.2d.%.2d.%.2d",
+ buf[i+2], buf[i+1], buf[i]);
+ j+=3;
+ if(j < len)
+ {
+ sprintf((pbuf+strlen(pbuf))," %.2d", buf[i+3]);
+ j++;
+ }
+ if(j < len)
+ {
+ sprintf((pbuf+strlen(pbuf)),":%.2d", buf[i+4]);
+ j++;
+ }
+ if(j < len)
+ {
+ sprintf((pbuf+strlen(pbuf)),":%.2d", buf[i+5]);
+ j++;
+ }
+ sprintf((pbuf+strlen(pbuf)),"]");
+ i += len;
+ goto next;
+ break;
+ case 0x2c:
+ sprintf((pbuf+strlen(pbuf)), "[keypad: ");
+ break;
+ case 0x30:
+ sprintf((pbuf+strlen(pbuf)), "[keypad echo: ");
+ break;
+ case 0x32:
+ sprintf((pbuf+strlen(pbuf)), "[information req (Q.932): ");
+ break;
+ case 0x34:
+ sprintf((pbuf+strlen(pbuf)), "[signal: ");
+ break;
+ case 0x36:
+ sprintf((pbuf+strlen(pbuf)), "[switchhook: ");
+ break;
+ case 0x38:
+ sprintf((pbuf+strlen(pbuf)), "[feature activation (Q.932): ");
+ break;
+ case 0x39:
+ sprintf((pbuf+strlen(pbuf)), "[feature ind (Q.932): ");
+ break;
+ case 0x3a:
+ sprintf((pbuf+strlen(pbuf)), "[service profile id (Q.932): ");
+ break;
+ case 0x3b:
+ sprintf((pbuf+strlen(pbuf)), "[endpoint id (Q.932): ");
+ break;
+ case 0x40:
+ sprintf((pbuf+strlen(pbuf)), "[information rate: ");
+ break;
+ case 0x41:
+ sprintf((pbuf+strlen(pbuf)), "[precedence level (Q.955): ");
+ break;
+ case 0x42:
+ sprintf((pbuf+strlen(pbuf)), "[end-to-end transit delay: ");
+ break;
+ case 0x43:
+ sprintf((pbuf+strlen(pbuf)), "[transit delay detection and indication: ");
+ break;
+ case 0x44:
+ sprintf((pbuf+strlen(pbuf)), "[packet layer binary parameters: ");
+ break;
+ case 0x45:
+ sprintf((pbuf+strlen(pbuf)), "[packet layer window size: ");
+ break;
+ case 0x46:
+ sprintf((pbuf+strlen(pbuf)), "[packet size: ");
+ break;
+ case 0x47:
+ sprintf((pbuf+strlen(pbuf)), "[closed user group: ");
+ break;
+ case 0x48:
+ sprintf((pbuf+strlen(pbuf)), "[link layer core parameters (Q.933): ");
+ break;
+ case 0x49:
+ sprintf((pbuf+strlen(pbuf)), "[link layer protocol parameters (Q.933): ");
+ break;
+ case 0x4a:
+ sprintf((pbuf+strlen(pbuf)), "[reverse charging information: ");
+ break;
+ case 0x4c:
+ sprintf((pbuf+strlen(pbuf)), "[connected number (Q.951): ");
+ i += p_q931address(pbuf, &buf[i]);
+ goto next;
+ break;
+
+ break;
+ case 0x4d:
+ sprintf((pbuf+strlen(pbuf)), "[connected subaddress (Q.951): ");
+ break;
+ case 0x50:
+ sprintf((pbuf+strlen(pbuf)), "[X.213 priority (Q.933): ");
+ break;
+ case 0x51:
+ sprintf((pbuf+strlen(pbuf)), "[report type (Q.933): ");
+ break;
+ case 0x53:
+ sprintf((pbuf+strlen(pbuf)), "[link integrity verification (Q.933): ");
+ break;
+ case 0x57:
+ sprintf((pbuf+strlen(pbuf)), "[PVC status (Q.933): ");
+ break;
+ case 0x6c:
+ sprintf((pbuf+strlen(pbuf)), "[calling party number: ");
+ i += p_q931address(pbuf, &buf[i]);
+ goto next;
+ break;
+ case 0x6d:
+ sprintf((pbuf+strlen(pbuf)), "[calling party subaddress: ");
+ break;
+ case 0x70:
+ sprintf((pbuf+strlen(pbuf)), "[called party number: ");
+ i += p_q931address(pbuf, &buf[i]);
+ goto next;
+ break;
+ case 0x71:
+ sprintf((pbuf+strlen(pbuf)), "[called party subaddress: ");
+ break;
+ case 0x74:
+ sprintf((pbuf+strlen(pbuf)), "[redirecting number: ");
+ break;
+ case 0x76:
+ sprintf((pbuf+strlen(pbuf)), "[redirection number: ");
+ break;
+ case 0x78:
+ sprintf((pbuf+strlen(pbuf)), "[transit network selection: ");
+ break;
+ case 0x79:
+ sprintf((pbuf+strlen(pbuf)), "[restart indicator: ");
+ break;
+ case 0x7c:
+ sprintf((pbuf+strlen(pbuf)), "[low layer compatibility: ");
+ break;
+ case 0x7d:
+ sprintf((pbuf+strlen(pbuf)), "[high layer compatibility:");
+ i += p_q931high_compat(pbuf, &buf[i]);
+ goto next;
+ break;
+ case 0x7e:
+ sprintf((pbuf+strlen(pbuf)), "[user-user: ");
+ break;
+ case 0x7f:
+ sprintf((pbuf+strlen(pbuf)), "[escape for extension: ");
+ break;
+ default:
+ sprintf((pbuf+strlen(pbuf)), "[UNKNOWN INFO-ELEMENT-ID=0x%02x: ", buf[i]);
+ break;
+ }
+ }
+ else
+ {
+ sprintf((pbuf+strlen(pbuf)), "[UNKNOWN CODESET=%d, IE=0x%02x: ", codeset, buf[i]);
+ }
+
+ i++; /* index -> length */
+
+ len = buf[i];
+
+ sprintf((pbuf+strlen(pbuf)), "LEN=0x%02x, DATA=", len);
+
+ i++; /* index -> 1st param */
+
+ for(j = 0; j < len; j++)
+ {
+ sprintf((pbuf+strlen(pbuf)),"0x%02x ", buf[j+i]);
+ }
+
+ sprintf((pbuf+strlen(pbuf)),"]");
+
+ i += len;
+
+next:
+
+ if(!codelock && (codeset != oldcodeset))
+ codeset = oldcodeset;
+ }
+ }
+ sprintf((pbuf+strlen(pbuf)),"\n");
+}
+
+/* EOF */
+
diff --git a/usr.sbin/i4b/isdntrace/q931_util.c b/usr.sbin/i4b/isdntrace/q931_util.c
new file mode 100644
index 0000000..1b2ab09
--- /dev/null
+++ b/usr.sbin/i4b/isdntrace/q931_util.c
@@ -0,0 +1,697 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * q931_util.c - utility functions to print Q.931 traces
+ * -----------------------------------------------------
+ *
+ * $Id: q931_util.c,v 1.4 1998/12/05 18:04:21 hm Exp $
+ *
+ * last edit-date: [Sat Dec 5 18:20:43 1998]
+ *
+ *---------------------------------------------------------------------------*/
+
+#include "trace.h"
+
+/*---------------------------------------------------------------------------*
+ * decode and print the cause
+ *---------------------------------------------------------------------------*/
+int
+p_q931cause(char *pbuf, unsigned char *buf)
+{
+ int j;
+ int len;
+ int i = 0;
+ int ls;
+ int r = 0;
+ int rflag = 0;
+
+ i++; /* index -> length */
+
+ len = buf[i];
+
+ i++; /* coding/location */
+ len--;
+
+ ls = buf[i];
+
+ i++;
+ len--;
+
+ if(!(buf[i-1] & 0x80))
+ {
+ r = buf[i];
+ rflag = 1;
+ i++;
+ len--;
+ }
+
+ sprintf((pbuf+strlen(pbuf)), "%s ", print_cause_q850(buf[i] & 0x7f));
+
+ sprintf((pbuf+strlen(pbuf)), "\n (location=");
+
+ switch(ls & 0x0f)
+ {
+ case 0x00:
+ sprintf((pbuf+strlen(pbuf)), "user");
+ break;
+ case 0x01:
+ sprintf((pbuf+strlen(pbuf)), "private network serving local user");
+ break;
+ case 0x02:
+ sprintf((pbuf+strlen(pbuf)), "public network serving local user");
+ break;
+ case 0x03:
+ sprintf((pbuf+strlen(pbuf)), "transit network");
+ break;
+ case 0x04:
+ sprintf((pbuf+strlen(pbuf)), "public network serving remote user");
+ break;
+ case 0x05:
+ sprintf((pbuf+strlen(pbuf)), "private network serving remote user");
+ break;
+ case 0x07:
+ sprintf((pbuf+strlen(pbuf)), "international network");
+ break;
+ case 0x0a:
+ sprintf((pbuf+strlen(pbuf)), "network beyond interworking point");
+ break;
+ default:
+ sprintf((pbuf+strlen(pbuf)), "reserved (0x%02x)", ls & 0x0f);
+ break;
+ }
+
+ sprintf((pbuf+strlen(pbuf)), ", std=");
+
+ switch((ls & 0x60) >> 5)
+ {
+ case 0:
+ sprintf((pbuf+strlen(pbuf)), "CCITT");
+ break;
+ case 1:
+ sprintf((pbuf+strlen(pbuf)), "ISO/IEC");
+ break;
+ case 2:
+ sprintf((pbuf+strlen(pbuf)), "National");
+ break;
+ case 3:
+ sprintf((pbuf+strlen(pbuf)), "Local");
+ break;
+ }
+
+ if(rflag)
+ {
+ sprintf((pbuf+strlen(pbuf)), ", rec=");
+
+ switch(r & 0x7f)
+ {
+ case 0:
+ sprintf((pbuf+strlen(pbuf)), "Q.931");
+ break;
+ case 3:
+ sprintf((pbuf+strlen(pbuf)), "X.21");
+ break;
+ case 4:
+ sprintf((pbuf+strlen(pbuf)), "X.25");
+ break;
+ case 5:
+ sprintf((pbuf+strlen(pbuf)), "Q.1031/Q.1051");
+ break;
+ default:
+ sprintf((pbuf+strlen(pbuf)), "Reserved");
+ break;
+ }
+ }
+
+ sprintf((pbuf+strlen(pbuf)),")");
+
+ i++;
+ len--;
+
+ for(j = 0; j < len; j++)
+ sprintf((pbuf+strlen(pbuf))," 0x%02x", buf[j+i]);
+
+ sprintf((pbuf+strlen(pbuf)),"]");
+
+ i += (len+1);
+
+ return(i);
+}
+
+/*---------------------------------------------------------------------------*
+ * decode and print the bearer capability
+ *---------------------------------------------------------------------------*/
+int
+p_q931bc(char *pbuf, unsigned char *buf)
+{
+ int len;
+ int i = 0;
+ int mr = 0;
+
+ i++; /* index -> length */
+
+ len = buf[i];
+
+ i++;
+
+ sprintf((pbuf+strlen(pbuf)), "\n cap=");
+
+ switch(buf[i] & 0x1f)
+ {
+ case 0x00:
+ sprintf((pbuf+strlen(pbuf)), "speech");
+ break;
+ case 0x08:
+ sprintf((pbuf+strlen(pbuf)), "unrestricted digital information");
+ break;
+ case 0x09:
+ sprintf((pbuf+strlen(pbuf)), "restricted digital information");
+ break;
+ case 0x10:
+ sprintf((pbuf+strlen(pbuf)), "3.1 kHz audio");
+ break;
+ case 0x11:
+ sprintf((pbuf+strlen(pbuf)), "unrestricted digital information with tones");
+ break;
+ case 0x18:
+ sprintf((pbuf+strlen(pbuf)), "video");
+ break;
+ default:
+ sprintf((pbuf+strlen(pbuf)), "reserved (0x%02x)", buf[i] & 0x0f);
+ break;
+ }
+
+ sprintf((pbuf+strlen(pbuf)), "\n std=");
+
+ switch((buf[i] & 0x60) >> 5)
+ {
+ case 0:
+ sprintf((pbuf+strlen(pbuf)), "CCITT");
+ break;
+ case 1:
+ sprintf((pbuf+strlen(pbuf)), "ISO/IEC");
+ break;
+ case 2:
+ sprintf((pbuf+strlen(pbuf)), "National");
+ break;
+ case 3:
+ sprintf((pbuf+strlen(pbuf)), "NSI Std");
+ break;
+ }
+
+ i++;
+ len--;
+
+ sprintf((pbuf+strlen(pbuf)), "\n rate=");
+
+ switch(buf[i] & 0x1f)
+ {
+ case 0x00:
+ sprintf((pbuf+strlen(pbuf)), "packet mode");
+ break;
+ case 0x10:
+ sprintf((pbuf+strlen(pbuf)), "64 kbit/s");
+ break;
+ case 0x11:
+ sprintf((pbuf+strlen(pbuf)), "2 x 64 kbit/s");
+ break;
+ case 0x13:
+ sprintf((pbuf+strlen(pbuf)), "384 kbit/s");
+ break;
+ case 0x15:
+ sprintf((pbuf+strlen(pbuf)), "1536 kbit/s");
+ break;
+ case 0x17:
+ sprintf((pbuf+strlen(pbuf)), "1920 kbit/s");
+ break;
+ case 0x18:
+ sprintf((pbuf+strlen(pbuf)), "Multirate");
+ mr = 1;
+ break;
+ default:
+ sprintf((pbuf+strlen(pbuf)), "reserved (0x%02x)", buf[i] & 0x0f);
+ break;
+ }
+
+ sprintf((pbuf+strlen(pbuf)), "\n mode=");
+
+ switch((buf[i] & 0x60) >> 5)
+ {
+ case 0:
+ sprintf((pbuf+strlen(pbuf)), "circuit");
+ break;
+ case 2:
+ sprintf((pbuf+strlen(pbuf)), "packet");
+ break;
+ default:
+ sprintf((pbuf+strlen(pbuf)), "reserved (0x%02x)", ((buf[i] & 0x60) >> 5));
+ break;
+ }
+
+ i++;
+ len--;
+
+ if(!len)
+ goto exit;
+
+ if(mr)
+ {
+ sprintf((pbuf+strlen(pbuf)), "\n rate multiplier=%d", buf[i] & 0x7f);
+ i++;
+ len--;
+ }
+
+ if(!len)
+ goto exit;
+
+ sprintf((pbuf+strlen(pbuf)), "\n layer1=");
+
+ switch(buf[i] & 0x1f)
+ {
+ case 0x01:
+ sprintf((pbuf+strlen(pbuf)), "V.110");
+ break;
+ case 0x02:
+ sprintf((pbuf+strlen(pbuf)), "G.711 u-law");
+ break;
+ case 0x03:
+ sprintf((pbuf+strlen(pbuf)), "G.711 A-law");
+ break;
+ case 0x04:
+ sprintf((pbuf+strlen(pbuf)), "G.721");
+ break;
+ case 0x05:
+ sprintf((pbuf+strlen(pbuf)), "H.221/H.242");
+ break;
+ case 0x07:
+ sprintf((pbuf+strlen(pbuf)), "Non-Std");
+ break;
+ case 0x08:
+ sprintf((pbuf+strlen(pbuf)), "V.120");
+ break;
+ case 0x09:
+ sprintf((pbuf+strlen(pbuf)), "X.31");
+ break;
+ default:
+ sprintf((pbuf+strlen(pbuf)), "reserved (0x%02x)", buf[i] & 0x0f);
+ break;
+ }
+ i++;
+ len--;
+
+ if(!len)
+ goto exit;
+
+ if(!(buf[i-1] & 0x80))
+ {
+ sprintf((pbuf+strlen(pbuf)), "\n user rate=0x%02x ", buf[i] & 0x1f);
+
+ if(buf[i] & 0x40)
+ sprintf((pbuf+strlen(pbuf)), "(async,");
+ else
+ sprintf((pbuf+strlen(pbuf)), "(sync,");
+
+ if(buf[i] & 0x20)
+ sprintf((pbuf+strlen(pbuf)), "in-band neg. possible)");
+ else
+ sprintf((pbuf+strlen(pbuf)), "in-band neg not possible)");
+
+ i++;
+ len--;
+ }
+
+ if(!len)
+ goto exit;
+
+ if(!(buf[i-1] & 0x80))
+ {
+ sprintf((pbuf+strlen(pbuf)), "\n clk/flow=0x%02x", buf[i] & 0x1f);
+
+ sprintf((pbuf+strlen(pbuf)), "\n intermediate rate=");
+
+ switch((buf[i] & 0x60) >> 5)
+ {
+ case 0:
+ sprintf((pbuf+strlen(pbuf)), "not used");
+ break;
+ case 1:
+ sprintf((pbuf+strlen(pbuf)), "8 kbit/s");
+ break;
+ case 2:
+ sprintf((pbuf+strlen(pbuf)), "16 kbit/s");
+ break;
+ case 3:
+ sprintf((pbuf+strlen(pbuf)), "32 kbit/s");
+ break;
+ }
+ i++;
+ len--;
+ }
+
+ if(!len)
+ goto exit;
+
+ if(!(buf[i-1] & 0x80))
+ {
+ sprintf((pbuf+strlen(pbuf)), "\n hdr/mfrm/etc.=0x%02x", buf[i]);
+ i++;
+ len--;
+ }
+
+ if(!len)
+ goto exit;
+
+ if(!(buf[i-1] & 0x80))
+ {
+ sprintf((pbuf+strlen(pbuf)), "\n stop/data/parity=0x%02x", buf[i]);
+ i++;
+ len--;
+ }
+
+ if(!len)
+ goto exit;
+
+ if(!(buf[i-1] & 0x80))
+ {
+ sprintf((pbuf+strlen(pbuf)), "\n modemtype=0x%02x", buf[i]);
+ i++;
+ len--;
+ }
+
+ if(!len)
+ goto exit;
+
+ switch(buf[i] & 0x7f)
+ {
+ case 0x42:
+ sprintf((pbuf+strlen(pbuf)), "\n layer2=Q.921/I.441");
+ break;
+ case 0x46:
+ sprintf((pbuf+strlen(pbuf)), "\n layer2=X.25 link");
+ break;
+ default:
+ sprintf((pbuf+strlen(pbuf)), "\n layer2=0x%02x",(buf[i] & 0x7f));
+ break;
+ }
+ i++;
+ len--;
+
+ if(!len)
+ goto exit;
+
+ switch(buf[i] & 0x7f)
+ {
+ case 0x62:
+ sprintf((pbuf+strlen(pbuf)), "\n layer3=Q.921/I.441");
+ break;
+ case 0x66:
+ sprintf((pbuf+strlen(pbuf)), "\n layer3=X.25 packet");
+ break;
+ default:
+ sprintf((pbuf+strlen(pbuf)), "\n layer3=0x%02x",(buf[i] & 0x7f));
+ break;
+ }
+ i++;
+ len--;
+
+exit:
+ sprintf((pbuf+strlen(pbuf)), "]");
+ return(i);
+}
+
+/*---------------------------------------------------------------------------*
+ * decode and print the ISDN (telephone) number
+ *---------------------------------------------------------------------------*/
+int
+p_q931address(char *pbuf, unsigned char *buf)
+{
+ int j;
+ int len;
+ int i = 0;
+ int tp;
+ int ind = 0;
+ int indflag = 0;
+
+ i++; /* index -> length */
+ len = buf[i];
+
+ i++; /* index -> type/plan */
+ tp = buf[i];
+
+ i++;
+ len--;
+
+ if(!(tp & 0x80))
+ {
+ ind = buf[i];
+ indflag = 1;
+ i++;
+ len--;
+ }
+
+ for(j = 0; j < len; j++)
+ {
+ sprintf((pbuf+strlen(pbuf)),"%c", buf[j+i]);
+ }
+
+ switch((tp & 0x70) >> 4)
+ {
+ case 0:
+ sprintf((pbuf+strlen(pbuf)), " (type=unknown, ");
+ break;
+ case 1:
+ sprintf((pbuf+strlen(pbuf)), " (type=international, ");
+ break;
+ case 2:
+ sprintf((pbuf+strlen(pbuf)), " (type=national, ");
+ break;
+ case 3:
+ sprintf((pbuf+strlen(pbuf)), " (type=network specific, ");
+ break;
+ case 4:
+ sprintf((pbuf+strlen(pbuf)), " (type=subscriber, ");
+ break;
+ case 6:
+ sprintf((pbuf+strlen(pbuf)), " (type=abbreviated, ");
+ break;
+ default:
+ sprintf((pbuf+strlen(pbuf)), " (type=reserved (%d), ", ((tp & 0x70) >> 4));
+ break;
+ }
+
+ switch(tp & 0x0f)
+ {
+ case 0:
+ sprintf((pbuf+strlen(pbuf)), "plan=unknown");
+ break;
+ case 1:
+ sprintf((pbuf+strlen(pbuf)), "plan=ISDN");
+ break;
+ case 3:
+ sprintf((pbuf+strlen(pbuf)), "plan=Data");
+ break;
+ case 4:
+ sprintf((pbuf+strlen(pbuf)), "plan=Telex");
+ break;
+ case 8:
+ sprintf((pbuf+strlen(pbuf)), "plan=National");
+ break;
+ case 9:
+ sprintf((pbuf+strlen(pbuf)), "plan=private");
+ break;
+ default:
+ sprintf((pbuf+strlen(pbuf)), "plan=reserved (%d)", (tp & 0x0f));
+ break;
+ }
+
+ if(indflag)
+ {
+ sprintf((pbuf+strlen(pbuf)), ",\n ");
+ switch((ind & 0x60) >> 5)
+ {
+ case 0:
+ sprintf((pbuf+strlen(pbuf)), "presentation allowed, ");
+ break;
+ case 1:
+ sprintf((pbuf+strlen(pbuf)), "presentation restricted, ");
+ break;
+ case 2:
+ sprintf((pbuf+strlen(pbuf)), "number not available, ");
+ break;
+ case 3:
+ sprintf((pbuf+strlen(pbuf)), "reserved, ");
+ break;
+ }
+
+ switch(ind & 0x03)
+ {
+ case 0:
+ sprintf((pbuf+strlen(pbuf)), "screening user provided: not screened");
+ break;
+ case 1:
+ sprintf((pbuf+strlen(pbuf)), "screening user provided: verified & passed");
+ break;
+ case 2:
+ sprintf((pbuf+strlen(pbuf)), "screening user provided: verified & failed");
+ break;
+ case 3:
+ sprintf((pbuf+strlen(pbuf)), "screening network provided");
+ break;
+ }
+ }
+
+ sprintf((pbuf+strlen(pbuf)),")]");
+
+ i += j;
+
+ return(i);
+}
+
+/*---------------------------------------------------------------------------*
+ * decode and print HL comatibility
+ *---------------------------------------------------------------------------*/
+int
+p_q931high_compat(char *pbuf, unsigned char *buf)
+{
+ int len = buf[1];
+
+ sprintf(pbuf+strlen(pbuf), " standard=");
+
+ switch ((buf[2] >> 5) & 0x03)
+ {
+ case 0: sprintf(pbuf+strlen(pbuf), "CCITT");
+ break;
+ case 1: sprintf(pbuf+strlen(pbuf), "unknown international standard");
+ break;
+ case 2: sprintf(pbuf+strlen(pbuf), "unknown national standard");
+ break;
+ case 3: sprintf(pbuf+strlen(pbuf), "local network standard");
+ }
+
+ len--;
+
+ sprintf(pbuf+strlen(pbuf), ", characteristics=");
+
+ switch (buf[3] & 0x7f)
+ {
+ case 0x01:
+ sprintf(pbuf+strlen(pbuf), "Telephony");
+ break;
+ case 0x04:
+ sprintf(pbuf+strlen(pbuf), "Fax Group 2/3");
+ break;
+ case 0x21:
+ sprintf(pbuf+strlen(pbuf), "Fax Group 4 Class I (F.184)");
+ break;
+ case 0x24:
+ sprintf(pbuf+strlen(pbuf), "Teletex basic/mixed (F.230) or Fax Group 4 Class II/III (F.184)");
+ break;
+ case 0x28:
+ sprintf(pbuf+strlen(pbuf), "Teletex basic/processable (F.220)");
+ break;
+ case 0x31:
+ sprintf(pbuf+strlen(pbuf), "Teletex basic mode (F.200)");
+ break;
+ case 0x32:
+ sprintf(pbuf+strlen(pbuf), "Videotex (F.300 and T.101)");
+ break;
+ case 0x35:
+ sprintf(pbuf+strlen(pbuf), "Telex (F.60)");
+ break;
+ case 0x38:
+ sprintf(pbuf+strlen(pbuf), "MHS (X.400 series)");
+ break;
+ case 0x41:
+ sprintf(pbuf+strlen(pbuf), "OSI application (X.200 series)");
+ break;
+ case 0x5e:
+ sprintf(pbuf+strlen(pbuf), "Maintenance");
+ break;
+ case 0x5f:
+ sprintf(pbuf+strlen(pbuf), "Management");
+ break;
+ case 0x7f:
+ sprintf(pbuf+strlen(pbuf), "reserved");
+ break;
+ default:
+ sprintf(pbuf+strlen(pbuf), "UNKNOWN (0x%02x)", buf[3]);
+ break;
+ }
+
+ len--;
+
+ if (!len)
+ {
+ sprintf(pbuf+strlen(pbuf), "]");
+ return 4;
+ }
+
+ sprintf(pbuf+strlen(pbuf), " of ");
+
+ switch (buf[4] & 0x7f)
+ {
+ case 0x01:
+ sprintf(pbuf+strlen(pbuf), "Telephony");
+ break;
+ case 0x04:
+ sprintf(pbuf+strlen(pbuf), "Fax Group 2/3");
+ break;
+ case 0x21:
+ sprintf(pbuf+strlen(pbuf), "Fax Group 4 Class I (F.184)");
+ break;
+ case 0x24:
+ sprintf(pbuf+strlen(pbuf), "Teletex basic/mixed (F.230) or Fax Group 4 Class II/III (F.184)");
+ break;
+ case 0x28:
+ sprintf(pbuf+strlen(pbuf), "Teletex basic/processable (F.220)");
+ break;
+ case 0x31:
+ sprintf(pbuf+strlen(pbuf), "Teletex basic mode (F.200)");
+ break;
+ case 0x32:
+ sprintf(pbuf+strlen(pbuf), "Videotex (F.300 and T.101)");
+ break;
+ case 0x35:
+ sprintf(pbuf+strlen(pbuf), "Telex (F.60)");
+ break;
+ case 0x38:
+ sprintf(pbuf+strlen(pbuf), "MHS (X.400 series)");
+ break;
+ case 0x41:
+ sprintf(pbuf+strlen(pbuf), "OSI application (X.200 series)");
+ break;
+ case 0x7f:
+ sprintf(pbuf+strlen(pbuf), "reserved");
+ break;
+ default:
+ sprintf(pbuf+strlen(pbuf), "UNKNOWN (0x%02x)", buf[3]);
+ break;
+ }
+ sprintf(pbuf+strlen(pbuf), "]");
+ return 5;
+}
+
+/* EOF */
+
diff --git a/usr.sbin/i4b/isdntrace/q932_fac.c b/usr.sbin/i4b/isdntrace/q932_fac.c
new file mode 100644
index 0000000..ba3f59d
--- /dev/null
+++ b/usr.sbin/i4b/isdntrace/q932_fac.c
@@ -0,0 +1,926 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * q932_fac.c - decode Q.932 facilities
+ * ------------------------------------
+ *
+ * $Id: q932_fac.c,v 1.4 1998/12/05 18:04:22 hm Exp $
+ *
+ * last edit-date: [Sat Dec 5 18:20:58 1998]
+ *
+ *---------------------------------------------------------------------------
+ *
+ * - Q.932 (03/93) Generic Procedures for the Control of
+ * ISDN Supplementaty Services
+ * - Q.950 (03/93) Supplementary Services Protocols, Structure and
+ * General Principles
+ * - ETS 300 179 (10/92) Advice Of Charge: charging information during
+ * the call (AOC-D) supplementary service Service description
+ * - ETS 300 180 (10/92) Advice Of Charge: charging information at the
+ * end of call (AOC-E) supplementary service Service description
+ * - ETS 300 181 (04/93) Advice Of Charge (AOC) supplementary service
+ * Functional capabilities and information flows
+ * - ETS 300 182 (04/93) Advice Of Charge (AOC) supplementary service
+ * Digital Subscriber Signalling System No. one (DSS1) protocol
+ * - X.208 Specification of Abstract Syntax Notation One (ASN.1)
+ * - X.209 Specification of Basic Encoding Rules for
+ * Abstract Syntax Notation One (ASN.1)
+ * - "ASN.1 Abstract Syntax Notation One", Walter Gora, DATACOM-Verlag
+ * 1992, 3rd Edition (ISBN 3-89238-062-7) (german !)
+ *
+ *---------------------------------------------------------------------------*/
+
+#include "trace.h"
+#include "q932_fac.h"
+
+static int do_component(int length, char *pbuf);
+static char *uni_str(int code);
+static char *opval_str(int val);
+static char *bid_str(int val);
+static void next_state(char *pbuf, int class, int form, int code, int val);
+
+static int byte_len;
+static unsigned char *byte_buf;
+static int state;
+
+/*---------------------------------------------------------------------------*
+ * decode Q.931/Q.932 facility info element
+ *---------------------------------------------------------------------------*/
+int
+q932_facility(char *pbuf, unsigned char *buf)
+{
+ int len;
+
+ sprintf((pbuf+strlen(pbuf)), "[facility (Q.932): ");
+
+ buf++; /* length */
+
+ len = *buf;
+
+ buf++; /* protocol profile */
+
+ sprintf((pbuf+strlen(pbuf)), "Protocol=");
+
+ switch(*buf & 0x1f)
+ {
+ case FAC_PROTO_ROP:
+ sprintf((pbuf+strlen(pbuf)), "Remote Operations Protocol\n");
+ break;
+
+ case FAC_PROTO_CMIP:
+ sprintf((pbuf+strlen(pbuf)), "CMIP Protocol (Q.941), UNSUPPORTED!\n");
+ return(len+2);
+ break;
+
+ case FAC_PROTO_ACSE:
+ sprintf((pbuf+strlen(pbuf)), "ACSE Protocol (X.217/X.227), UNSUPPORTED!\n");
+ return(len+2);
+ break;
+
+ default:
+ sprintf((pbuf+strlen(pbuf)), "Unknown Protocol (val = 0x%x), UNSUPPORTED!\n", *buf & 0x1f);
+ return(len+2);
+ break;
+ }
+
+ /* next byte */
+
+ buf++;
+ len--;
+
+ /* initialize variables for do_component */
+
+ byte_len = 0;
+ byte_buf = buf;
+ state = ST_EXP_COMP_TYP;
+
+ /* decode facility */
+
+ do_component(len, pbuf);
+
+ sprintf((pbuf+(strlen(pbuf)-1)), "]"); /* XXX replace last newline */
+
+ return(len+3);
+}
+
+/*---------------------------------------------------------------------------*
+ * handle a component recursively
+ *---------------------------------------------------------------------------*/
+static int
+do_component(int length, char *pbuf)
+{
+ int comp_tag_class; /* component tag class */
+ int comp_tag_form; /* component form: constructor or primitive */
+ int comp_tag_code; /* component code depending on class */
+ int comp_length = 0; /* component length */
+
+#ifdef FAC_DEBUG
+ sprintf((pbuf+strlen(pbuf)), "ENTER - comp_length = %d, byte_len = %d, length =%d\n", comp_length, byte_len, length);
+#endif
+
+again:
+
+#ifdef FAC_DEBUG
+ sprintf((pbuf+strlen(pbuf)), "AGAIN - comp_length = %d, byte_len = %d, length =%d\n", comp_length, byte_len, length);
+#endif
+
+ /*----------------------------------------*/
+ /* first component element: component tag */
+ /*----------------------------------------*/
+
+ /* tag class bits */
+
+ sprintf((pbuf+strlen(pbuf)), "\t0x%02x Tag: ", *byte_buf);
+
+ comp_tag_class = (*byte_buf & 0xc0) >> 6;
+
+ switch(comp_tag_class)
+ {
+ case FAC_TAGCLASS_UNI:
+ sprintf((pbuf+strlen(pbuf)), "Universal");
+ break;
+ case FAC_TAGCLASS_APW:
+ sprintf((pbuf+strlen(pbuf)), "Applic-wide");
+ break;
+ case FAC_TAGCLASS_COS:
+ sprintf((pbuf+strlen(pbuf)), "Context-spec");
+ break;
+ case FAC_TAGCLASS_PRU:
+ sprintf((pbuf+strlen(pbuf)), "Private");
+ break;
+ }
+
+ /* tag form bit */
+
+ comp_tag_form = (*byte_buf & 0x20) > 5;
+
+ sprintf((pbuf+strlen(pbuf)), ", ");
+
+ if(comp_tag_form == FAC_TAGFORM_CON)
+ {
+ sprintf((pbuf+strlen(pbuf)), "Constructor");
+ }
+ else
+ {
+ sprintf((pbuf+strlen(pbuf)), "Primitive");
+ }
+
+ /* tag code bits */
+
+ comp_tag_code = *byte_buf & 0x1f;
+
+ sprintf((pbuf+strlen(pbuf)), ", ");
+
+ if(comp_tag_code == 0x1f)
+ {
+ comp_tag_code = 0;
+
+ byte_buf++;
+ byte_len++;
+
+ while(*byte_buf & 0x80)
+ {
+ comp_tag_code += (*byte_buf & 0x7f);
+ byte_buf++;
+ byte_len++;
+ }
+ comp_tag_code += (*byte_buf & 0x7f);
+ sprintf((pbuf+strlen(pbuf)), "%d (ext)\n", comp_tag_code);
+ }
+ else
+ {
+ comp_tag_code = (*byte_buf & 0x1f);
+
+ if(comp_tag_class == FAC_TAGCLASS_UNI)
+ {
+ sprintf((pbuf+strlen(pbuf)), "%s (%d)\n", uni_str(comp_tag_code), comp_tag_code);
+ }
+ else
+ {
+ sprintf((pbuf+strlen(pbuf)), "code = %d\n", comp_tag_code);
+ }
+ }
+
+ byte_buf++;
+ byte_len++;
+
+ /*--------------------------------------------*/
+ /* second component element: component length */
+ /*--------------------------------------------*/
+
+ sprintf((pbuf+strlen(pbuf)), "\t0x%02x Len: ", *byte_buf);
+
+ comp_length = 0;
+
+ if(*byte_buf & 0x80)
+ {
+ int i = *byte_buf & 0x7f;
+
+ byte_len += i;
+
+ for(;i > 0;i++)
+ {
+ byte_buf++;
+ comp_length += (*byte_buf * (i*256));
+ }
+ sprintf((pbuf+strlen(pbuf)), "%d (long form)\n", comp_length);
+ }
+ else
+ {
+ comp_length = *byte_buf & 0x7f;
+ sprintf((pbuf+strlen(pbuf)), "%d (short form)\n", comp_length);
+ }
+
+ next_state(pbuf, comp_tag_class, comp_tag_form, comp_tag_code, -1);
+
+ byte_len++;
+ byte_buf++;
+
+ if(comp_length)
+ {
+
+ /*---------------------------------------------*/
+ /* third component element: component contents */
+ /*---------------------------------------------*/
+
+ if(comp_tag_form) /* == constructor */
+ {
+ do_component(comp_length, pbuf);
+ }
+ else
+ {
+ int val = 0;
+ if(comp_tag_class == FAC_TAGCLASS_UNI)
+ {
+ switch(comp_tag_code)
+ {
+ case FAC_CODEUNI_INT:
+ case FAC_CODEUNI_ENUM:
+ case FAC_CODEUNI_BOOL:
+ if(comp_length)
+ {
+ int i;
+
+ sprintf((pbuf+strlen(pbuf)), "\t");
+
+ for(i = comp_length-1; i >= 0; i--)
+ {
+ sprintf((pbuf+strlen(pbuf)), "0x%02x ", *byte_buf);
+ val += (*byte_buf + (i*255));
+ byte_buf++;
+ byte_len++;
+ if(i)
+ sprintf((pbuf+strlen(pbuf)), "\n\t");
+ }
+ sprintf((pbuf+strlen(pbuf)), "Val: %d\n", val);
+ }
+ break;
+ default:
+ if(comp_length)
+ {
+ int i;
+
+ sprintf((pbuf+strlen(pbuf)), "\t");
+
+ for(i = comp_length-1; i >= 0; i--)
+ {
+ sprintf((pbuf+strlen(pbuf)), "0x%02x = %d", *byte_buf, *byte_buf);
+ if(isprint(*byte_buf))
+ sprintf((pbuf+strlen(pbuf)), " = '%c'", *byte_buf);
+ byte_buf++;
+ byte_len++;
+ if(i)
+ sprintf((pbuf+strlen(pbuf)), "\n\t");
+ }
+ }
+ break;
+ }
+ }
+
+ else /* comp_tag_class != FAC_TAGCLASS_UNI */
+ {
+ if(comp_length)
+ {
+ int i;
+
+ sprintf((pbuf+strlen(pbuf)), "\t");
+
+ for(i = comp_length-1; i >= 0; i--)
+ {
+ sprintf((pbuf+strlen(pbuf)), "0x%02x", *byte_buf);
+ val += (*byte_buf + (i*255));
+ byte_buf++;
+ byte_len++;
+ if(i)
+ sprintf((pbuf+strlen(pbuf)), "\n\t");
+ }
+ sprintf((pbuf+strlen(pbuf)), "\n");
+ }
+ }
+ next_state(pbuf, comp_tag_class, comp_tag_form, comp_tag_code, val);
+ }
+ }
+
+#ifdef FAC_DEBUG
+ sprintf((pbuf+strlen(pbuf)), "PREGOTO - comp_length = %d, byte_len = %d, length =%d\n", comp_length, byte_len, length);
+#endif
+ if(byte_len < length)
+ goto again;
+#ifdef FAC_DEBUG
+ sprintf((pbuf+strlen(pbuf)), "RETURN - comp_length = %d, byte_len = %d, length =%d\n", comp_length, byte_len, length);
+#endif
+ return(byte_len);
+}
+
+/*---------------------------------------------------------------------------*
+ * print universal id type
+ *---------------------------------------------------------------------------*/
+static char *uni_str(int code)
+{
+ static char *tbl[] = {
+ "BOOLEAN",
+ "INTEGER",
+ "BIT STRING",
+ "OCTET STRING",
+ "NULL",
+ "OBJECT IDENTIFIER",
+ "OBJECT DESCRIPTOR",
+ "EXTERNAL",
+ "REAL",
+ "ENUMERATED",
+ "RESERVED11",
+ "RESERVED12",
+ "RESERVED13",
+ "RESERVED14",
+ "RESERVED15",
+ "SEQUENCE",
+ "SET",
+ "NUMERIC STRING",
+ "PRINTABLE STRING",
+ "TELETEX STRING",
+ "ISO646 STRING",
+ "IA5 STRING",
+ "GRAPHIC STRING",
+ "GENERAL STRING"
+ };
+
+ if(code >= 1 && code <= FAC_CODEUNI_GNSTR)
+ return(tbl[code-1]);
+ else
+ return("ERROR, Value out of Range!");
+}
+
+/*---------------------------------------------------------------------------*
+ * print operation value
+ *---------------------------------------------------------------------------*/
+static char *opval_str(int val)
+{
+ static char buffer[80];
+ char *r;
+
+ switch(val)
+ {
+ case FAC_OPVAL_UUS:
+ r = "uUs";
+ break;
+ case FAC_OPVAL_CUG:
+ r = "cUGCall";
+ break;
+ case FAC_OPVAL_MCID:
+ r = "mCIDRequest";
+ break;
+ case FAC_OPVAL_BTPY:
+ r = "beginTPY";
+ break;
+ case FAC_OPVAL_ETPY:
+ r = "endTPY";
+ break;
+ case FAC_OPVAL_ECT:
+ r = "eCTRequest";
+ break;
+ case FAC_OPVAL_DIV_ACT:
+ r = "activationDiversion";
+ break;
+ case FAC_OPVAL_DIV_DEACT:
+ r = "deactivationDiversion";
+ break;
+ case FAC_OPVAL_DIV_ACTSN:
+ r = "activationStatusNotificationDiv";
+ break;
+ case FAC_OPVAL_DIV_DEACTSN:
+ r = "deactivationStatusNotificationDiv";
+ break;
+ case FAC_OPVAL_DIV_INTER:
+ r = "interrogationDiversion";
+ break;
+ case FAC_OPVAL_DIV_INFO:
+ r = "diversionInformation";
+ break;
+ case FAC_OPVAL_DIV_CALLDEF:
+ r = "callDeflection";
+ break;
+ case FAC_OPVAL_DIV_CALLRER:
+ r = "callRerouting";
+ break;
+ case FAC_OPVAL_DIV_LINF2:
+ r = "divertingLegInformation2";
+ break;
+ case FAC_OPVAL_DIV_INVS:
+ r = "invokeStatus";
+ break;
+ case FAC_OPVAL_DIV_INTER1:
+ r = "interrogationDiversion1";
+ break;
+ case FAC_OPVAL_DIV_LINF1:
+ r = "divertingLegInformation1";
+ break;
+ case FAC_OPVAL_DIV_LINF3:
+ r = "divertingLegInformation3";
+ break;
+ case FAC_OPVAL_ER_CRCO:
+ r = "explicitReservationCreationControl";
+ break;
+ case FAC_OPVAL_ER_MGMT:
+ r = "explicitReservationManagement";
+ break;
+ case FAC_OPVAL_ER_CANC:
+ r = "explicitReservationCancel";
+ break;
+ case FAC_OPVAL_MLPP_QUERY:
+ r = "mLPP lfb Query";
+ break;
+ case FAC_OPVAL_MLPP_CALLR:
+ r = "mLPP Call Request";
+ break;
+ case FAC_OPVAL_MLPP_CALLP:
+ r = "mLPP Call Preemption";
+ break;
+ case FAC_OPVAL_AOC_REQ:
+ r = "chargingRequest";
+ break;
+ case FAC_OPVAL_AOC_S_CUR:
+ r = "aOCSCurrency";
+ break;
+ case FAC_OPVAL_AOC_S_SPC:
+ r = "aOCSSpecialArrangement";
+ break;
+ case FAC_OPVAL_AOC_D_CUR:
+ r = "aOCDCurrency";
+ break;
+ case FAC_OPVAL_AOC_D_UNIT:
+ r = "aOCDChargingUnit";
+ break;
+ case FAC_OPVAL_AOC_E_CUR:
+ r = "aOCECurrency";
+ break;
+ case FAC_OPVAL_AOC_E_UNIT:
+ r = "aOCEChargingUnit";
+ break;
+ case FAC_OPVAL_AOC_IDOFCRG:
+ r = "identificationOfCharge";
+ break;
+ case FAC_OPVAL_CONF_BEG:
+ r = "beginConf";
+ break;
+ case FAC_OPVAL_CONF_ADD:
+ r = "addConf";
+ break;
+ case FAC_OPVAL_CONF_SPLIT:
+ r = "splitConf";
+ break;
+ case FAC_OPVAL_CONF_DROP:
+ r = "dropConf";
+ break;
+ case FAC_OPVAL_CONF_ISOLATE:
+ r = "isolateConf";
+ break;
+ case FAC_OPVAL_CONF_REATT:
+ r = "reattachConf";
+ break;
+ case FAC_OPVAL_CONF_PDISC:
+ r = "partyDISC";
+ break;
+ case FAC_OPVAL_CONF_FCONF:
+ r = "floatConf";
+ break;
+ case FAC_OPVAL_CONF_END:
+ r = "endConf";
+ break;
+ case FAC_OPVAL_CONF_IDCFE:
+ r = "indentifyConferee";
+ break;
+ case FAC_OPVAL_REVC_REQ:
+ r = "requestREV";
+ break;
+ default:
+ sprintf(buffer, "unknown operation value %d!", val);
+ r = buffer;
+ }
+ return(r);
+}
+
+/*---------------------------------------------------------------------------*
+ * billing id string
+ *---------------------------------------------------------------------------*/
+static char *bid_str(int val)
+{
+ static char buffer[80];
+ char *r;
+
+ switch(val)
+ {
+ case 0:
+ r = "normalCharging";
+ break;
+ case 1:
+ r = "reverseCharging";
+ break;
+ case 2:
+ r = "creditCardCharging";
+ break;
+ case 3:
+ r = "callForwardingUnconditional";
+ break;
+ case 4:
+ r = "callForwardingBusy";
+ break;
+ case 5:
+ r = "callForwardingNoReply";
+ break;
+ case 6:
+ r = "callDeflection";
+ break;
+ case 7:
+ r = "callTransfer";
+ break;
+ default:
+ sprintf(buffer, "unknown billing-id value %d!", val);
+ r = buffer;
+ }
+ return(r);
+}
+
+/*---------------------------------------------------------------------------*
+ * invoke component
+ *---------------------------------------------------------------------------*/
+static void
+F_1_1(char *pbuf, int val)
+{
+#ifdef ST_DEBUG
+ sprintf((pbuf+strlen(pbuf)), "next_state: exec F_1_1, val = %d\n", val);
+#endif
+ if(val == -1)
+ {
+ sprintf((pbuf+strlen(pbuf)), "\t invokeComponent\n");
+ state = ST_EXP_INV_ID;
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * return result
+ *---------------------------------------------------------------------------*/
+static void
+F_1_2(char *pbuf, int val)
+{
+#ifdef ST_DEBUG
+ sprintf((pbuf+strlen(pbuf)), "next_state: exec F_1_2, val = %d\n", val);
+#endif
+ if(val == -1)
+ {
+ sprintf((pbuf+strlen(pbuf)), "\t returnResult\n");
+ state = ST_EXP_RR_INV_ID;
+ }
+}
+/*---------------------------------------------------------------------------*
+ * return error
+ *---------------------------------------------------------------------------*/
+static void
+F_1_3(char *pbuf, int val)
+{
+#ifdef ST_DEBUG
+ sprintf((pbuf+strlen(pbuf)), "next_state: exec F_1_3, val = %d\n", val);
+#endif
+ if(val == -1)
+ {
+ sprintf((pbuf+strlen(pbuf)), "\t returnError\n");
+ state = ST_EXP_NIX;
+ }
+}
+/*---------------------------------------------------------------------------*
+ * reject
+ *---------------------------------------------------------------------------*/
+static void
+F_1_4(char *pbuf, int val)
+{
+#ifdef ST_DEBUG
+ sprintf((pbuf+strlen(pbuf)), "next_state: exec F_1_4, val = %d\n", val);
+#endif
+ if(val == -1)
+ {
+ sprintf((pbuf+strlen(pbuf)), "\t reject\n");
+ state = ST_EXP_NIX;
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * invoke component: invoke id
+ *---------------------------------------------------------------------------*/
+static void
+F_2(char *pbuf, int val)
+{
+#ifdef ST_DEBUG
+ sprintf((pbuf+strlen(pbuf)), "next_state: exec F_2, val = %d\n", val);
+#endif
+ if(val != -1)
+ {
+ sprintf((pbuf+strlen(pbuf)), "\t InvokeIdentifier = %d\n", val);
+ state = ST_EXP_OP_VAL;
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * return result: invoke id
+ *---------------------------------------------------------------------------*/
+static void
+F_RR2(char *pbuf, int val)
+{
+#ifdef ST_DEBUG
+ sprintf((pbuf+strlen(pbuf)), "next_state: exec F_RR2, val = %d\n", val);
+#endif
+ if(val != -1)
+ {
+ sprintf((pbuf+strlen(pbuf)), "\t InvokeIdentifier = %d\n", val);
+ state = ST_EXP_RR_OP_VAL;
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * invoke component: operation value
+ *---------------------------------------------------------------------------*/
+static void
+F_3(char *pbuf, int val)
+{
+#ifdef ST_DEBUG
+ sprintf((pbuf+strlen(pbuf)), "next_state: exec F_3, val = %d\n", val);
+#endif
+ if(val != -1)
+ {
+ sprintf((pbuf+strlen(pbuf)), "\t Operation Value = %s (%d)\n", opval_str(val), val);
+ state = ST_EXP_INFO;
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * return result: operation value
+ *---------------------------------------------------------------------------*/
+static void
+F_RR3(char *pbuf, int val)
+{
+#ifdef ST_DEBUG
+ sprintf((pbuf+strlen(pbuf)), "next_state: exec F_RR3, val = %d\n", val);
+#endif
+ if(val != -1)
+ {
+ sprintf((pbuf+strlen(pbuf)), "\t Operation Value = %s (%d)\n", opval_str(val), val);
+ state = ST_EXP_RR_RESULT;
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * return result: RESULT
+ *---------------------------------------------------------------------------*/
+static void
+F_RRR(char *pbuf, int val)
+{
+#ifdef ST_DEBUG
+ sprintf((pbuf+strlen(pbuf)), "next_state: exec F_RRR, val = %d\n", val);
+#endif
+ state = ST_EXP_NIX;
+}
+
+/*---------------------------------------------------------------------------*
+ *
+ *---------------------------------------------------------------------------*/
+static void
+F_4(char *pbuf, int val)
+{
+#ifdef ST_DEBUG
+ sprintf((pbuf+strlen(pbuf)), "next_state: exec F_4, val = %d\n", val);
+#endif
+ if(val == -1)
+ {
+ sprintf((pbuf+strlen(pbuf)), "\t specificChargingUnits\n");
+ state = ST_EXP_RUL;
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ *
+ *---------------------------------------------------------------------------*/
+static void
+F_4_1(char *pbuf, int val)
+{
+#ifdef ST_DEBUG
+ sprintf((pbuf+strlen(pbuf)), "next_state: exec F_4_1, val = %d\n", val);
+#endif
+ if(val == -1)
+ {
+ sprintf((pbuf+strlen(pbuf)), "\t freeOfCharge\n");
+ state = ST_EXP_NIX;
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ *
+ *---------------------------------------------------------------------------*/
+static void
+F_4_2(char *pbuf, int val)
+{
+#ifdef ST_DEBUG
+ sprintf((pbuf+strlen(pbuf)), "next_state: exec F_4_2, val = %d\n", val);
+#endif
+ if(val == -1)
+ {
+ sprintf((pbuf+strlen(pbuf)), "\t chargeNotAvailable\n");
+ state = ST_EXP_NIX;
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ *
+ *---------------------------------------------------------------------------*/
+static void
+F_5(char *pbuf, int val)
+{
+#ifdef ST_DEBUG
+ sprintf((pbuf+strlen(pbuf)), "next_state: exec F_5, val = %d\n", val);
+#endif
+ if(val == -1)
+ {
+ sprintf((pbuf+strlen(pbuf)), "\t recordedUnitsList [1]\n");
+ state = ST_EXP_RU;
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ *
+ *---------------------------------------------------------------------------*/
+static void
+F_6(char *pbuf, int val)
+{
+#ifdef ST_DEBUG
+ sprintf((pbuf+strlen(pbuf)), "next_state: exec F_6, val = %d\n", val);
+#endif
+ if(val == -1)
+ {
+ sprintf((pbuf+strlen(pbuf)), "\t RecordedUnits\n");
+ state = ST_EXP_RNOU;
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ *
+ *---------------------------------------------------------------------------*/
+static void
+F_7(char *pbuf, int val)
+{
+#ifdef ST_DEBUG
+ sprintf((pbuf+strlen(pbuf)), "next_state: exec F_7, val = %d\n", val);
+#endif
+ if(val != -1)
+ {
+ sprintf((pbuf+strlen(pbuf)), "\t NumberOfUnits = %d\n", val);
+ state = ST_EXP_TOCI;
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ *
+ *---------------------------------------------------------------------------*/
+static void
+F_8(char *pbuf, int val)
+{
+#ifdef ST_DEBUG
+ sprintf((pbuf+strlen(pbuf)), "next_state: exec F_8, val = %d\n", val);
+#endif
+ if(val != -1)
+ {
+ sprintf((pbuf+strlen(pbuf)), "\t typeOfChargingInfo = %s\n", val == 0 ? "subTotal" : "total");
+ state = ST_EXP_DBID;
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ *
+ *---------------------------------------------------------------------------*/
+static void
+F_9(char *pbuf, int val)
+{
+#ifdef ST_DEBUG
+ sprintf((pbuf+strlen(pbuf)), "next_state: exec F_9, val = %d\n", val);
+#endif
+ if(val != -1)
+ {
+ sprintf((pbuf+strlen(pbuf)), "\t AOCDBillingId = %s (%d)\n", bid_str(val), val);
+ state = ST_EXP_NIX;
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * state table
+ *---------------------------------------------------------------------------*/
+static struct statetab {
+ int currstate; /* input: current state we are in */
+ int form; /* input: current tag form */
+ int class; /* input: current tag class */
+ int code; /* input: current tag code */
+ void (*func)(char *,int); /* output: func to exec */
+} statetab[] = {
+
+/* current state tag form tag class tag code function */
+/* --------------------- ---------------------- ---------------------- ---------------------- ----------------*/
+
+/* invoke */
+
+ {ST_EXP_COMP_TYP, FAC_TAGFORM_CON, FAC_TAGCLASS_COS, 1, F_1_1 },
+ {ST_EXP_COMP_TYP, FAC_TAGFORM_CON, FAC_TAGCLASS_COS, 2, F_1_2 },
+ {ST_EXP_COMP_TYP, FAC_TAGFORM_CON, FAC_TAGCLASS_COS, 3, F_1_3 },
+ {ST_EXP_COMP_TYP, FAC_TAGFORM_CON, FAC_TAGCLASS_COS, 4, F_1_4 },
+ {ST_EXP_INV_ID, FAC_TAGFORM_PRI, FAC_TAGCLASS_UNI, FAC_CODEUNI_INT, F_2 },
+ {ST_EXP_OP_VAL, FAC_TAGFORM_PRI, FAC_TAGCLASS_UNI, FAC_CODEUNI_INT, F_3 },
+ {ST_EXP_INFO, FAC_TAGFORM_CON, FAC_TAGCLASS_UNI, FAC_CODEUNI_SEQ, F_4 },
+ {ST_EXP_INFO, FAC_TAGFORM_PRI, FAC_TAGCLASS_UNI, FAC_CODEUNI_NULL, F_4_1 },
+ {ST_EXP_INFO, FAC_TAGFORM_PRI, FAC_TAGCLASS_COS, 1, F_4_2 },
+ {ST_EXP_RUL, FAC_TAGFORM_CON, FAC_TAGCLASS_COS, 1, F_5 },
+ {ST_EXP_RU, FAC_TAGFORM_CON, FAC_TAGCLASS_UNI, FAC_CODEUNI_SEQ, F_6 },
+ {ST_EXP_RNOU, FAC_TAGFORM_PRI, FAC_TAGCLASS_UNI, FAC_CODEUNI_INT, F_7 },
+ {ST_EXP_TOCI, FAC_TAGFORM_PRI, FAC_TAGCLASS_COS, 2, F_8 },
+ {ST_EXP_DBID, FAC_TAGFORM_PRI, FAC_TAGCLASS_COS, 3, F_9 },
+
+/* return result */
+
+ {ST_EXP_RR_INV_ID, FAC_TAGFORM_PRI, FAC_TAGCLASS_UNI, FAC_CODEUNI_INT, F_RR2 },
+ {ST_EXP_RR_OP_VAL, FAC_TAGFORM_PRI, FAC_TAGCLASS_UNI, FAC_CODEUNI_INT, F_RR3 },
+ {ST_EXP_RR_RESULT, FAC_TAGFORM_CON, FAC_TAGCLASS_UNI, FAC_CODEUNI_SET, F_RRR },
+
+/* end */
+
+ {-1, -1, -1, -1, NULL }
+};
+
+/*---------------------------------------------------------------------------*
+ * state decode for do_component
+ *---------------------------------------------------------------------------*/
+static void
+next_state(char *pbuf, int class, int form, int code, int val)
+{
+ int i;
+
+#ifdef ST_DEBUG
+ sprintf((pbuf+strlen(pbuf)), "next_state: class=%d, form=%d, code=%d, val=%d\n", class, form, code, val);
+#endif
+
+ for(i=0; ; i++)
+ {
+ if((statetab[i].currstate > state) ||
+ (statetab[i].currstate == -1))
+ {
+ break;
+ }
+
+ if((statetab[i].currstate == state) &&
+ (statetab[i].form == form) &&
+ (statetab[i].class == class) &&
+ (statetab[i].code == code))
+ {
+ (*statetab[i].func)(pbuf, val);
+ break;
+ }
+ }
+}
+
+/* EOF */
+
diff --git a/usr.sbin/i4b/isdntrace/q932_fac.h b/usr.sbin/i4b/isdntrace/q932_fac.h
new file mode 100644
index 0000000..feae448
--- /dev/null
+++ b/usr.sbin/i4b/isdntrace/q932_fac.h
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * q932_fac.h - facility header file
+ * ---------------------------------
+ *
+ * $Id: q932_fac.h,v 1.4 1998/12/05 18:04:24 hm Exp $
+ *
+ * last edit-date: [Sat Dec 5 18:21:17 1998]
+ *
+ *---------------------------------------------------------------------------
+ *
+ * - Q.932 (03/93) Generic Procedures for the Control of
+ * ISDN Supplementaty Services
+ * - Q.950 (03/93) Supplementary Services Protocols, Structure and
+ * General Principles
+ * - ETS 300 179 (10/92) Advice Of Charge: charging information during
+ * the call (AOC-D) supplementary service Service description
+ * - ETS 300 180 (10/92) Advice Of Charge: charging information at the
+ * end of call (AOC-E) supplementary service Service description
+ * - ETS 300 181 (04/93) Advice Of Charge (AOC) supplementary service
+ * Functional capabilities and information flows
+ * - ETS 300 182 (04/93) Advice Of Charge (AOC) supplementary service
+ * Digital Subscriber Signalling System No. one (DSS1) protocol
+ * - X.208 Specification of Abstract Syntax Notation One (ASN.1)
+ * - X.209 Specification of Basic Encoding Rules for
+ * Abstract Syntax Notation One (ASN.1)
+ * - "ASN.1 Abstract Syntax Notation One", Walter Gora, DATACOM-Verlag
+ * 1992, 3rd Edition (ISBN 3-89238-062-7) (german !)
+ *
+ *---------------------------------------------------------------------------*/
+
+/* #define FAC_DEBUG */
+/* #define ST_DEBUG */
+
+/* protocols */
+#define FAC_PROTO_ROP 0x11
+#define FAC_PROTO_CMIP 0x12
+#define FAC_PROTO_ACSE 0x13
+
+/* tag classes */
+#define FAC_TAGCLASS_UNI 0x00
+#define FAC_TAGCLASS_APW 0x01
+#define FAC_TAGCLASS_COS 0x02
+#define FAC_TAGCLASS_PRU 0x03
+
+/* tag forms */
+#define FAC_TAGFORM_PRI 0x00
+#define FAC_TAGFORM_CON 0x01
+
+/* class UNIVERSAL values */
+#define FAC_CODEUNI_BOOL 1
+#define FAC_CODEUNI_INT 2
+#define FAC_CODEUNI_BITS 3
+#define FAC_CODEUNI_OCTS 4
+#define FAC_CODEUNI_NULL 5
+#define FAC_CODEUNI_OBJI 6
+#define FAC_CODEUNI_OBJD 7
+#define FAC_CODEUNI_EXT 8
+#define FAC_CODEUNI_REAL 9
+#define FAC_CODEUNI_ENUM 10
+#define FAC_CODEUNI_R11 11
+#define FAC_CODEUNI_R12 12
+#define FAC_CODEUNI_R13 13
+#define FAC_CODEUNI_R14 14
+#define FAC_CODEUNI_R15 15
+#define FAC_CODEUNI_SEQ 16
+#define FAC_CODEUNI_SET 17
+#define FAC_CODEUNI_NSTR 18
+#define FAC_CODEUNI_PSTR 19
+#define FAC_CODEUNI_TSTR 20
+#define FAC_CODEUNI_VSTR 21
+#define FAC_CODEUNI_ISTR 22
+#define FAC_CODEUNI_UTIME 23
+#define FAC_CODEUNI_GTIME 24
+#define FAC_CODEUNI_GSTR 25
+#define FAC_CODEUNI_VISTR 26
+#define FAC_CODEUNI_GNSTR 27
+
+/* operation values */
+#define FAC_OPVAL_UUS 1
+#define FAC_OPVAL_CUG 2
+#define FAC_OPVAL_MCID 3
+#define FAC_OPVAL_BTPY 4
+#define FAC_OPVAL_ETPY 5
+#define FAC_OPVAL_ECT 6
+
+#define FAC_OPVAL_DIV_ACT 7
+#define FAC_OPVAL_DIV_DEACT 8
+#define FAC_OPVAL_DIV_ACTSN 9
+#define FAC_OPVAL_DIV_DEACTSN 10
+#define FAC_OPVAL_DIV_INTER 11
+#define FAC_OPVAL_DIV_INFO 12
+#define FAC_OPVAL_DIV_CALLDEF 13
+#define FAC_OPVAL_DIV_CALLRER 14
+#define FAC_OPVAL_DIV_LINF2 15
+#define FAC_OPVAL_DIV_INVS 16
+#define FAC_OPVAL_DIV_INTER1 17
+#define FAC_OPVAL_DIV_LINF1 18
+#define FAC_OPVAL_DIV_LINF3 19
+
+#define FAC_OPVAL_ER_CRCO 20
+#define FAC_OPVAL_ER_MGMT 21
+#define FAC_OPVAL_ER_CANC 22
+
+#define FAC_OPVAL_MLPP_QUERY 24
+#define FAC_OPVAL_MLPP_CALLR 25
+#define FAC_OPVAL_MLPP_CALLP 26
+
+#define FAC_OPVAL_AOC_REQ 30
+#define FAC_OPVAL_AOC_S_CUR 31
+#define FAC_OPVAL_AOC_S_SPC 32
+#define FAC_OPVAL_AOC_D_CUR 33
+#define FAC_OPVAL_AOC_D_UNIT 34
+#define FAC_OPVAL_AOC_E_CUR 35
+#define FAC_OPVAL_AOC_E_UNIT 36
+#define FAC_OPVAL_AOC_IDOFCRG 37
+
+#define FAC_OPVAL_CONF_BEG 40
+#define FAC_OPVAL_CONF_ADD 41
+#define FAC_OPVAL_CONF_SPLIT 42
+#define FAC_OPVAL_CONF_DROP 43
+#define FAC_OPVAL_CONF_ISOLATE 44
+#define FAC_OPVAL_CONF_REATT 45
+#define FAC_OPVAL_CONF_PDISC 46
+#define FAC_OPVAL_CONF_FCONF 47
+#define FAC_OPVAL_CONF_END 48
+#define FAC_OPVAL_CONF_IDCFE 49
+
+#define FAC_OPVAL_REVC_REQ 60
+
+enum states {
+ ST_EXP_COMP_TYP,
+ ST_EXP_INV_ID,
+ ST_EXP_OP_VAL,
+ ST_EXP_INFO,
+ ST_EXP_RUL,
+ ST_EXP_RU,
+ ST_EXP_RNOU,
+ ST_EXP_TOCI,
+ ST_EXP_DBID,
+
+ ST_EXP_RR_INV_ID,
+ ST_EXP_RR_OP_VAL,
+ ST_EXP_RR_RESULT,
+
+ ST_EXP_NIX
+};
+
+/* EOF */
+
diff --git a/usr.sbin/i4b/isdntrace/trace.c b/usr.sbin/i4b/isdntrace/trace.c
new file mode 100644
index 0000000..a9dde80
--- /dev/null
+++ b/usr.sbin/i4b/isdntrace/trace.c
@@ -0,0 +1,809 @@
+/*
+ * Copyright (c) 1996, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Copyright (c) 1996 Gary Jennejohn. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 4. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software and/or documentation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------*
+ *
+ * trace.c - print traces of D (B) channel activity for isdn4bsd
+ * -------------------------------------------------------------
+ *
+ * $Id: trace.c,v 1.10 1998/10/19 12:32:21 hm Exp $
+ *
+ * last edit-date: [Mon Oct 19 14:30:58 1998]
+ *
+ * -hm rewriting for isic and new trace format
+ * -hm new option -f, use automatic name for -o
+ * -hm changed default option setting
+ * -hm multi unit support
+ * -hm analyzer functionality
+ * -hm binary record/playback
+ * -hm -p option
+ * -hm cleanup
+ * -hm adding date to timestamp field
+ * -hm reopen files on SIGUSR1 for rotation
+ * -hm Joerg reported a bug with commandline options
+ * -hm I.430 INFO signals from layer 1
+ *
+ *---------------------------------------------------------------------------*/
+
+#include "trace.h"
+
+unsigned char buf[BSIZE];
+FILE *Fout = NULL;
+FILE *BP = NULL;
+int outflag = 1;
+int header = 1;
+int print_q921 = 1;
+int unit = 0;
+int dchan = 0;
+int bchan = 0;
+int traceon = 0;
+int analyze = 0;
+int Rx = RxUDEF;
+int Tx = TxUDEF;
+int f;
+int Bopt = 0;
+int Popt = 0;
+int bpopt = 0;
+int info = 0;
+int Fopt = 0;
+
+static char outfilename[1024];
+static char BPfilename[1024];
+static struct stat fst;
+
+static void dumpbuf( int n, unsigned char *buf, i4b_trace_hdr_t *hdr, int raw );
+static int switch_driver( int value, int rx, int tx );
+static void usage( void );
+static void exit_hdl( void );
+static void reopenfiles( int );
+
+/*---------------------------------------------------------------------------*
+ * usage instructions
+ *---------------------------------------------------------------------------*/
+void
+usage(void)
+{
+ fprintf(stderr,"\n");
+ fprintf(stderr,"isdntrace - i4b package ISDN trace facility for passive cards (%02d.%02d.%d)\n", VERSION, REL, STEP);
+ fprintf(stderr,"usage: isdntrace -a -b -d -f <file> -h -i -l -n <val> -o -p <file> -r -u <unit>\n");
+ fprintf(stderr," -B -F -P -R <unit> -T <unit>\n");
+ fprintf(stderr," -a analyzer mode ................................... (default off)\n");
+ fprintf(stderr," -b switch B channel trace on ....................... (default off)\n");
+ fprintf(stderr," -d switch D channel trace off ....................... (default on)\n");
+ fprintf(stderr," -f <file> write output to file filename ............ (default %s0)\n", TRACE_FILE_NAME);
+ fprintf(stderr," -h don't print header for each message ............. (default off)\n");
+ fprintf(stderr," -i print I.430 (layer 1) INFO signals .............. (default off)\n");
+ fprintf(stderr," -l don't decode low layer Q.921 messages ........... (default off)\n");
+ fprintf(stderr," -n <val> process packet if it is longer than <val> octetts . (default 0)\n");
+ fprintf(stderr," -o don't write output to a file .................... (default off)\n");
+ fprintf(stderr," -p <file> specify filename for -B and -P ........ (default %s0)\n", BIN_FILE_NAME);
+ fprintf(stderr," -r don't print raw hex/ASCII dump of protocol ...... (default off)\n");
+ fprintf(stderr," -u <unit> specify controller unit number ............... (default unit 0)\n");
+ fprintf(stderr," -B write binary trace data to file filename ........ (default off)\n");
+ fprintf(stderr," -F with -P and -p: wait for more data at EOF ....... (default off)\n");
+ fprintf(stderr," -P playback from binary trace data file ............ (default off)\n");
+ fprintf(stderr," -R <unit> analyze Rx controller unit number (for -a) ... (default unit %d)\n", RxUDEF);
+ fprintf(stderr," -T <unit> analyze Tx controller unit number (for -a) ... (default unit %d)\n", TxUDEF);
+ fprintf(stderr,"\n");
+ exit(1);
+}
+
+/*---------------------------------------------------------------------------*
+ * main
+ *---------------------------------------------------------------------------*/
+int
+main(int argc, char *argv[])
+{
+ extern int optind;
+ extern int opterr;
+ extern char *optarg;
+ char devicename[80];
+ char headerbuf[256];
+
+ int n;
+ int c;
+ char *b;
+
+ int enable_trace = TRACE_D_RX | TRACE_D_TX;
+ char *outfile = TRACE_FILE_NAME;
+ char *binfile = BIN_FILE_NAME;
+ int outfileset = 0;
+ int raw = 1;
+ int noct = -1;
+ time_t tm;
+ i4b_trace_hdr_t *ithp = NULL;
+ int l;
+ static struct stat fstnew;
+
+ b = &buf[sizeof(i4b_trace_hdr_t)];
+
+ while( (c = getopt(argc, argv, "abdf:hiln:op:ru:BFPR:T:?")) != EOF)
+ {
+ switch(c)
+ {
+ case 'a':
+ analyze = 1;
+ break;
+
+ case 'b':
+ enable_trace |= (TRACE_B_RX | TRACE_B_TX);
+ break;
+
+ case 'd':
+ enable_trace &= (~(TRACE_D_TX | TRACE_D_RX));
+ break;
+
+ case 'o':
+ outflag = 0;
+ break;
+
+ case 'f':
+ outfile = optarg;
+ outfileset = 1;
+ break;
+
+ case 'n':
+ noct = atoi(optarg);
+ break;
+
+ case 'h':
+ header = 0;
+ break;
+
+ case 'i':
+ enable_trace |= TRACE_I;
+ info = 1;
+ break;
+
+ case 'l':
+ print_q921 = 0;
+ break;
+
+ case 'p':
+ binfile = optarg;
+ bpopt = 1;
+ break;
+
+ case 'r':
+ raw = 0;
+ break;
+
+ case 'u':
+ unit = atoi(optarg);
+ if(unit < 0 || unit >= MAX_CONTROLLERS)
+ usage();
+ break;
+
+ case 'B':
+ Bopt = 1;
+ break;
+
+ case 'F':
+ Fopt = 1;
+ break;
+
+ case 'P':
+ Popt = 1;
+ break;
+
+ case 'R':
+ Rx = atoi(optarg);
+ if(Rx < 0 || Rx >= MAX_CONTROLLERS)
+ usage();
+ break;
+
+ case 'T':
+ Tx = atoi(optarg);
+ if(Tx < 0 || Tx >= MAX_CONTROLLERS)
+ usage();
+ break;
+
+ case '?':
+ default:
+ usage();
+ break;
+ }
+ }
+
+ if(enable_trace == 0)
+ usage();
+
+ if(Bopt && Popt)
+ usage();
+
+ atexit(exit_hdl);
+
+ if(Bopt)
+ {
+ if(bpopt)
+ sprintf(BPfilename, "%s", binfile);
+ else
+ sprintf(BPfilename, "%s%d", BIN_FILE_NAME, unit);
+
+ if((BP = fopen(BPfilename, "r")) != NULL)
+ {
+ char buffer[1024];
+ fclose(BP);
+ sprintf(buffer, "%s%s", BPfilename, TRACE_FILE_NAME_BAK);
+ rename(BPfilename, buffer);
+ }
+ if((BP = fopen(BPfilename, "w")) == NULL)
+ {
+ char buffer[80];
+
+ sprintf(buffer, "Error opening file [%s]", BPfilename);
+ perror(buffer);
+ exit(1);
+ }
+
+ if((setvbuf(BP, (char *)NULL, _IONBF, 0)) != 0)
+ {
+ char buffer[80];
+
+ sprintf(buffer, "Error setting file [%s] to unbuffered", BPfilename);
+ perror(buffer);
+ exit(1);
+ }
+ }
+
+ if(Popt)
+ {
+ if(bpopt)
+ sprintf(BPfilename, "%s", binfile);
+ else
+ sprintf(BPfilename, "%s%d", BIN_FILE_NAME, unit);
+
+ if((BP = fopen(BPfilename, "r")) == NULL)
+ {
+ char buffer[80];
+
+ sprintf(buffer, "Error opening file [%s]", BPfilename);
+ perror(buffer);
+ exit(1);
+ }
+ if(Fopt)
+ {
+ if(fstat(fileno(BP), &fst))
+ {
+ char buffer[80];
+ sprintf(buffer, "Error fstat file [%s]", BPfilename);
+ perror(buffer);
+ exit(1);
+ }
+ }
+ }
+ else
+ {
+ sprintf(devicename, "%s%d", I4BTRC_DEVICE, unit);
+
+ if((f = open(devicename, O_RDWR)) < 0)
+ {
+ char buffer[80];
+
+ sprintf(buffer, "Error opening trace device [%s]", devicename);
+ perror(buffer);
+ exit(1);
+ }
+ }
+
+ if(outflag)
+ {
+ if(outfileset == 0)
+ sprintf(outfilename, "%s%d", TRACE_FILE_NAME, unit);
+ else
+ strcpy(outfilename, outfile);
+
+
+ if((Fout = fopen(outfilename, "r")) != NULL)
+ {
+ char buffer[1024];
+ fclose(Fout);
+ sprintf(buffer, "%s%s", outfilename, TRACE_FILE_NAME_BAK);
+ rename(outfilename, buffer);
+ }
+
+ if((Fout = fopen(outfilename, "w")) == NULL)
+ {
+ char buffer[80];
+
+ sprintf(buffer, "Error opening file [%s]", outfilename);
+ perror(buffer);
+ exit(1);
+ }
+
+ if((setvbuf(Fout, (char *)NULL, _IONBF, 0)) != 0)
+ {
+ char buffer[80];
+
+ sprintf(buffer, "Error setting file [%s] to unbuffered", outfile);
+ perror(buffer);
+ exit(1);
+ }
+ }
+
+ if((setvbuf(stdout, (char *)NULL, _IOLBF, 0)) != 0)
+ {
+ char buffer[80];
+
+ sprintf(buffer, "Error setting stdout to line-buffered");
+ perror(buffer);
+ exit(1);
+ }
+
+ if(!Popt)
+ {
+ if((switch_driver(enable_trace, Rx, Tx)) == -1)
+ exit(1);
+ else
+ traceon = 1;
+ }
+
+ signal(SIGHUP, SIG_IGN); /* ignore hangup signal */
+ signal(SIGUSR1, reopenfiles); /* rotate logfile(s) */
+
+ time(&tm);
+
+ if(analyze)
+ {
+ sprintf(headerbuf, "\n==== isdnanalyze controller rx #%d - tx #%d ==== started %s",
+ Rx, Tx, ctime(&tm));
+ }
+ else
+ {
+ sprintf(headerbuf, "\n=========== isdntrace controller #%d =========== started %s",
+ unit, ctime(&tm));
+ }
+
+ printf("%s", headerbuf);
+
+ if(outflag)
+ fprintf(Fout, "%s", headerbuf);
+
+ for (;;)
+ {
+ if(Popt == 0)
+ {
+ n = read(f, buf, BSIZE);
+
+ if(Bopt)
+ {
+ if((fwrite(buf, 1, n, BP)) != n)
+ {
+ char buffer[80];
+ sprintf(buffer, "Error writing file [%s]", BPfilename);
+ perror(buffer);
+ exit(1);
+ }
+ }
+
+ n -= sizeof(i4b_trace_hdr_t);
+ }
+ else
+ {
+again:
+ if((fread(buf, 1, sizeof(i4b_trace_hdr_t), BP)) != sizeof(i4b_trace_hdr_t))
+ {
+ if(feof(BP))
+ {
+ if(Fopt)
+ {
+ if(ferror(BP))
+ {
+ char buffer[80];
+ sprintf(buffer, "Error reading hdr from file [%s]", BPfilename);
+ perror(buffer);
+ exit(1);
+ }
+
+ usleep(250000);
+ clearerr(BP);
+
+ if(stat(BPfilename, &fstnew) != -1)
+ {
+ if((fst.st_ino != fstnew.st_ino) ||
+ (fstnew.st_nlink == 0))
+ {
+ if((BP = freopen(BPfilename, "r", BP)) == NULL)
+ {
+ char buffer[80];
+ sprintf(buffer, "Error reopening file [%s]", BPfilename);
+ perror(buffer);
+ exit(1);
+ }
+ stat(BPfilename, &fst);
+ }
+ }
+ goto again;
+ }
+ else
+ {
+ printf("\nEnd of playback input file reached.\n");
+ exit(0);
+ }
+ }
+ else
+ {
+ char buffer[80];
+ sprintf(buffer, "Error reading hdr from file [%s]", BPfilename);
+ perror(buffer);
+ exit(1);
+ }
+ }
+
+ ithp = (i4b_trace_hdr_t *)buf;
+ l = ithp->length - sizeof(i4b_trace_hdr_t);
+
+ if((n = fread(buf+sizeof(i4b_trace_hdr_t), 1, l , BP)) != l)
+ {
+ char buffer[80];
+ sprintf(buffer, "Error reading data from file [%s]", BPfilename);
+ perror(buffer);
+ exit(1);
+ }
+
+ }
+
+ if((n > 0) && (n > noct))
+ {
+ dumpbuf(n, b, (i4b_trace_hdr_t *)buf, raw);
+ }
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * format header into static buffer, return buffer address
+ *---------------------------------------------------------------------------*/
+char *
+fmt_hdr(i4b_trace_hdr_t *hdr, int frm_len)
+{
+ struct tm *s;
+ static char hbuf[256];
+ int i = 0;
+
+ s = localtime(&(hdr->time.tv_sec));
+
+ if(hdr->type == TRC_CH_I) /* Layer 1 INFO's */
+ {
+ sprintf(hbuf,"\n-- %s - unit:%d ---------------- time:%2.2d.%2.2d %2.2d:%2.2d:%2.2d.%6u ",
+ ((hdr->dir) ? "NT->TE" : "TE->NT"),
+ hdr->unit,
+ s->tm_mday,
+ s->tm_mon + 1,
+ s->tm_hour,
+ s->tm_min,
+ s->tm_sec,
+ (u_int32_t)hdr->time.tv_usec);
+ }
+ else
+ {
+ if(hdr->trunc > 0)
+ {
+ sprintf(hbuf,"\n-- %s - unit:%d - frame:%6.6u - time:%2.2d.%2.2d %2.2d:%2.2d:%2.2d.%6u - length:%d (%d) ",
+ ((hdr->dir) ? "NT->TE" : "TE->NT"),
+ hdr->unit,
+ hdr->count,
+ s->tm_mday,
+ s->tm_mon + 1,
+ s->tm_hour,
+ s->tm_min,
+ s->tm_sec,
+ (u_int32_t)hdr->time.tv_usec,
+ frm_len,
+ hdr->trunc);
+ }
+ else
+ {
+ sprintf(hbuf,"\n-- %s - unit:%d - frame:%6.6u - time:%2.2d.%2.2d %2.2d:%2.2d:%2.2d.%6u - length:%d ",
+ ((hdr->dir) ? "NT->TE" : "TE->NT"),
+ hdr->unit,
+ hdr->count,
+ s->tm_mday,
+ s->tm_mon + 1,
+ s->tm_hour,
+ s->tm_min,
+ s->tm_sec,
+ (u_int32_t)hdr->time.tv_usec,
+ frm_len);
+ }
+ }
+
+ for(i=strlen(hbuf); i <= NCOLS;)
+ hbuf[i++] = '-';
+
+ hbuf[i++] = '\n';
+ hbuf[i] = '\0';
+
+ return(hbuf);
+}
+
+/*---------------------------------------------------------------------------*
+ * decode protocol and output to file(s)
+ *---------------------------------------------------------------------------*/
+static void
+dumpbuf(int n, unsigned char *buf, i4b_trace_hdr_t *hdr, int raw)
+{
+ static char l1buf[128];
+ static unsigned char l2buf[32000];
+ static unsigned char l3buf[32000];
+ int cnt;
+ int nsave = n;
+ char *pbuf;
+ int i, j;
+
+ l1buf[0] = '\0';
+ l2buf[0] = '\0';
+ l3buf[0] = '\0';
+
+ switch(hdr->type)
+ {
+ case TRC_CH_I: /* Layer 1 INFO's */
+ pbuf = &l1buf[0];
+
+ switch(buf[0])
+ {
+ case INFO0:
+ sprintf((pbuf+strlen(pbuf)),"I430: INFO0 (No Signal)\n");
+ break;
+
+ case INFO1_8:
+ sprintf((pbuf+strlen(pbuf)),"I430: INFO1 (Activation Request, Priority = 8, from TE)\n");
+ break;
+
+ case INFO1_10:
+ sprintf((pbuf+strlen(pbuf)),"I430: INFO1 (Activation Request, Priority = 10, from TE)\n");
+ break;
+
+ case INFO2:
+ sprintf((pbuf+strlen(pbuf)),"I430: INFO2 (Pending Activation, from NT)\n");
+ break;
+
+ case INFO3:
+ sprintf((pbuf+strlen(pbuf)),"I430: INFO3 (Synchronized, from TE)\n");
+ break;
+
+ case INFO4_8:
+ sprintf((pbuf+strlen(pbuf)),"I430: INFO4 (Activated, Priority = 8/9, from NT)\n");
+ break;
+
+ case INFO4_10:
+ sprintf((pbuf+strlen(pbuf)),"I430: INFO4 (Activated, Priority = 10/11, from NT)\n");
+ break;
+
+ default:
+ sprintf((pbuf+strlen(pbuf)),"I430: ERROR, invalid INFO value 0x%x!\n", buf[0]);
+ break;
+ }
+ break;
+
+ case TRC_CH_D: /* D-channel data */
+
+ cnt = decode_lapd(l2buf, n, buf, hdr->dir, raw, print_q921);
+
+ n -= cnt;
+ buf += cnt;
+
+ if(n)
+ {
+ switch(*buf)
+ {
+ case 0x40:
+ case 0x41:
+ decode_1tr6(l3buf, n, cnt, buf, raw);
+ break;
+
+ default:
+ decode_q931(l3buf, n, cnt, buf, raw);
+ break;
+ }
+ }
+ break;
+
+ default: /* B-channel data */
+
+ pbuf = &l2buf[0];
+
+ for (i = 0; i < n; i += 16)
+ {
+ sprintf((pbuf+strlen(pbuf)),"B%d:%.3x ", hdr->type, i);
+
+ for (j = 0; j < 16; j++)
+ if (i + j < n)
+ sprintf((pbuf+strlen(pbuf)),"%02x ", buf[i + j]);
+ else
+ sprintf((pbuf+strlen(pbuf))," ");
+
+ sprintf((pbuf+strlen(pbuf))," ");
+
+ for (j = 0; j < 16 && i + j < n; j++)
+ if (isprint(buf[i + j]))
+ sprintf((pbuf+strlen(pbuf)),"%c", buf[i + j]);
+ else
+ sprintf((pbuf+strlen(pbuf)),".");
+
+ sprintf((pbuf+strlen(pbuf)),"\n");
+ }
+ break;
+ }
+
+ if(header && ((l1buf[0] != '\0' || l2buf[0] != '\0') || (l3buf[0] != 0)))
+ {
+ char *p;
+ p = fmt_hdr(hdr, nsave);
+ printf("%s", p);
+ if(outflag)
+ fprintf(Fout, "%s", p);
+ }
+
+ if(l1buf[0] != '\0')
+ {
+ printf("%s", l1buf);
+ if(outflag)
+ fprintf(Fout, "%s", l1buf);
+ }
+
+ if(l2buf[0] != '\0')
+ {
+ printf("%s", l2buf);
+ if(outflag)
+ fprintf(Fout, "%s", l2buf);
+ }
+
+ if(l3buf[0] != '\0')
+ {
+ printf("%s", l3buf);
+ if(outflag)
+ fprintf(Fout, "%s", l3buf);
+ }
+}
+
+/*---------------------------------------------------------------------------*
+ * exit handler function to be called at program exit
+ *---------------------------------------------------------------------------*/
+void
+exit_hdl()
+{
+ if(traceon)
+ switch_driver(TRACE_OFF, Rx, Tx);
+}
+
+/*---------------------------------------------------------------------------*
+ * switch driver debugging output on/off
+ *---------------------------------------------------------------------------*/
+static int
+switch_driver(int value, int rx, int tx)
+{
+ char buffer[80];
+ int v = value;
+
+ if(analyze == 0)
+ {
+ if(ioctl(f, I4B_TRC_SET, &v) < 0)
+ {
+ sprintf(buffer, "Error ioctl I4B_TRC_SET, val = %d", v);
+ perror(buffer);
+ return(-1);
+ }
+ }
+ else
+ {
+ if(value == TRACE_OFF)
+ {
+ if(ioctl(f, I4B_TRC_RESETA, &v) < 0)
+ {
+ sprintf(buffer, "Error ioctl I4B_TRC_RESETA - ");
+ perror(buffer);
+ return(-1);
+ }
+ }
+ else
+ {
+ i4b_trace_setupa_t tsa;
+
+ tsa.rxunit = rx;
+ tsa.rxflags = value;
+ tsa.txunit = tx;
+ tsa.txflags = value;
+
+ if(ioctl(f, I4B_TRC_SETA, &tsa) < 0)
+ {
+ sprintf(buffer, "Error ioctl I4B_TRC_SETA, val = %d", v);
+ perror(buffer);
+ return(-1);
+ }
+ }
+ }
+ return(0);
+}
+
+/*---------------------------------------------------------------------------*
+ * reopen files to support rotating logfile(s) on SIGUSR1
+ *
+ * based on an idea from Ripley (ripley@nostromo.in-berlin.de)
+ *
+ * close file and reopen it for append. this will be a nop
+ * if the previously opened file hasn't moved but will open
+ * a new one otherwise, thus enabling a rotation...
+ *
+ *---------------------------------------------------------------------------*/
+static void
+reopenfiles(int dummy)
+{
+ if(outflag)
+ {
+ fclose(Fout);
+
+ if((Fout = fopen(outfilename, "a")) == NULL)
+ {
+ char buffer[80];
+
+ sprintf(buffer, "Error re-opening file [%s]", outfilename);
+ perror(buffer);
+ exit(1);
+ }
+
+ if((setvbuf(Fout, (char *)NULL, _IONBF, 0)) != 0)
+ {
+ char buffer[80];
+
+ sprintf(buffer, "Error re-setting file [%s] to unbuffered", outfilename);
+ perror(buffer);
+ exit(1);
+ }
+ }
+
+ if(Bopt)
+ {
+
+ fclose(BP);
+
+ if((BP = fopen(BPfilename, "a")) == NULL)
+ {
+ char buffer[80];
+
+ sprintf(buffer, "Error re-opening file [%s]", BPfilename);
+ perror(buffer);
+ exit(1);
+ }
+
+ if((setvbuf(BP, (char *)NULL, _IONBF, 0)) != 0)
+ {
+ char buffer[80];
+
+ sprintf(buffer, "Error re-setting file [%s] to unbuffered", BPfilename);
+ perror(buffer);
+ exit(1);
+ }
+ }
+}
+
+
+/* EOF */
diff --git a/usr.sbin/i4b/isdntrace/trace.h b/usr.sbin/i4b/isdntrace/trace.h
new file mode 100644
index 0000000..e4c5b5a
--- /dev/null
+++ b/usr.sbin/i4b/isdntrace/trace.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 1996, 1998 Hellmuth Michaelis. All rights reserved.
+ *
+ * Copyright (c) 1996 Gary Jennejohn. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 4. Altered versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software and/or documentation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *---------------------------------------------------------------------------
+ *
+ * trace.h - header file for isdn trace
+ * ------------------------------------
+ *
+ * $Id: trace.h,v 1.7 1998/10/19 12:32:23 hm Exp $
+ *
+ * last edit-date: [Mon Oct 19 14:27:21 1998]
+ *
+ * -hm splitting
+ * -hm new filenames
+ *
+ *---------------------------------------------------------------------------*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/uio.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+
+#include <machine/i4b_ioctl.h>
+#include <machine/i4b_trace.h>
+
+#include "pcause_1tr6.h" /* obsolete german national ISDN */
+#include "pcause_q850.h"
+
+#define I4BTRC_DEVICE "/dev/i4btrc" /* trace device file */
+#define TRACE_FILE_NAME "isdntrace" /* default output filename */
+#define TRACE_FILE_NAME_BAK ".last" /* backup filename trailer */
+#define BIN_FILE_NAME "isdntracebin" /* default binary filename */
+
+#define BSIZE 4096 /* read buffer size */
+#define NCOLS 80 /* screen width */
+
+#define RxUDEF 0 /* analyze mode, default unit for receiver side */
+#define TxUDEF 1 /* analyze mode, default unit for transmitter side */
+
+int decode_lapd(char *pbuf, int n, unsigned char *buf, int is_te, int raw, int printit);
+void decode_q931(char *pbuf, int n, int off, unsigned char *buf, int raw);
+void decode_1tr6(char *pbuf, int n, int off, unsigned char *buf, int raw);
+char *print_error(int prot, unsigned char code);
+int q931_facility(char *pbuf, unsigned char *buf);
+int p_q931cause(char *pbuf, unsigned char *buf);
+int p_q931address(char *pbuf, unsigned char *buf);
+int p_q931bc(char *pbuf, unsigned char *buf);
+int p_q931high_compat(char *pbuf, unsigned char *buf);
+int q932_facility(char *pbuf, unsigned char *buf);
+
+/* EOF */
diff --git a/usr.sbin/i4b/man/Makefile b/usr.sbin/i4b/man/Makefile
new file mode 100644
index 0000000..65248d6
--- /dev/null
+++ b/usr.sbin/i4b/man/Makefile
@@ -0,0 +1,5 @@
+MAN4 = i4b.4 i4bctl.4 i4bipr.4 i4bq921.4 i4bq931.4 i4brbch.4 i4btel.4 \
+ i4btrc.4 isic.4 daic.4 i4bisppp.4
+
+.include <bsd.prog.mk>
+
diff --git a/usr.sbin/i4b/man/daic.4 b/usr.sbin/i4b/man/daic.4
new file mode 100644
index 0000000..fc04797
--- /dev/null
+++ b/usr.sbin/i4b/man/daic.4
@@ -0,0 +1,98 @@
+.\" Copyright (c) 1997 Martin Husemann <martin@rumolt.teuto.de>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. The name of the author may not be used to endorse or promote products
+.\" derived from this software withough specific prior written permission
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $Id: daic.4,v 1.1 1998/02/03 12:43:07 hm Exp $
+.\"
+.\" last edit-date: [Fri Jan 30 22:49:48 1998]
+.\"
+.\" -mh writing manual pages
+.\"
+.\"
+.Dd January 30, 1998
+.Dt daic 4
+.Sh NAME
+.Nm daic
+.Nd isdn4bsd driver for EICON.Diehl active isdn cards
+.Pp
+The
+.Nm
+driver supports the old Diehl active cards:
+.Em S, SX, SXn, SCOM
+and
+.Em QUADRO.
+.Sh SYNOPSIS
+.Pp
+Use a config line like this
+.Cd "daic0 at isa? iomem 0xd8000 irq 10"
+.Pp
+For a
+.Em QUADRO
+card use the same, the driver will detect the board type and use
+all four ports, each attached as a controller of its own to the
+ISDN4BSD system, which can be listed using the isdnctl utility.
+.Sh DESCRIPTION
+The
+.Nm
+driver interfaces the isdn card to the ISDN4BSD kernel subsystem.
+All lower layer isdn control is handled by the card. This should
+allow you to run any national isdn protocol delivered by EICON.Diehl
+for your card, but the driver has only been tested with the DSS1
+protocol and some parts of the cards interface are isdn protocol
+dependend.
+.Pp
+The
+.Nm
+driver is written to conform to the software interface documented
+by Diehl in their
+.Nm ISDN-Karten Benutzerhandbuch
+from 1992.
+.Sh MICROCODE DOWNLOAD
+Every active card needs its own operating software before it can
+work. You have to download this to the card before using it with
+ISDN4BSD. Use the isdnctl utility to do this, i.e. call
+.Nm "isdnctl -d te_etsi.sx 1"
+to download the file
+.Nm te_etsi.sx
+to controller number 1. Use
+.Nm "isdnctl -l"
+to list all available controllers (and ports). You have to select the
+correct isdn protocol file for your isdn interface, see the Diehl documentation
+for details.
+.Pp
+The cards bootstrap process involves another file, which is independend
+of the card type you use and the protocol you run. It is called
+.Nm download.bin
+in current versions of the Diehl software distribution and has to be
+copied to the kernel compile directory under
+.Nm dev/ic/microcode/daic
+and converted into a header file used when compiling the kernel by running
+.Nm make
+in that directory. Your kernel compile will fail and remind you of this
+if you forget to do this. Due to copright restrictions we cannot distribute
+the driver with this file integrated. But if you own a card, you do have
+the file (or can get it from the Diehl web server).
+.Sh BUGS
+The driver is not yet finished. It will only compile on NetBSD and
+even there will not work. This should be fixed soon and the driver
+will be ported to FreeBSD.
+.Sh SEE ALSO
+.Xr isdnctl 1
diff --git a/usr.sbin/i4b/man/i4b.4 b/usr.sbin/i4b/man/i4b.4
new file mode 100644
index 0000000..f285c08
--- /dev/null
+++ b/usr.sbin/i4b/man/i4b.4
@@ -0,0 +1,108 @@
+.\"
+.\" Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id: i4b.4,v 1.6 1998/12/05 18:06:03 hm Exp $
+.\"
+.\" last edit-date: [Sat Dec 5 18:38:11 1998]
+.\"
+.Dd February 3, 1998
+.Dt i4b 4
+.Sh NAME
+.Nm i4b
+.Nd isdn4bsd call control ISDN driver
+.Sh FreeBSD SYNOPSIS
+.Cd pseudo-device \&"i4b\&"
+.Sh NetBSD SYNOPSIS
+none
+.Sh DESCRIPTION
+The
+.Nm
+device driver is used by the
+.Xr isdnd 8
+daemon to exchange messages with the isdn4bsd kernel part for the purpose
+of call establishment, control and disconnection and to access various
+control and status informations.
+.Pp
+The messages and message parameters are documented in the include
+file
+.Em /usr/include/machine/i4b_ioctl.h .
+.Pp
+The available ioctl's are:
+.Pp
+.Bl -tag -width Ds -compact -offset indent
+.It Ar I4B_CDID_REQ
+Request a unique Call Description IDentifier (cdid) which identifies
+uniquely a single interaction of the local D channel with the exchange.
+.It Ar I4B_CONNECT_REQ
+Actively request a call setup to a remote ISDN subscriber.
+.It Ar I4B_CONNECT_RESP
+Respond to an incoming call, either accept, reject or ignore it.
+.It Ar I4B_DISCONNECT_REQ
+Actively terminate a connection.
+.It Ar I4B_CTRL_INFO_REQ
+Request information about an installed ISDN controller card.
+.It Ar I4B_DIALOUT_RESP
+Give information about call setup to driver who requested dialing out.
+.It Ar I4B_TIMEOUT_UPD
+Update the kernels timeout value(s) in case of dynamically calculated
+shorthold mode timing changes.
+.It Ar I4B_UPDOWN_IND
+Inform the kernel userland drivers about interface soft up/down status
+changes.
+.It Ar I4B_CTRL_DOWNLOAD
+Download firmware to active card(s).
+.It Ar I4B_ACTIVE_DIAGNOSTIC
+Return diagnostic information from active cards.
+.El
+.Pp
+Status and event messages available from the kernel are:
+.Pp
+.Bl -tag -width Ds -compact -offset indent
+.It Ar MSG_CONNECT_IND
+An incoming call from a remote ISDN user is indicated.
+.It Ar MSG_CONNECT_ACTIVE_IND
+After an incoming call has been accepted locally or an outgoing call has
+been accepted by a remote, the exchange signaled an active connection
+and the corresponding B-channel is switched through.
+.It Ar MSG_DISCONNECT_IND
+A call was terminated.
+.It Ar MSG_DIALOUT_IND
+A userland interface driver requests the daemon to dial out (typically a
+network interface when a packet arrives in its send queue).
+.It Ar MSG_IDLE_TIMEOUT_IND
+A call was terminated by the isdn4bsd kernel driver because a B-channel
+idle timeout occurred.
+.It Ar MSG_ACCT_IND
+Accounting information from a network driver.
+.It Ar MSG_CHARGING_IND
+Charging information from the kernel.
+.El
+.Pp
+.Sh SEE ALSO
+.Xr isdnd 8
+.Sh AUTHOR
+The
+.Nm
+device driver and this manpage were written by Hellmuth Michaelis. He can be
+contacted at hm@kts.org.
diff --git a/usr.sbin/i4b/man/i4bctl.4 b/usr.sbin/i4b/man/i4bctl.4
new file mode 100644
index 0000000..fa5fccd
--- /dev/null
+++ b/usr.sbin/i4b/man/i4bctl.4
@@ -0,0 +1,50 @@
+.\"
+.\" Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id: i4bctl.4,v 1.4 1998/12/05 18:06:04 hm Exp $
+.\"
+.\" last edit-date: [Sat Dec 5 18:38:22 1998]
+.\"
+.Dd February 3, 1998
+.Dt i4bctl 4
+.Sh NAME
+.Nm i4bctl
+.Nd control device for the isdn4bsd kernel part
+.Sh FreeBSD SYNOPSIS
+.Cd pseudo-device \&"i4bctl\&"
+.Sh NetBSD SYNOPSIS
+none
+.Sh DESCRIPTION
+.Nm
+is used by the
+.Xr isdndebug 8
+utility to get and set the current debugging level and other information
+of the isdn4bsd package kernel ISDN handling layers.
+.Sh SEE ALSO
+.Xr isdndebug 8
+.Sh AUTHOR
+The
+.Nm
+device driver and this manpage were written by Hellmuth Michaelis. He can be
+contacted at hm@kts.org.
diff --git a/usr.sbin/i4b/man/i4bipr.4 b/usr.sbin/i4b/man/i4bipr.4
new file mode 100644
index 0000000..f4cdeac
--- /dev/null
+++ b/usr.sbin/i4b/man/i4bipr.4
@@ -0,0 +1,98 @@
+.\"
+.\" Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id: i4bipr.4,v 1.8 1998/12/05 18:06:06 hm Exp $
+.\"
+.\" last edit-date: [Sat Dec 5 18:38:34 1998]
+.\"
+.Dd July 6, 1998
+.Dt i4bipr 4
+.Sh NAME
+.Nm i4bipr
+.Nd isdn4bsd IP over ISDN B-channel network driver
+.Sh FreeBSD SYNOPSIS
+.Cd pseudo-device \&"i4bipr\&" Op count
+.Sh NetBSD SYNOPSIS
+none
+.Sh DESCRIPTION
+The
+.Nm
+driver interfaces the IP subsystem of the operating system with the
+isdn4bsd package so that transport of IP packets over an ISDN link
+is possible.
+.Pp
+The driver just packs IP packets without anything appended or prepended
+into raw HDLC packets on the B channel and transfers them to a remote site.
+IP packets received from the remote site are queued into the local IP
+protocol stack.
+.Pp
+The format of the resulting packet on the B channel is:
+.Pp
+.Dl (HDLC opening flag) (IP-packet) (CRC) (HDLC closing flag)
+.Pp
+In the case where an IP packet for a remote site arrives in the driver and no
+connection has been established yet, the driver communicates with the
+.Xr isdnd 8
+daemon to establish a connection.
+.Pp
+The driver has support for interfacing to the
+.Xr bpf 4
+subsystem for using
+.Xr tcpdump 1
+with the
+.Nm ipr
+interfaces.
+.Pp
+The driver optionally (when compiled with the IPR_VJ option) provides Van
+Jacobsen header compression, under control of the link0 and link1 options to
+.Xr ifconfig 8
+:
+.Pp
+.Bl -tag -width 15n -offset indent -compact
+.It link0
+Apply VJ compression to outgoing packets on this interface, and assume that
+incoming packets require decompression.
+.It link1
+Check incoming packets for Van Jacobsen compression; if they appear to be
+compressed, automatically set link0.
+.El
+.Pp
+The default values are
+.Em on
+for
+.Em link1
+and
+.Em off
+for
+.Em link0 .
+.Sh SEE ALSO
+.Xr isdnd 8
+.Xr isdnd.rc 5
+.Xr bpf 4
+.Xr tcpdump 1
+.Sh AUTHOR
+The
+.Nm
+device driver and this manpage were written by Hellmuth Michaelis. He can be
+contacted at hm@kts.org.
diff --git a/usr.sbin/i4b/man/i4bisppp.4 b/usr.sbin/i4b/man/i4bisppp.4
new file mode 100644
index 0000000..ce65b82
--- /dev/null
+++ b/usr.sbin/i4b/man/i4bisppp.4
@@ -0,0 +1,107 @@
+.\"
+.\" Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id: i4bisppp.4,v 1.9 1998/12/22 19:16:57 hm Exp $
+.\"
+.\" last edit-date: [Tue Dec 22 20:15:08 1998]
+.\"
+.Dd December 22, 1998
+.Dt i4bisppp 4
+.Sh NAME
+.Nm i4bisppp
+.Nd isdn4bsd synchronous PPP over ISDN B-channel network driver
+.Sh FreeBSD SYNOPSIS
+.Cd pseudo-device \&"i4bisppp\&" Op count
+.Sh NetBSD SYNOPSIS
+none
+.Sh DESCRIPTION
+The
+.Nm
+driver interfaces the IP subsystem of the operating system with the
+isdn4bsd package so that a transport of IP packets over an ISDN link
+is possible.
+.Pp
+The driver is just a glue layer between Serge Vakulenko's sppp
+backend and the ISDN4BSD package.
+.Pp
+In case an IP packet for a remote side arrives in the driver and no
+connection is established yet, the driver communicates with the
+.Xr isdnd 8
+daemon to establish a connection.
+.Pp
+The driver has support for interfacing to the
+.Xr bpf 4
+subsystem for using
+.Xr tcpdump 1
+with the
+.Nm isp
+interfaces.
+.Pp
+The
+.Xr spppcontrol 8
+utility is used to configure all aspects of PPP required to connect to a
+remote site.
+.Sh LINK0 and LINK1
+The
+.Em link0
+and
+.Em link1
+flags given as parameters to
+.Xr ifconfig 8
+have the following meaning for the
+.Nm isp
+devices:
+.Bl -tag -width link0 -compact
+.Pp
+.It Li link0
+wait passively for connection
+.Pp
+.It Li link1
+auto-dial on output
+.El
+.Pp
+The
+.Em link0
+and
+.Em link1
+flags are set to
+.Em off
+by default.
+.Pp
+See
+.Xr sppp 4
+for a more detailed discussion of the flags,
+.Pp
+.Sh SEE ALSO
+.Xr isdnd 8
+.Xr isdnd.rc 5
+.Xr spppcontrol 8
+.Xr sppp 4
+.Xr bpf 4
+.Xr tcpdump 1
+.Sh AUTHOR
+The
+.Nm
+device driver was written by Joerg Wunsch and then added to ISDN4BSD by Gary Jennejohn.
+This manpage was written by Hellmuth Michaelis. He can be contacted at hm@kts.org.
diff --git a/usr.sbin/i4b/man/i4bq921.4 b/usr.sbin/i4b/man/i4bq921.4
new file mode 100644
index 0000000..bb5bcfc
--- /dev/null
+++ b/usr.sbin/i4b/man/i4bq921.4
@@ -0,0 +1,49 @@
+.\"
+.\" Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id: i4bq921.4,v 1.5 1998/12/05 18:06:08 hm Exp $
+.\"
+.\" last edit-date: [Sat Dec 5 18:38:57 1998]
+.\"
+.Dd February 3, 1998
+.Dt i4bq921 4
+.Sh NAME
+.Nm i4bq921
+.Nd isdn4bsd pseudo device driver handling the Q.921 protocol
+.Sh FreeBSD SYNOPSIS
+.Cd pseudo-device \&"i4bq921\&"
+.Sh NetBSD SYNOPSIS
+none
+.Sh DESCRIPTION
+.Nm
+is the ISDN D channel layer 2 handler.
+.Sh STANDARDS
+ITU Recommendation Q.920 and Q.921
+.Sh SEE ALSO
+.Xr i4bq931 4
+.Sh AUTHOR
+The
+.Nm
+driver and this manpage were written by Hellmuth Michaelis. He can be
+contacted at hm@kts.org.
diff --git a/usr.sbin/i4b/man/i4bq931.4 b/usr.sbin/i4b/man/i4bq931.4
new file mode 100644
index 0000000..7c8d155
--- /dev/null
+++ b/usr.sbin/i4b/man/i4bq931.4
@@ -0,0 +1,49 @@
+.\"
+.\" Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id: i4bq931.4,v 1.5 1998/12/05 18:06:10 hm Exp $
+.\"
+.\" last edit-date: [Sat Dec 5 18:39:08 1998]
+.\"
+.Dd February 3, 1998
+.Dt i4bq931 4
+.Sh NAME
+.Nm i4bq931
+.Nd isdn4bsd pseudo device driver handling the Q.931 protocol
+.Sh FreeBSD SYNOPSIS
+.Cd pseudo-device \&"i4bq931\&"
+.Sh NetBSD SYNOPSIS
+none
+.Sh DESCRIPTION
+.Nm
+is the ISDN D channel layer 2 handler.
+.Sh STANDARDS
+ITU Recommendation Q.930 and Q.931
+.Sh SEE ALSO
+.Xr i4bq921 4
+.Sh AUTHOR
+The
+.Nm
+driver and this manpage were written by Hellmuth Michaelis. He can be
+contacted at hm@kts.org.
diff --git a/usr.sbin/i4b/man/i4brbch.4 b/usr.sbin/i4b/man/i4brbch.4
new file mode 100644
index 0000000..b7ee3df
--- /dev/null
+++ b/usr.sbin/i4b/man/i4brbch.4
@@ -0,0 +1,50 @@
+.\"
+.\" Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id: i4brbch.4,v 1.5 1998/12/05 18:06:11 hm Exp $
+.\"
+.\" last edit-date: [Sat Dec 5 18:39:19 1998]
+.\"
+.Dd February 3, 1998
+.Dt i4brbch 4
+.Sh NAME
+.Nm i4brbch
+.Nd isdn4bsd ISDN Raw B-CHannel access driver
+.Sh FreeBSD SYNOPSIS
+.Cd pseudo-device \&"i4brbch\&" Op count
+.Sh NetBSD SYNOPSIS
+none
+.Sh DESCRIPTION
+The
+.Nm
+driver provides an interface to the raw untranslated B-channel. It is
+part of the isdn4bsd package.
+.Sh SEE ALSO
+.Xr isdnd 8
+.Xr isdnd.rc 5
+.Sh AUTHOR
+The
+.Nm
+device driver and this manpage were written by Hellmuth Michaelis. He can be
+contacted at hm@kts.org.
diff --git a/usr.sbin/i4b/man/i4btel.4 b/usr.sbin/i4b/man/i4btel.4
new file mode 100644
index 0000000..e5f6252
--- /dev/null
+++ b/usr.sbin/i4b/man/i4btel.4
@@ -0,0 +1,52 @@
+.\"
+.\" Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id: i4btel.4,v 1.5 1998/12/05 18:06:12 hm Exp $
+.\"
+.\" last edit-date: [Sat Dec 5 18:39:31 1998]
+.\"
+.Dd February 3, 1998
+.Dt i4btel 4
+.Sh NAME
+.Nm i4btel
+.Nd isdn4bsd ISDN B-channel telephony interface driver
+.Sh FreeBSD SYNOPSIS
+.Cd pseudo-device \&"i4btel\&" Op count
+.Sh NetBSD SYNOPSIS
+none
+.Sh DESCRIPTION
+The
+.Nm
+driver provides an interface to the B-channel for telephony applications
+and is currently used by the
+.Xr isdnd 8
+for answering machine support. The driver is part of the isdn4bsd package.
+.Sh SEE ALSO
+.Xr isdnd 8
+.Xr isdnd.rc 5
+.Sh AUTHOR
+The
+.Nm
+device driver and this manpage were written by Hellmuth Michaelis. He can be
+contacted at hm@kts.org.
diff --git a/usr.sbin/i4b/man/i4btrc.4 b/usr.sbin/i4b/man/i4btrc.4
new file mode 100644
index 0000000..60b88ed
--- /dev/null
+++ b/usr.sbin/i4b/man/i4btrc.4
@@ -0,0 +1,52 @@
+.\"
+.\" Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id: i4btrc.4,v 1.5 1998/12/05 18:06:13 hm Exp $
+.\"
+.\" last edit-date: [Sat Dec 5 18:39:42 1998]
+.\"
+.Dd February 3, 1998
+.Dt i4btrc 4
+.Sh NAME
+.Nm i4btrc
+.Nd isdn4bsd ISDN interface driver for D and B channel tracing
+.Sh FreeBSD SYNOPSIS
+.Cd pseudo-device \&"i4btrc\&" Op count
+.Sh NetBSD SYNOPSIS
+none
+.Sh DESCRIPTION
+The
+.Nm
+driver is used to add a header to the data got from the D and/or B channel
+and queues it to be read and further processed by the
+.Xr isdntrace 8
+utility.
+.Sh SEE ALSO
+.Xr isdnd 8
+.Xr isdntrace 8
+.Sh AUTHOR
+The
+.Nm
+device driver and this manpage were written by Hellmuth Michaelis. He can be
+contacted at hm@kts.org.
diff --git a/usr.sbin/i4b/man/isic.4 b/usr.sbin/i4b/man/isic.4
new file mode 100644
index 0000000..0ba54d6
--- /dev/null
+++ b/usr.sbin/i4b/man/isic.4
@@ -0,0 +1,380 @@
+.\"
+.\" Copyright (c) 1997, 1998 Hellmuth Michaelis. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $Id: isic.4,v 1.14 1998/12/22 19:12:13 hm Exp $
+.\"
+.\" last edit-date: [Tue Dec 22 20:08:06 1998]
+.\"
+.Dd December 22, 1998
+.Dt isic 4
+.Sh NAME
+.Nm isic
+.Nd isdn4bsd Siemens ISDN Chipset device driver
+.Sh FreeBSD SYNOPSIS
+.Pp
+For a Teles S0/8 or Niccy 1008 card:
+.Cd options \&"TEL_S0_8\&"
+.Cd "device isic0 at isa? iomem 0xd0000 net irq 5 flags 1 vector isicintr"
+.Pp
+For a Teles S0/16 or Creatix ISDN-S0 or Niccy 1016 card:
+.Cd options \&"TEL_S0_16\&"
+.Cd "device isic0 at isa? port 0xd80 iomem 0xd0000 net irq 5 flags 2 vector isicintr"
+.Pp
+For a Teles S0/16.3 card:
+.Cd options \&"TEL_S0_16_3\&"
+.Cd "device isic0 at isa? port 0xd80 net irq 5 flags 3 vector isicintr"
+.Pp
+For an AVM A1 or AVM Fritz!Card classic:
+.Cd options \&"AVM_A1\&"
+.Cd "device isic0 at isa? port 0x340 net irq 5 flags 4 vector isicintr"
+.Pp
+For an AVM Fritz!Card PCMCIA:
+.Cd options \&"AVM_A1_PCMCIA\&"
+.Cd "device isic0 at isa? port 0x340 net irq 5 flags 10 vector isicintr"
+.Pp
+For a Teles S0/16.3 PnP card (PnP):
+.Cd options \&"TEL_S0_16_3_P\&"
+.Cd "device isic0 at isa? port ? net irq ? vector isicintr"
+.Pp
+For a Creatix ISDN-S0 P&P card (PnP):
+.Cd options \&"CRTX_S0_P\&"
+.Cd "device isic0 at isa? port ? net irq ? vector isicintr"
+.Pp
+For an USRobotics Sportster ISDN TA internal or Stollmann Tina-pp card:
+.Cd options \&"USR_STI\&"
+.Cd "device isic0 at isa? port 0x268 net irq 5 flags 7 vector isicintr"
+.Pp
+For an ITK micro ix1 card:
+.Cd options \&"ITKIX1\&"
+.Cd "device isic0 at isa? port 0x398 net irq 10 flags 18 vector isicintr"
+.Pp
+For a Dr. Neuhaus Niccy Go@ (PnP):
+.Cd options \&"DRN_NGO\&"
+.Cd "device isic0 at isa? port ? net irq ? vector isicintr"
+.Pp
+For a Sedlbauer Win Speed card (PnP):
+.Cd options \&"SEDLBAUER\&"
+.Cd "device isic0 at isa? port ? net irq ? vector isicintr"
+.Pp
+For a Dynalink IS64PH (PnP):
+.Cd options \&"DYNALINK\&"
+.Cd "device isic0 at isa? port ? net irq ? vector isicintr"
+.Pp
+For an ELSA QuickStep 1000pro ISA (PnP):
+.Cd options \&"ELSA_QS1ISA\&"
+.Cd "device isic0 at isa? port ? net irq ? vector isicintr"
+.Pp
+For an ELSA QuickStep 1000pro PCI:
+.Cd options \&"ELSA_QS1PCI\&"
+.Cd "device isic0"
+.Pp
+.Ar FreeBSD PnP configuration:
+.Pp
+To be able to use PnP cards under FreeBSD, you have to add
+.Pp
+.Cd controller pnp0
+.Pp
+to you kernel config file. More, it is recommended to add
+.Pp
+.Cd options \&"USERCONFIG\&"
+.Cd options \&"USERCONFIG_BOOT\&"
+.Pp
+to your kernel config file to be able to adjust your PnP configuration
+in case of trouble.
+.Pp
+See also:
+.Xr pnp 4
+and
+.Xr boot 8
+.Pp
+.Sh NetBSD SYNOPSIS
+On the ISA bus:
+.Pp
+For a Teles S0/8 or Niccy 1008 card:
+.Cd options \&"TEL_S0_8\&"
+.Cd "isic0 at isa? iomem 0xd0000 irq 5"
+.Pp
+For a Teles S0/16 or Creatix ISDN-S0 or Niccy 1016 card:
+.Cd options \&"TEL_S0_16\&"
+.Cd "isic0 at isa? port 0xd80 iomem 0xd0000 irq 5"
+.Pp
+For a Teles S0/16.3 card:
+.Cd options \&"TEL_S0_16_3\&"
+.Cd "isic0 at isa? port 0xd80 irq 5"
+.Pp
+For an AVM A1 or AVM Fritz card:
+.Cd options \&"AVM_A1\&"
+.Cd "isic0 at isa? port 0x340 irq 5"
+.Pp
+For an USRobotics Sportster ISDN TA internal or Stollmann Tina-pp card:
+.Cd options \&"USR_STI\&"
+.Cd "isic0 at isa? port 0x268 irq 5"
+.Pp
+For an ITK ix1 micro card:
+.Cd options \&"ITKIX1\&"
+.Cd "isic0 at isa? port 0x398 irq 10"
+.Pp
+On the ISAPNP bus:
+.Pp
+For a Teles S0/16.3 PnP card
+.Cd options \&"TEL_S0_16_3_P\&"
+.Cd "isic* at isapnp?"
+.Pp
+For a Creatix ISDN-S0 P&P card
+.Cd options \&"CRTX_S0_P\&"
+.Cd "isic* at isapnp?"
+.Pp
+For a Dr. Neuhaus Niccy GO@
+.Cd options \&"DRN_NGO\&"
+.Cd "isic* at isapnp?"
+.Pp
+For an ELSA QuickStep 1000pro (ISA version):
+.Cd options \&"ELSA_QS1ISA\&"
+.Cd "isic* at isapnp?"
+.Pp
+For a Sedlbauer WinSpeed:
+.Cd options \&"SEDLBAUER\&"
+.Cd "isic* at isapnp?"
+.Pp
+For a Dynalink IS64PH:
+.Cd options \&"DYNALINK\&"
+.Cd "isic* at isapnp?"
+.Pp
+Cards on the PCI bus:
+.Pp
+For an ELSA QuickStep 1000pro (PCI version)
+.Cd options \&"ELSA_QS1PCI\&"
+.Cd "isic* at pci?"
+.Pp
+Cards on the PCMCIA or PCCARD bus:
+.Pp
+For an AVM Fritz!Card PCMCIA
+.Cd options \&"AVM_PCMCIA\&"
+.Cd "isic* at pcmcia? function ?"
+.Pp
+For an ELSA MicroLink ISDN/MC
+.Cd options \&"ELSA_ISDNMC\&"
+.Cd "isic* at pcmcia? function ?"
+.Pp
+For an ELSA MicroLink MC/all
+.Cd options \&"ELSA_MCALL\&"
+.Cd "isic* at pcmcia? function ?"
+.Pp
+.Sh DESCRIPTION
+The
+.Nm
+driver provides D-channel layer 1 supports as specified in ITU Recommendation
+I.430 and layer 1 support for the B-channel.
+.Pp
+The driver supports several 8 and 16bit passive ISDN cards from various
+manufacturers which are all based upon the popular Siemens ISDN chipset
+consisting of the ISDN Subscriber Access Controller ISAC (such as the
+PEB2085 or PSB 2186) and the High-Level Serial Communications Controller
+Extended HSCX (such as the SAB82525 or PSB21525). The newer IPAC chip
+(which integrates an ISAC and a HSCX in one chip, with the added benefit
+of larger FIFO buffers) is also supported.
+.Pp
+.Sh SUPPORTED CARDS
+.Pp
+.Bl -tag -width Ds -compact -offset
+.It Ar Teles S0/8, Dr. Neuhaus Niccy 1008, Creatix ISDN-S0/8
+.Pp
+The required (optional for NetBSD)
+.Em flag
+value is 1.
+.Pp
+Notice that this cards must not have a
+.Em port
+value in the config line.
+.Pp
+Valid interrupts are 2, 3, 4, 5, 6 and 7.
+.Pp
+The i/o ports are memory mapped and the memory start address may
+be in the range 0xA0000 to 0xDF000 and uses 4kB of memory.
+.Pp
+.It Ar Teles S0/16, Creatix ISDN-S0, Dr. Neuhaus Niccy 1016
+.Pp
+The required (optional under NetBSD)
+.Em flag
+value is 2.
+.Pp
+These boards have a jumper which specifies an i/o base address of either
+0xd80, 0xe80 or 0xf80. The remaining necessary configuration values are then
+programmed at run time by accessing this i/o port.
+.Pp
+Valid interrupts are 2, 3, 4, 5, 10, 11, 12 or 15.
+.Pp
+Valid memory start
+addresses are 0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000,
+0xCE000, 0xD0000, 0xD2000, 0xD4000, 0xD6000, 0xD8000, 0xDA000, 0xDC000 and
+0xDE000.
+.Pp
+Notice: Although the Jumpers are labeled 0xd80, 0xe80 or 0xf80, they
+also require i/o space at addresses 0x180, 0x280 or 0x380.
+.Pp
+.It Ar Teles S0/16.3
+.Pp
+The required (optional under NetBSD)
+.Em flag
+value is 3.
+.Pp
+This card is completely i/o mapped and must not have an
+.Em iomem
+statement in the config line.
+.Pp
+Valid interrupts are 2, 5, 9, 10, 12 or 15.
+.Pp
+Notice: Although the switch positions are labeled 0x180, 0x280 and 0x380,
+the card is to be configured at 0xd80, 0xe80 or 0xf80 respectively!
+.Pp
+.It Ar AVM A1, AVM Fritz!Card
+.Pp
+The required (optional under NetBSD)
+.Em flag
+value is 4.
+.Pp
+These boards have a jumper which specifies an i/o base address of either
+0x200, 0x240, 0x300 or 0x340.
+.Pp
+Valid interrupt configurations are 3, 4, 5, 6, 7, 10, 11, 12 or 15.
+.Pp
+Older Versions of the AVM A1 also require setting of an IRQ jumper, newer
+versions of this and the Fritz!Card only have an i/o base jumper and the
+interrupt is setup at runtime by reprogramming a register.
+.Pp
+This card is completely i/o mapped and must not have an
+.Em iomem
+statement in the config line.
+.Pp
+.It Ar Teles S0/16.3 PnP
+.Pp
+Possible i/o port values are 0x580, 0x500 and 0x680.
+Possible interrupt configurations are 3, 5, 7, 10, 11 and 12.
+.Pp
+The the card is auto-configured by the PnP kernel subsystem.
+.Pp
+.It Ar Creatix ISDN-S0 P&P
+.Pp
+Valid i/o port values are 0x120, 0x180 and 0x100.
+.Pp
+Valid interrupt configurations are 3, 5, 7, 10, 11 and 12.
+.Pp
+The card is auto-configured by the PnP kernel subsystem.
+.Pp
+.It Ar "3Com USRobotics Sportster ISDN TA intern and Stollmann Tina pp"
+.Pp
+The required (optional for NetBSD)
+.Em flag
+value is 7.
+.Pp
+Valid i/o port values are 0x200, 0x208, 0x210, 0x218, 0x220, 0x228, 0x230,
+0x238, 0x240, 0x248, 0x250, 0x258, 0x260, 0x268, 0x270 and 0x278.
+.Pp
+Valid interrupt configurations are 5, 7, 10, 11, 12, 14, 15.
+.Pp
+Notice: this card has a strange address decoding scheme resulting in 64
+windows of some bytes length. Anyway, support for this card is good because
+the manufacturer gave out technical docs for this card!
+.Pp
+.Pp
+.It Ar "Dr. Neuhaus Niccy Go@"
+.Pp
+Valid i/o port values must be in the range 0x200 ... 0x3e0.
+.Pp
+Valid interrupt configurations are 3, 4, 5, 9, 10, 11, 12, 15.
+.Pp
+The card is auto-configured by the PnP kernel subsystem.
+.Pp
+.It Ar "Sedlbauer Win Speed"
+.Pp
+Valid i/o port values must be in the range 0x100 ... 0x3f0. (alignment 0x8,
+len 0x8)
+.Pp
+Valid interrupt configurations are 3, 4, 5, 7, 10, 11, 12, 13, 15.
+.Pp
+The card is auto-configured by the PnP kernel subsystem.
+.Em FreeBSD:
+This card is PnP only, and so it can be configured using USERCONFIG
+('man 4 pnp'). This can be done via
+.Em /kernel.config
+\&. For example:
+.Pp
+.Cd USERCONFIG
+.Cd pnp 1 0 os enable port0 0x270 irq0 10
+.Cd quit
+.Pp
+.Pp
+.It Ar "ELSA QuickStep 1000pro (ISA)"
+.Pp
+I/O port in the range 0x160 ... 0x360 (occupies 8 bytes).
+.Pp
+Valid interrupt configurations are 3, 4, 5, 7, 10, 11, 12, 15.
+.Pp
+The card is auto-configured by the PnP kernel subsystem.
+.Pp
+.Pp
+.It Ar "ELSA QuickStep 1000pro-PCI"
+.Pp
+The card is auto-configured by the PCI kernel subsystem.
+.Pp
+.Pp
+.It Ar "ITK ix1 micro"
+.Pp
+The required (optional under NetBSD)
+.Em flag
+value is 18.
+.Pp
+Valid i/o port values must be in the range (<unknown>).
+.Pp
+Valid interrupt configurations are (<unknown>).
+.Pp
+.Sh CAVEATS
+Note that all of the boards with I/O ports actually use several ranges
+of port addresses; Teles happen to refer to the 0xd80 range in their
+documentation (the board also uses 0x180 etc.), while AVM happen to refer
+to the 0x200 range in their documentation (the board also uses 0x600 etc.)
+The driver matches the manufacturers' description for the purposes of
+configuration, but of course makes use of all the ports in order to
+operate the card.
+.Pp
+.Sh BUGS
+Since there is no hardware documentation available from several manufacturers
+for their boards, it is likely that there are many, many bugs left.
+
+.Sh STANDARDS
+CCITT Recommendation I.430
+
+.Sh SEE ALSO
+.Xr i4bq921 4
+.Xr i4bq931 4
+
+.Sh AUTHOR
+The
+.Nm
+driver and this manpage were written by Hellmuth Michaelis. It is based
+on earlier work of Arne Helme, Andrew Gordon and Gary Jennejohn. The author
+can be contacted at hm@kts.org.
+.Pp
+The complete porting to and maintenance of NetBSD was done by Martin Husemann.
+He can be contacted at martin@rumolt.teuto.de
OpenPOWER on IntegriCloud