freebsd-nq/usr.sbin/i4b/isdntest/main.c
Poul-Henning Kamp 19c749625f Initial entry of ISDN4BSD into the FreeBSD tree.
ISDN4BSD is the work of our brand-new comitter: Hellmuth Michaelis,
who has done a tremendous amount of work to bring us this far.

There are still some outstanding issues and files to bring into
the tree, and for now it will be needed to pick up all the extra
docs from the isdn4bsd release.

It is probably also a very good idea to subscribe to the isdn@freebsd.org
mailing list before you try this out.

These files correspond to release "beta Version 0.70.00 / December
1998" from Hellmuth.
1998-12-27 21:47:14 +00:00

739 lines
17 KiB
C

/*
* 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 */