diff options
Diffstat (limited to 'usr.sbin/i4b')
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 |