diff options
Diffstat (limited to 'usr.sbin/i4b/isdntest/main.c')
-rw-r--r-- | usr.sbin/i4b/isdntest/main.c | 738 |
1 files changed, 738 insertions, 0 deletions
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 */ |