Silence warnings about ignored trigraphs.
[dragonfly.git] / usr.sbin / i4b / isdntest / main.c
CommitLineData
984263bc
MD
1/*
2 * Copyright (c) 1997, 1999 Hellmuth Michaelis. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 *
25 *---------------------------------------------------------------------------
26 *
27 * main.c - i4b selftest utility
28 * -----------------------------
29 *
30 * $Id: main.c,v 1.16 2000/03/13 16:18:38 hm Exp $
31 *
32 * $FreeBSD: src/usr.sbin/i4b/isdntest/main.c,v 1.7.2.1 2001/08/01 17:45:07 obrien Exp $
564dee32 33 * $DragonFly: src/usr.sbin/i4b/isdntest/main.c,v 1.6 2006/03/18 19:43:18 swildner Exp $
984263bc
MD
34 *
35 * last edit-date: [Mon Mar 13 17:19:26 2000]
36 *
37 *---------------------------------------------------------------------------*/
38
39#include <stdio.h>
40#include <signal.h>
41#include <errno.h>
42#include <string.h>
43#include <stdlib.h>
44#include <unistd.h>
45#include <fcntl.h>
46#include <ctype.h>
47#include <sys/stat.h>
48#include <sys/wait.h>
49#include <sys/ioctl.h>
50#include <sys/types.h>
51#include <sys/time.h>
52
38a690d7
MD
53#include <i4b_machine/i4b_ioctl.h>
54#include <i4b_machine/i4b_cause.h>
984263bc
MD
55
56static void kbdrdhdl ( void );
57static void isdnrdhdl (int isdnfd );
58
59void handle_connect_ind(unsigned char *ptr);
60void handle_disconnect(unsigned char *ptr);
61void handle_connect_active_ind(unsigned char *ptr);
62
63int connect_response(int isdnfd, unsigned int cdid, int response);
64int disconnect_request(int isdnfd, unsigned int cdid);
65unsigned int get_cdid(int isdnfd);
66int connect_request(int isdnfd, unsigned int cdid);
67int do_test(void);
68static void cleanup(void);
69static void usage(void);
70void setup_wrfix(int len, unsigned char *buf);
71int check_rd(int len, unsigned char *wbuf, unsigned char *rdbuf);
72
73static int isdnfd;
74char outgoingnumber[32];
75char incomingnumber[32];
76int debug_level = 0;
77
78#define I4BDEVICE "/dev/i4b"
79#define DATADEV0 "/dev/i4brbch0"
80#define DATAUNIT0 0
81#define DATADEV1 "/dev/i4brbch1"
82#define DATAUNIT1 1
83
84unsigned int out_cdid = CDID_UNUSED;
85unsigned int in_cdid = CDID_UNUSED;
86
87int waitchar = 0;
88int usehdlc = 0;
89int controller = 0;
90int dotest = 0;
91
92/*---------------------------------------------------------------------------*
93 * usage display and exit
94 *---------------------------------------------------------------------------*/
95static void
96usage(void)
97{
98 fprintf(stderr, "\n");
99 fprintf(stderr, "isdntest - i4b selftest, version %d.%d.%d, compiled %s %s\n",VERSION, REL, STEP, __DATE__, __TIME__);
100 fprintf(stderr, "usage: isdntest [-c ctrl] [-d level] [-h] [-i telno] [-o telno] [-t num] [-w]\n");
101 fprintf(stderr, " -c <ctrl> specify controller to use\n");
102 fprintf(stderr, " -d <level> set debug level\n");
103 fprintf(stderr, " -h use HDLC as Bchannel protocol\n");
104 fprintf(stderr, " -i <telno> incoming telephone number\n");
105 fprintf(stderr, " -o <telno> outgoing telephone number\n");
106 fprintf(stderr, " -t <num> send test pattern num times\n");
107 fprintf(stderr, " -w wait for keyboard entry to disconnect\n");
108 fprintf(stderr, "\n");
109 exit(1);
110}
111
112/*---------------------------------------------------------------------------*
113 * program entry
114 *---------------------------------------------------------------------------*/
115int
116main(int argc, char **argv)
117{
118 int i;
119 int c;
120 fd_set set;
121 int ret;
122 char *ptr;
123
124 incomingnumber[0] = '\0';
125 outgoingnumber[0] = '\0';
126
127 while ((c = getopt(argc, argv, "c:d:hi:o:t:w")) != -1)
128 {
129 switch(c)
130 {
131 case 'c':
132 if(isdigit(*optarg))
133 {
134 controller = strtoul(optarg, NULL, 10);
135 }
136 else
137 {
138 fprintf(stderr, "Error: option -c requires a numeric argument!\n");
139 usage();
140 }
141 break;
142
143 case 'd':
144 if(isdigit(*optarg))
145 {
146 debug_level = strtoul(optarg, NULL, 10);
147 }
148 else
149 {
150 fprintf(stderr, "Error: option -d requires a numeric argument!\n");
151 usage();
152 }
153 break;
154
155 case 'o':
156 i = 0;
157 ptr = optarg;
158
159 while(*ptr)
160 {
161 if(isdigit(*ptr))
162 {
163 outgoingnumber[i++] = *ptr++;
164 }
165 else
166 {
167 fprintf(stderr, "Error: option -o requires a numeric argument!\n");
168 usage();
169 }
170 }
171 outgoingnumber[i] = '\0';
172 break;
173
174 case 'i':
175 i = 0;
176 ptr = optarg;
177
178 while(*ptr)
179 {
180 if(isdigit(*ptr))
181 {
182 incomingnumber[i++] = *ptr++;
183 }
184 else
185 {
186 fprintf(stderr, "Error: option -i requires a numeric argument!\n");
187 usage();
188 }
189 }
190 incomingnumber[i] = '\0';
191 break;
192
193 case 'w':
194 waitchar = 1;
195 break;
196
197 case 'h':
198 usehdlc = 1;
199 break;
200
201 case 't':
202 if(isdigit(*optarg))
203 {
204 dotest = strtoul(optarg, NULL, 10);
205 }
206 else
207 {
208 fprintf(stderr, "Error: option -t requires a numeric argument!\n");
209 usage();
210 }
211 break;
212
213 case '?':
214 default:
215 usage();
216 break;
217 }
218 }
219
220 if((strlen(incomingnumber) == 0) || (strlen(outgoingnumber) == 0))
221 usage();
222
223 fprintf(stderr, "isdntest: accepting calls from telephone number [%s] \n", incomingnumber);
224 fprintf(stderr, "isdntest: calling out telephone number [%s] \n", outgoingnumber);
225
226 if((atexit(cleanup)) != 0)
227 {
228 fprintf(stderr, "isdntest: atexit error: %s\n", strerror(errno));
229 exit(1);
230 }
231
232 /* open isdn device */
233
234 if((isdnfd = open(I4BDEVICE, O_RDWR)) < 0)
235 {
236 fprintf(stderr, "\nisdntest: cannot open %s: %s\n", I4BDEVICE, strerror(errno));
237 fprintf(stderr, " isdnd is probably running, to use isdntest,\n");
238 fprintf(stderr, " terminate isdnd and then run isdntest again!\n");
239 exit(1);
240 }
241
242 if((out_cdid = get_cdid(isdnfd)) == 0)
243 {
244 fprintf(stderr, "isdntest: error getting cdid: %s\n", strerror(errno));
245 exit(1);
246 }
247
248 if((connect_request(isdnfd, out_cdid)) == -1)
249 {
250 fprintf(stderr, "isdntest: error, outgoing call failed!\n");
251 exit(1);
252 }
253
254 for(;;)
255 {
256 FD_ZERO(&set);
257
258 FD_SET(0, &set);
259
260 FD_SET(isdnfd, &set);
261
262 ret = select(isdnfd + 1, &set, NULL, NULL, NULL);
263
264 if(ret > 0)
265 {
266 if(FD_ISSET(isdnfd, &set))
267 isdnrdhdl(isdnfd);
268
269 if(FD_ISSET(0, &set))
270 kbdrdhdl();
271 }
272 else
273 {
274 fprintf(stderr, "isdntest: select error: %s\n", strerror(errno));
275 }
276 }
277}
278
279/*---------------------------------------------------------------------------*
280 * data from keyboard available
281 *---------------------------------------------------------------------------*/
282static void
283kbdrdhdl(void)
284{
285 cleanup();
286 exit(2);
287}
288
289/*---------------------------------------------------------------------------*
290 * data from /dev/isdn available, read and process them
291 *---------------------------------------------------------------------------*/
292static void
293isdnrdhdl(int isdnfd)
294{
295 static unsigned char buf[1024];
296 int len;
297
298 if((len = read(isdnfd, buf, 1024 - 1)) > 0)
299 {
300 switch (buf[0])
301 {
302 case MSG_CONNECT_IND:
303 handle_connect_ind(&buf[0]);
304 break;
305
306 case MSG_CONNECT_ACTIVE_IND:
307 handle_connect_active_ind(&buf[0]);
308 break;
309
310 case MSG_DISCONNECT_IND:
311 handle_disconnect(&buf[0]);
312 break;
313
314 default:
315 if(debug_level)
316 fprintf(stderr, "isdntest: unknown message 0x%x = %c\n", buf[0], buf[0]);
317 break;
318 }
319 }
320 else
321 {
322 fprintf(stderr, "isdntest: read error, errno = %d, length = %d", errno, len);
323 }
324}
325
326/*---------------------------------------------------------------------------*
327 * initiate an outgoing connection
328 *---------------------------------------------------------------------------*/
329int
330connect_request(int isdnfd, unsigned int cdid)
331{
332 msg_connect_req_t mcr;
333 int ret;
334
335 bzero(&mcr, sizeof(msg_connect_req_t));
336
337 mcr.controller = controller;
338 mcr.channel = CHAN_ANY; /* any channel */
339 mcr.cdid = cdid; /* cdid from get_cdid() */
340
341 if(usehdlc)
342 mcr.bprot = BPROT_RHDLC;/* b channel protocol */
343 else
344 mcr.bprot = BPROT_NONE; /* b channel protocol */
345
346 mcr.driver = BDRV_RBCH; /* raw b channel driver */
347 mcr.driver_unit = DATAUNIT0; /* raw b channel driver unit */
348
349 strcpy(mcr.dst_telno, outgoingnumber);
350 strcpy(mcr.src_telno, incomingnumber);
351
352 if((ret = ioctl(isdnfd, I4B_CONNECT_REQ, &mcr)) < 0)
353 {
354 fprintf(stderr, "ioctl I4B_CONNECT_REQ failed: %s", strerror(errno));
355 return(-1);
356 }
357 fprintf(stderr, "isdntest: calling out to telephone number [%s] \n", outgoingnumber);
358 return(0);
359}
360
361/*---------------------------------------------------------------------------*
362 * handle setup indicator
363 *---------------------------------------------------------------------------*/
364void
365handle_connect_ind(unsigned char *ptr)
366{
367 msg_connect_ind_t *msi = (msg_connect_ind_t *)ptr;
368
369 fprintf(stderr, "isdntest: incoming SETUP: from %s to %s\n",
370 msi->src_telno,
371 msi->dst_telno);
372
373 fprintf(stderr, " channel %d, controller %d, bprot %d, cdid %d\n",
374 msi->channel,
375 msi->controller,
376 msi->bprot,
377 msi->header.cdid);
378
379 in_cdid = msi->header.cdid;
380
381 if(strcmp(msi->dst_telno, outgoingnumber))
382 {
383 msg_connect_resp_t msr;
384 int ret;
385
386 fprintf(stderr, "isdntest: ignoring incoming SETUP: my number [%s] != outgoing [%s]\n",
387 msi->dst_telno, outgoingnumber);
388
389 msr.cdid = in_cdid;
390 msr.response = SETUP_RESP_DNTCRE;
391
392 if((ret = ioctl(isdnfd, I4B_CONNECT_RESP, &msr)) < 0)
393 {
394 fprintf(stderr, "ioctl I4B_CONNECT_RESP ignore failed: %s", strerror(errno));
395 exit(1);
396 }
397
398 }
399 else
400 {
401 msg_connect_resp_t msr;
402 int ret;
403
404 fprintf(stderr, "isdntest: accepting call, sending CONNECT_RESPONSE .....\n");
405
406 msr.cdid = in_cdid;
407 msr.response = SETUP_RESP_ACCEPT;
408
409 if(usehdlc)
410 msr.bprot = BPROT_RHDLC;
411 else
412 msr.bprot = BPROT_NONE;
413
414 msr.driver = BDRV_RBCH;
415 msr.driver_unit = DATAUNIT1;
416
417 if((ret = ioctl(isdnfd, I4B_CONNECT_RESP, &msr)) < 0)
418 {
419 fprintf(stderr, "ioctl I4B_CONNECT_RESP accept failed: %s", strerror(errno));
420 exit(1);
421 }
422 }
423}
424
425#define SLEEPTIME 5
426
427/*---------------------------------------------------------------------------*
428 * handle connection active
429 *---------------------------------------------------------------------------*/
430void
431handle_connect_active_ind(unsigned char *ptr)
432{
433 msg_connect_active_ind_t *msi = (msg_connect_active_ind_t *)ptr;
434 int i;
435
436 fprintf(stderr, "isdntest: connection active, cdid %d\n", msi->header.cdid);
437
438 if(out_cdid == msi->header.cdid)
439 {
440 if(waitchar)
441 {
442 fprintf(stderr, "isdntest: press any key to disconnect ...%c%c%c\n", 0x07, 0x07, 0x07);
443 getchar();
444 }
445 else
446 {
447 if(dotest)
448 {
449 do_test();
450 }
451 else
452 {
453 fprintf(stderr, "isdntest: %d secs delay until disconnect:", SLEEPTIME);
454
455 for(i=0; i < SLEEPTIME;i++)
456 {
457 fprintf(stderr, " .");
458 sleep(1);
459 }
460 fprintf(stderr, "\n");
461 }
462 cleanup();
463 exit(0);
464 }
465 }
466}
467
468/*---------------------------------------------------------------------------*
469 * handle disconnect indication
470 *---------------------------------------------------------------------------*/
471void
472handle_disconnect(unsigned char *ptr)
473{
474 msg_disconnect_ind_t *mdi = (msg_disconnect_ind_t *)ptr;
475
476 if(mdi->header.cdid == out_cdid)
477 {
478 fprintf(stderr, "isdntest: incoming disconnect indication, cdid %d (out_cdid), cause %d\n",
479 mdi->header.cdid, mdi->cause);
480
481 out_cdid = CDID_UNUSED;
482 }
483 else if(mdi->header.cdid == in_cdid)
484 {
485 fprintf(stderr, "isdntest: incoming disconnect indication, cdid %d (in_cdid), cause %d\n",
486 mdi->header.cdid, mdi->cause);
487 in_cdid = CDID_UNUSED;
488 }
489 else
490 {
564dee32 491 fprintf(stderr, "isdntest: incoming disconnect indication, cdid %d (??\?), cause %d\n",
984263bc
MD
492 mdi->header.cdid, mdi->cause);
493 }
494}
495
496/*---------------------------------------------------------------------------*
497 * hang up
498 *---------------------------------------------------------------------------*/
499int
500disconnect_request(int isdnfd, unsigned int cdid)
501{
502 msg_discon_req_t mdr;
503 int ret;
504
505 mdr.cdid = cdid;
506 mdr.cause = (CAUSET_I4B << 8) | CAUSE_I4B_NORMAL;
507
508 if((ret = ioctl(isdnfd, I4B_DISCONNECT_REQ, &mdr)) < 0)
509 {
510 fprintf(stderr, "ioctl I4B_DISCONNECT_REQ failed: %s", strerror(errno));
511 return(-1);
512 }
513 fprintf(stderr, "isdntest: sending disconnect request\n");
514 return(0);
515}
516
517/*---------------------------------------------------------------------------*
518 * get cdid from kernel
519 *---------------------------------------------------------------------------*/
520unsigned int
521get_cdid(int isdnfd)
522{
523 msg_cdid_req_t mcr;
524 int ret;
525
526 mcr.cdid = 0;
527
528 if((ret = ioctl(isdnfd, I4B_CDID_REQ, &mcr)) < 0)
529 {
530 fprintf(stderr, "ioctl I4B_CDID_REQ failed: %s", strerror(errno));
531 return(0);
532 }
533 fprintf(stderr, "isdntest: got cdid %d from kernel\n", mcr.cdid);
534 return(mcr.cdid);
535}
536
537/*---------------------------------------------------------------------------*
538 * make shure all cdid's are inactive before leaving
539 *---------------------------------------------------------------------------*/
fe361e7d
SW
540void
541cleanup(void)
984263bc
MD
542{
543 int len;
544 char buf[1024];
545
546 if(out_cdid != CDID_UNUSED)
547 {
548 fprintf(stderr, "isdntest: cleanup, send disconnect req for out_cdid %d, in_cdid %d\n", out_cdid, in_cdid);
549 disconnect_request(isdnfd, out_cdid);
550 }
551
552 while((out_cdid != CDID_UNUSED) || (in_cdid != CDID_UNUSED))
553 {
554 if(debug_level)
555 fprintf(stderr, "isdntest: cleanup, out_cdid %d, in_cdid %d\n", out_cdid, in_cdid);
556
557 if((len = read(isdnfd, buf, 1024 - 1)) > 0)
558 {
559 switch (buf[0])
560 {
561 case MSG_CONNECT_IND:
562 handle_connect_ind(&buf[0]);
563 break;
564
565 case MSG_CONNECT_ACTIVE_IND:
566 handle_connect_active_ind(&buf[0]);
567 break;
568
569 case MSG_DISCONNECT_IND:
570 handle_disconnect(&buf[0]);
571 break;
572
573 default:
574 if(debug_level)
575 fprintf(stderr, "isdntest: unknown message 0x%x = %c\n", buf[0], buf[0]);
576 break;
577 }
578 }
579 else
580 {
581 fprintf(stderr, "isdntest: read error, errno = %d, length = %d", errno, len);
582 }
583 }
584 if(debug_level)
585 fprintf(stderr, "isdntest: exit cleanup, out_cdid %d, in_cdid %d\n", out_cdid, in_cdid);
586}
587
588/*---------------------------------------------------------------------------*
589 * test the b-channels
590 *---------------------------------------------------------------------------*/
fe361e7d
SW
591int
592do_test(void)
984263bc
MD
593{
594
595#define FPH 0x3c
596#define FPL 0x66
597
598 int fd0, fd1;
599 unsigned char wrbuf[2048];
600 unsigned char rdbuf[2048];
601 int sz;
602 fd_set set;
603 struct timeval timeout;
604 int ret;
605 int frame;
606 int errcnt;
607 int frm_len;
608 int bytecnt = 0;
609 time_t start_time;
610 time_t cur_time;
611 time_t run_time;
612
613 if((fd0 = open(DATADEV0, O_RDWR)) == -1)
614 {
615 fprintf(stderr, "open of %s failed: %s", DATADEV0, strerror(errno));
616 return(-1);
617 }
618
619 if((fd1 = open(DATADEV1, O_RDWR)) == -1)
620 {
621 fprintf(stderr, "open of %s failed: %s", DATADEV1, strerror(errno));
622 return(-1);
623 }
624
625 printf("\n");
626 frame = 0;
627 errcnt = 0;
628
629 frm_len = 2;
630
631 start_time = time(NULL);
632
633 printf(" frame size errors totalbytes bps elapsedtime\n");
634
635 for(;dotest > 0; dotest--)
636 {
637 setup_wrfix(frm_len, &wrbuf[0]);
638
639 frame++;
640
641 bytecnt += frm_len;
642
643 printf("%6d %4d", frame, frm_len);
644 fflush(stdout);
645
646 if((sz = write(fd0, wrbuf, frm_len)) != frm_len)
647 {
648 fprintf(stderr, "write (%d of %d bytes) to %s failed: %s\n", sz, frm_len, DATADEV0, strerror(errno));
649 }
650
651 timeout.tv_sec = 2;
652 timeout.tv_usec = 0;
653
654 FD_ZERO(&set);
655
656 FD_SET(0, &set);
657 FD_SET(fd1, &set);
658
659 ret = select(fd1+1, &set, NULL, NULL, &timeout);
660
661 if(ret > 0)
662 {
663 if(FD_ISSET(fd1, &set))
664 {
665 if((sz = read(fd1, rdbuf, 2048)) != frm_len)
666 {
667 fprintf(stderr, "read (%d bytes) from %s failed: %s\n", sz, DATADEV1, strerror(errno));
668 }
669
670 cur_time = time(NULL);
671 run_time = difftime(cur_time, start_time);
672
673 if(run_time == 0)
674 run_time = 1;
675
676 printf(" %6d %10d %4d %2.2d:%2.2d:%2.2d \r",
677 errcnt, bytecnt,
678 (int)((int)bytecnt/(int)run_time),
679 (int)run_time/3600, (int)run_time/60, (int)run_time%60);
680 fflush(stdout);
681
682 errcnt += check_rd(frm_len, &wrbuf[0], &rdbuf[0]);
683
684#ifdef NOTDEF
685 for(i=0; i<sz; i++)
686 {
687 printf("0x%02x ", (unsigned char)rdbuf[i]);
688 }
689 printf("\n");
690#endif
691 }
692
693 if(FD_ISSET(0, &set))
694 {
695 return(0);
696 printf("\n\n");
697 }
698 }
699 else
700 {
701 fprintf(stderr, "isdntest, do_test: select error: %s\n", strerror(errno));
702 }
703
704 frm_len = frm_len*2;
705 if(frm_len > 2048)
706 frm_len = 2;
707
708 }
709 printf("\n\n");
710 return(0);
711}
712
713void
714setup_wrfix(int len, unsigned char *buf)
715{
27a1f132 716 int i;
984263bc
MD
717
718 for(i=0; i<len;)
719 {
720 *buf = FPH;
721 buf++;
722 *buf = FPL;
723 buf++;
724 i+=2;
725 }
726}
727
728int
729check_rd(int len, unsigned char *wbuf, unsigned char *rbuf)
730{
27a1f132 731 int i;
984263bc
MD
732 int ret = 0;
733
734 for(i=0; i<len; i++)
735 {
736 if(*wbuf != *rbuf)
737 {
738 fprintf(stderr, "\nERROR, byte %d, written 0x%02x, read 0x%02x\n", i, *wbuf, *rbuf);
739 ret++;
740 }
741 wbuf++;
742 rbuf++;
743 }
744 return(ret);
745}
746
747
748/* EOF */