summaryrefslogtreecommitdiffstats
path: root/usr.sbin/i4b
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/i4b')
-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
93 files changed, 26454 insertions, 0 deletions
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