sconfig.c revision 155064
16059Samurai/*
26059Samurai * Channel configuration utility for Cronyx serial adapters.
36059Samurai *
46059Samurai * Copyright (C) 1997-2002 Cronyx Engineering.
56059Samurai * Author: Serge Vakulenko, <vak@cronyx.ru>
66059Samurai *
76059Samurai * Copyright (C) 1999-2005 Cronyx Engineering.
86059Samurai * Author: Roman Kurakin, <rik@cronyx.ru>
96059Samurai *
106059Samurai * This software is distributed with NO WARRANTIES, not even the implied
116059Samurai * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
126059Samurai *
136059Samurai * Authors grant any other persons or organisations permission to use
146059Samurai * or modify this software as long as this message is kept with the software,
156059Samurai * all derivative works or modified versions.
166059Samurai *
176059Samurai * Cronyx Id: sconfig.c,v 1.4.2.2 2005/11/09 13:01:35 rik Exp $
186059Samurai * $FreeBSD: head/sbin/sconfig/sconfig.c 155064 2006-01-30 21:08:30Z rik $
196059Samurai */
2036465Sbrian#include <stdio.h>
218857Srgrimes#include <stdlib.h>
226059Samurai#include <string.h>
236059Samurai#include <unistd.h>
2436285Sbrian#include <fcntl.h>
2536452Sbrian#include <errno.h>
2630715Sbrian#include <ctype.h>
2730715Sbrian#include <sys/ioctl.h>
2830715Sbrian#include <sys/types.h>
2930715Sbrian#include <sys/stat.h>
3036285Sbrian#include <sys/socket.h>
3136285Sbrian#include <net/if.h>
3230715Sbrian#include <machine/cserial.h>
3330715Sbrian
346059Samurai#define MAXCHAN 128
3511336Samurai
3630715Sbrianint vflag, eflag, sflag, mflag, cflag, fflag, iflag, aflag, xflag;
3730715Sbrianint tflag, uflag;
3830715Sbrianchar mask[64];
396059Samuraiint adapter_type;		/* 0-sigma, 1-tau, 2-taupci, 3-tau32 */
406059Samuraichar chan_name[16];
4118786Sjkh
4230715Sbrianextern char *optarg;
4330715Sbrianextern int optind;
4430715Sbrian
4530715Sbrianstatic void
4631061Sbrianusage (void)
4730715Sbrian{
4830715Sbrian	printf(
4936285Sbrian"Serial Adapter Configuration Utility\n"
506059Samurai"Copyright (C) 1998-2005 Cronyx Engineering.\n"
5131514Sbrian"See also man sconfig (8)\n"
5213389Sphk"Usage:\n"
5336285Sbrian"\tsconfig [-aimsxeftuc] [device [parameters ...]]\n"
5436285Sbrian"\n"
5536285Sbrian"Options:\n"
566059Samurai"\t<no options>\t\t -- print channel options\n"
5736285Sbrian"\t-a\t\t\t -- print all settings of the channel\n"
5836285Sbrian"\t-i\t\t\t -- print network interface status\n"
5936285Sbrian"\t-m\t\t\t -- print modem signal status\n"
6036285Sbrian"\t-s\t\t\t -- print channel statistics\n"
6136285Sbrian"\t-x\t\t\t -- print extended channel statistics\n"
6226142Sbrian"\t-e\t\t\t -- print short E1/G703 statistics\n"
636735Samurai"\t-f\t\t\t -- print full E1/G703 statistics\n"
6413389Sphk"\t-t\t\t\t -- print short E3/T3/STS-1 statistics\n"
6513389Sphk"\t-u\t\t\t -- print full E3/T3/STS-1 statistics\n"
6623840Sbrian"\t-c\t\t\t -- clear statistics\n"
6730715Sbrian"\nParameters:\n"
6831195Sbrian"\t<number>\t\t -- baud rate, internal clock\n"
6936285Sbrian"\textclock\t\t -- external clock (default)\n"
7036285Sbrian"\nProtocol options:\n"
7136285Sbrian"\tasync\t\t\t -- asynchronous protocol\n"
7236285Sbrian#ifdef __linux__
7336285Sbrian"\tsync\t\t\t -- synchronous protocol\n"
746059Samurai#endif
756735Samurai"\tcisco\t\t\t -- Cisco/HDLC protocol\n"
766735Samurai"\tfr\t\t\t -- Frame Relay protocol\n"
776735Samurai#ifdef __linux__
786735Samurai"\t    dlci<number>\t -- Add new DLCI\n"
796735Samurai#endif
806735Samurai"\tppp\t\t\t -- PPP protocol\n"
8136431Sbrian#ifdef __linux__
8230715Sbrian"\trbrg\t\t\t -- Remote bridge\n"
8331343Sbrian"\traw\t\t\t -- raw HDLC protocol\n"
8430715Sbrian"\tpacket\t\t\t -- packetized HDLC protocol\n"
8536285Sbrian"\tidle\t\t\t -- no protocol\n"
8636285Sbrian#else
876059Samurai"\t    keepalive={on,of}\t -- Enable/disable keepalive\n"
8810528Samurai#endif
8936285Sbrian"\nInterface options:\n"
906059Samurai"\tport={rs232,v35,rs449}\t -- port type (for old models of Sigma)\n"
9136285Sbrian"\tcfg={A,B,C}\t\t -- adapter configuration\n"
9236285Sbrian"\tloop={on,off}\t\t -- internal loopback\n"
9336285Sbrian"\trloop={on,off}\t\t -- remote loopback\n"
946059Samurai"\tdpll={on,off}\t\t -- DPLL mode\n"
956059Samurai"\tnrzi={on,off}\t\t -- NRZI encoding\n"
966059Samurai"\tinvclk={on,off}\t\t -- invert receive and transmit clock\n"
9736285Sbrian"\tinvrclk={on,off}\t -- invert receive clock\n"
986059Samurai"\tinvtclk={on,off}\t -- invert transmit clock\n"
9936285Sbrian"\thigain={on,off}\t\t -- E1 high non linear input sensitivity \n\t\t\t\t    (long line)\n"
10036285Sbrian"\tmonitor={on,off}\t -- E1 high linear input sensitivity \n\t\t\t\t    (interception mode)\n"
10136285Sbrian"\tphony={on,off}\t\t -- E1 telepnony mode\n"
10236285Sbrian"\tunfram={on,off}\t\t -- E1 unframed mode\n"
10336285Sbrian"\tscrambler={on,off}\t -- G.703 scrambling mode\n"
1046059Samurai"\tuse16={on,off}\t\t -- E1 timeslot 16 usage\n"
1056059Samurai"\tcrc4={on,off}\t\t -- E1 CRC4 mode\n"
1066059Samurai#ifdef __linux__
1076059Samurai"\tami={on,off}\t\t -- E1 AMI or HDB3 line code\n"
10828679Sbrian"\tmtu={size}\t\t -- set MTU in bytes\n"
1096059Samurai#endif
11026858Sbrian"\tsyn={int,rcv,rcvX}\t -- G.703 transmit clock\n"
11136285Sbrian"\tts=...\t\t\t -- E1 timeslots\n"
11236285Sbrian"\tpass=...\t\t -- E1 subchannel timeslots\n"
11336285Sbrian"\tdir=<num>\t\t -- connect channel to link<num>\n"
11436285Sbrian/*"\trqken={size}\t\t -- set receive queue length in packets\n"*/
1156059Samurai/*"\tcablen={on,off}\t\t -- T3/STS-1 high transmitter output for long cable\n"*/
1166059Samurai"\tdebug={0,1,2}\t\t -- enable/disable debug messages\n"
1176059Samurai	);
11828679Sbrian	exit (0);
1196059Samurai}
12036285Sbrian
12128679Sbrianstatic unsigned long
1226059Samuraiscan_timeslots (char *s)
1236059Samurai{
12436285Sbrian	char *e;
12536285Sbrian	long v;
12610528Samurai	int i;
12736285Sbrian	unsigned long ts, lastv;
12810528Samurai
12936285Sbrian	ts = lastv = 0;
13036285Sbrian	for (;;) {
13110528Samurai		v = strtol (s, &e, 10);
13210528Samurai		if (e == s)
13310528Samurai			break;
13436285Sbrian		if (*e == '-') {
13510528Samurai			lastv = v;
13636285Sbrian			s = e+1;
13736285Sbrian			continue;
13810528Samurai		}
13910528Samurai		if (*e == ',')
14026940Sbrian			++e;
14136285Sbrian
14226940Sbrian		if (lastv)
14336285Sbrian			for (i=lastv; i<v; ++i)
14436285Sbrian				ts |= 1L << i;
14536285Sbrian		ts |= 1L << v;
14626940Sbrian
14726940Sbrian		lastv = 0;
14831081Sbrian		s = e;
14931081Sbrian	}
15031081Sbrian	return ts;
15136285Sbrian}
15236285Sbrian
15331081Sbrianstatic int
15431081Sbrianppp_ok (void)
15531343Sbrian{
15625908Sbrian#ifdef __linux__
15725908Sbrian	int s, p;
15825908Sbrian	struct ifreq ifr;
15931343Sbrian	char pttyname[32];
16031343Sbrian	char *p1, *p2;
16131343Sbrian	int i, j;
16231343Sbrian	int ppp_disc = N_PPP;
16310528Samurai
16431962Sbrian	/*
16525908Sbrian	 * Open a socket for doing the ioctl operations.
16625908Sbrian	 */
16725908Sbrian	s = socket (AF_INET, SOCK_DGRAM, 0);
16825908Sbrian	if (s < 0) {
16925908Sbrian		fprintf (stderr, "Error opening socket.\n");
17030715Sbrian		return 0;
17131343Sbrian	}
1726059Samurai	strncpy (ifr.ifr_name, "ppp0", sizeof (ifr.ifr_name));
17320120Snate	if (ioctl (s, SIOCGIFFLAGS, (caddr_t) &ifr) >= 0) {
17431343Sbrian		/* Ok. */
17531343Sbrian		close (s);
17631343Sbrian		return 1;
17731343Sbrian	}
17831343Sbrian	close (s);
1796059Samurai
1806059Samurai	/* open pseudo-tty and try to set PPP discipline */
1816059Samurai	sprintf (pttyname, "/dev/ptyXX");
18231197Sbrian	p1 = &pttyname[8];
18336285Sbrian	p2 = &pttyname[9];
1846059Samurai	for (i=0; i<16; i++) {
18536465Sbrian		struct stat stb;
1866059Samurai
1876059Samurai		*p1 = "pqrstuvwxyzabcde"[i];
18836285Sbrian		*p2 = '0';
18936465Sbrian		if (stat (pttyname, &stb) < 0)
1906059Samurai			continue;
1916059Samurai		for (j=0; j<16; j++) {
19236465Sbrian			*p2 = "0123456789abcdef"[j];
19336465Sbrian			p = open (pttyname, 2);
19436465Sbrian			if (p > 0) {
19536465Sbrian				if (ioctl (p, TIOCSETD, &ppp_disc) < 0) {
19631343Sbrian					fprintf (stderr, "No PPP discipline in kernel.\n");
19736465Sbrian					close (p);
19836285Sbrian					return 0;
19936465Sbrian				}
20036465Sbrian				close (p);
20136465Sbrian				return 1;
20236465Sbrian			}
20336465Sbrian		}
20436465Sbrian	}
20536465Sbrian	fprintf (stderr, "Cannot get pseudo-tty.\n");
20636465Sbrian	return 0;
20736465Sbrian#else
20836465Sbrian	return 1;
20936465Sbrian#endif
21036465Sbrian}
21136465Sbrian
21236465Sbrianstatic char *
21336465Sbrianformat_timeslots (unsigned long s)
21436465Sbrian{
21536465Sbrian	static char buf [100];
21636465Sbrian	char *p = buf;
21736465Sbrian	int i;
2186059Samurai
21928679Sbrian	for (i=1; i<32; ++i)
22028679Sbrian		if ((s >> i) & 1) {
2216059Samurai			int prev = (i > 1)  & (s >> (i-1));
22236465Sbrian			int next = (i < 31) & (s >> (i+1));
2236059Samurai
22436285Sbrian			if (prev) {
2256059Samurai				if (next)
2266059Samurai					continue;
2276059Samurai				*p++ = '-';
2286059Samurai			} else if (p > buf)
22936285Sbrian				*p++ = ',';
2306059Samurai
2316059Samurai			if (i >= 10)
23231197Sbrian				*p++ = '0' + i / 10;
23336285Sbrian			*p++ = '0' + i % 10;
23436285Sbrian		}
23536285Sbrian	*p = 0;
23636285Sbrian	return buf;
23736285Sbrian}
23836285Sbrian
23931197Sbrianstatic void
2406059Samuraiprint_modems (int fd, int need_header)
2416059Samurai{
24226940Sbrian	int status;
24328679Sbrian
2446059Samurai	if (ioctl (fd, TIOCMGET, &status) < 0) {
24531197Sbrian		perror ("getting modem status");
24636285Sbrian		return;
24736285Sbrian	}
24836285Sbrian	if (need_header)
24926516Sbrian		printf ("Channel\tLE\tDTR\tDSR\tRTS\tCTS\tCD\n");
25031823Sbrian	printf ("%s\t%s\t%s\t%s\t%s\t%s\t%s\n", chan_name,
25131823Sbrian		status & TIOCM_LE  ? "On" : "-",
25231823Sbrian		status & TIOCM_DTR ? "On" : "-",
25331823Sbrian		status & TIOCM_DSR ? "On" : "-",
25431823Sbrian		status & TIOCM_RTS ? "On" : "-",
25531823Sbrian		status & TIOCM_CTS ? "On" : "-",
25631823Sbrian		status & TIOCM_CD  ? "On" : "-");
25731823Sbrian}
25831823Sbrian
25931823Sbrianstatic void
26030715Sbrianprint_ifconfig (int fd)
26136285Sbrian{
26226516Sbrian	char buf [64];
26328679Sbrian#ifdef __linux__
26428679Sbrian	char protocol [8];
26536285Sbrian
26631121Sbrian	if (ioctl (fd, SERIAL_GETPROTO, &protocol) >= 0 &&
26736285Sbrian	    strcmp (protocol, "fr") == 0)
26836285Sbrian		sprintf (buf, "ifconfig %sd16 2>/dev/null", chan_name);
26936285Sbrian	else
27036285Sbrian#endif
27136285Sbrian	sprintf (buf, "ifconfig %s 2>/dev/null", chan_name);
27236285Sbrian	system (buf);
27336285Sbrian}
27436285Sbrian
27536465Sbrianstatic char *
27636285Sbrianformat_long (unsigned long val)
27736285Sbrian{
27836285Sbrian	static char s[32];
27936285Sbrian	int l;
28036285Sbrian	l = sprintf (s, "%lu", val);
28136285Sbrian	if (l>7 && !sflag) {
28236285Sbrian		s[3] = s[2];
28336285Sbrian		s[2] = s[1];
28436285Sbrian		s[1] = '.';
28536285Sbrian		s[4] = 'e';
28636285Sbrian		sprintf (s + 5, "%02d", l-1);
28736285Sbrian	}
28836285Sbrian	return s;
28936465Sbrian}
29036285Sbrian
29136285Sbrianstatic void
29231121Sbrianprint_stats (int fd, int need_header)
29331158Sbrian{
29431158Sbrian	struct serial_statistics st;
29531158Sbrian	unsigned long sarr [9];
29631158Sbrian	int i;
29731158Sbrian
29831158Sbrian	if (ioctl (fd, SERIAL_GETSTAT, &st) < 0) {
29936285Sbrian		perror ("getting statistics");
30031158Sbrian		return;
30131158Sbrian	}
30231158Sbrian	if (need_header) {
30331158Sbrian		if (sflag) {
30431158Sbrian			printf ("        ------------Receive-----------      "
30531158Sbrian				"------------Transmit----------\n");
30631158Sbrian			printf ("Channel Interrupts  Packets     Errors      "
30731158Sbrian				"Interrupts  Packets     Errors\n");
30836285Sbrian		}
30931121Sbrian		else    {
31036285Sbrian			printf ("        --------Receive---------------  "
31131157Sbrian				"--------Transmit--------------  Modem\n");
31231197Sbrian			printf ("Channel Intrs   Bytes   Packets Errors  "
31336285Sbrian				"Intrs   Bytes   Packets Errors  Intrs\n");
31431157Sbrian		}
31536285Sbrian	}
31631121Sbrian
31729083Sbrian	sarr [0] = st.rintr;
31831121Sbrian	sarr [1] = st.ibytes;
31936314Sbrian	sarr [2] = st.ipkts;
32036285Sbrian	sarr [3] = st.ierrs;
32126940Sbrian	sarr [4] = st.tintr;
3226059Samurai	sarr [5] = st.obytes;
32336314Sbrian	sarr [6] = st.opkts;
32436314Sbrian	sarr [7] = st.oerrs;
32536314Sbrian	sarr [8] = st.mintr;
32636314Sbrian	printf ("%s", chan_name);
32736285Sbrian	if (sflag) {
32831121Sbrian		printf ("\t%-12lu%-12lu%-12lu%-12lu%-12lu%-12lu", sarr[0],
32936285Sbrian			sarr[2], sarr[3], sarr[4], sarr[6], sarr[7]);
33036285Sbrian	} else {
33136285Sbrian		for (i = 0; i < 9; i++)
33236285Sbrian			printf ("\t%s", format_long (sarr [i]));
33336285Sbrian		printf ("\n");
33436285Sbrian	}
33536285Sbrian}
33636285Sbrian
33724753Sachestatic void
3386059Samuraiclear_stats (int fd)
33936465Sbrian{
34036285Sbrian	if (ioctl (fd, SERIAL_CLRSTAT, 0) < 0) {
34136285Sbrian		perror ("clearing statistics");
34236285Sbrian		exit (-1);
34336285Sbrian	}
34431197Sbrian}
34531197Sbrian
34636285Sbrianstatic char *
34736285Sbrianformat_e1_status (unsigned long status)
34836285Sbrian{
34936285Sbrian	static char buf [80];
35031197Sbrian
35136285Sbrian	if (status == 0)
35236285Sbrian		return "n/a";
35336285Sbrian	if (status & E1_NOALARM)
35436285Sbrian		return "Ok";
3556059Samurai	buf[0] = 0;
35636285Sbrian	if (status & E1_LOS)     strcat (buf, ",LOS");
35736465Sbrian	if (status & E1_AIS)     strcat (buf, ",AIS");
35836285Sbrian	if (status & E1_LOF)     strcat (buf, ",LOF");
35936285Sbrian	if (status & E1_LOMF)    strcat (buf, ",LOMF");
36036285Sbrian	if (status & E1_CRC4E)   strcat (buf, ",CRC4E");
36136285Sbrian	if (status & E1_FARLOF)  strcat (buf, ",FARLOF");
36236285Sbrian	if (status & E1_AIS16)   strcat (buf, ",AIS16");
3636059Samurai	if (status & E1_FARLOMF) strcat (buf, ",FARLOMF");
36426940Sbrian/*	if (status & E1_TSTREQ)  strcat (buf, ",TSTREQ");*/
36536465Sbrian/*	if (status & E1_TSTERR)  strcat (buf, ",TSTERR");*/
36636285Sbrian	if (buf[0] == ',')
36736285Sbrian		return buf+1;
36836285Sbrian	return "Unknown";
36936285Sbrian}
37036465Sbrian
37136285Sbrianstatic void
37236285Sbrianprint_frac (int leftalign, unsigned long numerator, unsigned long divider)
37320813Sjkh{
3746059Samurai	int n;
37528679Sbrian
37620813Sjkh	if (numerator < 1 || divider < 1) {
37736285Sbrian		printf (leftalign ? "/-   " : "    -");
37836285Sbrian		return;
37920813Sjkh	}
38036285Sbrian	n = (int) (0.5 + 1000.0 * numerator / divider);
38120813Sjkh	if (n < 1000) {
38220813Sjkh		printf (leftalign ? "/.%-3d" : " .%03d", n);
38311336Samurai		return;
38436465Sbrian	}
38536285Sbrian	putchar (leftalign ? '/' : ' ');
38620813Sjkh
38736285Sbrian	if      (n >= 1000000) n = (n+500) / 1000 * 1000;
38836285Sbrian	else if (n >= 100000)  n = (n+50)  / 100 * 100;
38936285Sbrian	else if (n >= 10000)   n = (n+5)   / 10 * 10;
39036285Sbrian
39136285Sbrian	switch (n) {
39236285Sbrian	case 1000:    printf (".999"); return;
39336285Sbrian	case 10000:   n = 9990;   break;
39436285Sbrian	case 100000:  n = 99900;  break;
39536285Sbrian	case 1000000: n = 999000; break;
39636285Sbrian	}
39725908Sbrian	if (n < 10000)        printf ("%d.%d", n/1000, n/10%100);
39836285Sbrian	else if (n < 100000)  printf ("%d.%d", n/1000, n/100%10);
39936285Sbrian	else if (n < 1000000) printf ("%d.", n/1000);
40025908Sbrian	else                  printf ("%d", n/1000);
40136285Sbrian}
40236285Sbrian
40328679Sbrianstatic void
40428679Sbrianprint_e1_stats (int fd, int need_header)
40536285Sbrian{
40620813Sjkh	struct e1_statistics st;
40728679Sbrian	int i, maxi;
40836465Sbrian
40936285Sbrian	if (need_header)
41036285Sbrian		printf ("Chan\t Unav/Degr  Bpv/Fsyn  CRC/RCRC  Err/Lerr  Sev/Bur   Oof/Slp  Status\n");
41136285Sbrian
41220813Sjkh	if (ioctl (fd, SERIAL_GETESTAT, &st) < 0)
41336285Sbrian		return;
41436285Sbrian	printf ("%s\t", chan_name);
41536285Sbrian
41636285Sbrian	/* Unavailable seconds, degraded minutes */
41736285Sbrian	print_frac (0, st.currnt.uas, st.cursec);
41826686Sbrian	print_frac (1, 60 * st.currnt.dm, st.cursec);
41936285Sbrian
42036285Sbrian	/* Bipolar violations, frame sync errors */
42136285Sbrian	print_frac (0, st.currnt.bpv, st.cursec);
42236285Sbrian	print_frac (1, st.currnt.fse, st.cursec);
42336285Sbrian
42426686Sbrian	/* CRC errors, remote CRC errors (E-bit) */
4256059Samurai	print_frac (0, st.currnt.crce, st.cursec);
42636285Sbrian	print_frac (1, st.currnt.rcrce, st.cursec);
42732129Sbrian
42836285Sbrian	/* Errored seconds, line errored seconds */
42936285Sbrian	print_frac (0, st.currnt.es, st.cursec);
43036285Sbrian	print_frac (1, st.currnt.les, st.cursec);
4316059Samurai
43229696Sbrian	/* Severely errored seconds, bursty errored seconds */
43336285Sbrian	print_frac (0, st.currnt.ses, st.cursec);
43436431Sbrian	print_frac (1, st.currnt.bes, st.cursec);
43536285Sbrian
4366059Samurai	/* Out of frame seconds, controlled slip seconds */
43736285Sbrian	print_frac (0, st.currnt.oofs, st.cursec);
4386059Samurai	print_frac (1, st.currnt.css, st.cursec);
4396059Samurai
4406059Samurai	printf (" %s\n", format_e1_status (st.status));
44136431Sbrian
4426059Samurai	if (fflag) {
4436059Samurai		/* Print total statistics. */
44436285Sbrian		printf ("\t");
4456059Samurai		print_frac (0, st.total.uas, st.totsec);
44636285Sbrian		print_frac (1, 60 * st.total.dm, st.totsec);
44723598Sache
44828679Sbrian		print_frac (0, st.total.bpv, st.totsec);
44928679Sbrian		print_frac (1, st.total.fse, st.totsec);
45028679Sbrian
4517001Samurai		print_frac (0, st.total.crce, st.totsec);
45236314Sbrian		print_frac (1, st.total.rcrce, st.totsec);
45336285Sbrian
45425067Sbrian		print_frac (0, st.total.es, st.totsec);
45536314Sbrian		print_frac (1, st.total.les, st.totsec);
45636314Sbrian
45736314Sbrian		print_frac (0, st.total.ses, st.totsec);
45836285Sbrian		print_frac (1, st.total.bes, st.totsec);
45936285Sbrian
46036285Sbrian		print_frac (0, st.total.oofs, st.totsec);
46126551Sbrian		print_frac (1, st.total.css, st.totsec);
46236285Sbrian
46326696Sbrian		printf (" -- Total\n");
46436345Sbrian
46536285Sbrian		/* Print 24-hour history. */
46636285Sbrian		maxi = (st.totsec - st.cursec) / 900;
46736285Sbrian		if (maxi > 48)
46836285Sbrian			maxi = 48;
46936285Sbrian		for (i=0; i<maxi; ++i) {
47036285Sbrian			printf ("       ");
47136285Sbrian			print_frac (0, st.interval[i].uas, 15*60);
47236285Sbrian			print_frac (1, 60 * st.interval[i].dm, 15*60);
47336285Sbrian
47436285Sbrian			print_frac (0, st.interval[i].bpv, 15*60);
47536285Sbrian			print_frac (1, st.interval[i].fse, 15*60);
47636285Sbrian
47736285Sbrian			print_frac (0, st.interval[i].crce, 15*60);
47836285Sbrian			print_frac (1, st.interval[i].rcrce, 15*60);
47936285Sbrian
48036285Sbrian			print_frac (0, st.interval[i].es, 15*60);
48136285Sbrian			print_frac (1, st.interval[i].les, 15*60);
48236285Sbrian
48336285Sbrian			print_frac (0, st.interval[i].ses, 15*60);
48436285Sbrian			print_frac (1, st.interval[i].bes, 15*60);
48536285Sbrian
48636285Sbrian			print_frac (0, st.interval[i].oofs, 15*60);
48736285Sbrian			print_frac (1, st.interval[i].css, 15*60);
48836285Sbrian
48936285Sbrian			if (i < 3)
49036285Sbrian				printf (" -- %dm\n", (i+1)*15);
49136285Sbrian			else
49236285Sbrian				printf (" -- %dh %dm\n", (i+1)/4, (i+1)%4*15);
49336285Sbrian		}
49436285Sbrian	}
49536285Sbrian}
49636285Sbrian
49736285Sbrianstatic char *
49828679Sbrianformat_e3_status (unsigned long status)
49928679Sbrian{
5008857Srgrimes	static char buf [80];
5016059Samurai
50236345Sbrian	buf[0] = 0;
50336345Sbrian	if (status & E3_LOS)     strcat (buf, ",LOS");
50436345Sbrian	if (status & E3_TXE)     strcat (buf, ",XMIT");
50536345Sbrian	if (buf[0] == ',')
50636345Sbrian		return buf+1;
50736285Sbrian	return "Ok";
50836285Sbrian}
50936285Sbrian
51036285Sbrianstatic char *
5116059Samuraiformat_e3_cv (unsigned long cv, unsigned long baud, unsigned long time)
51228679Sbrian{
51336285Sbrian	static char buf[80];
51436285Sbrian
51528536Sbrian	if (!cv || !baud || !time)
51636285Sbrian		sprintf (buf, "         -         ");
51736285Sbrian	else
51832039Sbrian		sprintf (buf, "%10lu (%.1e)", cv, (double)cv/baud/time);
51936285Sbrian	return buf;
52036285Sbrian}
52136285Sbrian
52236285Sbrianstatic void
52336285Sbrianprint_e3_stats (int fd, int need_header)
52436345Sbrian{
52536285Sbrian	struct e3_statistics st;
52636285Sbrian	int i, maxi;
52736285Sbrian	long baud;
5286059Samurai
529	if (need_header)
530		printf ("Chan\t--Code Violations---\t\t\t\t\t ----Status----\n");
531
532	if (ioctl (fd, SERIAL_GETE3STAT, &st) < 0 ||
533	    ioctl (fd, SERIAL_GETBAUD, &baud) < 0)
534		return;
535
536	if (!st.cursec)
537		st.cursec = 1;
538
539	printf ("%s\t%s\t\t\t\t\t", chan_name,
540		format_e3_cv (st.ccv, baud, st.cursec));
541
542	printf (" %s\n", format_e3_status (st.status));
543
544
545	if (uflag) {
546		/* Print total statistics. */
547		printf ("\t%s\t\t\t\t\t",
548			format_e3_cv (st.tcv, baud, st.totsec));
549		printf (" -- Total\n");
550
551		/* Print 24-hour history. */
552		maxi = (st.totsec - st.cursec) / 900;
553		if (maxi > 48)
554			maxi = 48;
555		for (i=0; i<maxi; ++i) {
556			printf ("\t%s\t\t\t\t\t",
557				format_e3_cv (st.icv[i], baud, 15*60));
558			if (i < 3)
559				printf (" -- %2dm\n", (i+1)*15);
560			else
561				printf (" -- %2dh %2dm\n", (i+1)/4, (i+1)%4*15);
562		}
563	}
564}
565
566static void
567print_chan (int fd)
568{
569	char protocol [8];
570	char cfg;
571	int loop, dpll, nrzi, invclk, clk, higain, phony, use16, crc4;
572	int level, keepalive, debug, port, invrclk, invtclk, unfram, monitor;
573	int cable, dir, scrambler, ami, mtu;
574	int cablen, rloop, rqlen;
575	long baud, timeslots, subchan;
576	int protocol_valid, baud_valid, loop_valid, use16_valid, crc4_valid;
577	int dpll_valid, nrzi_valid, invclk_valid, clk_valid, phony_valid;
578	int timeslots_valid, subchan_valid, higain_valid, level_valid;
579	int keepalive_valid, debug_valid, cfg_valid, port_valid;
580	int invrclk_valid, invtclk_valid, unfram_valid, monitor_valid;
581	int cable_valid, dir_valid, scrambler_valid, ami_valid, mtu_valid;
582	int cablen_valid, rloop_valid, rqlen_valid;
583
584	protocol_valid  = ioctl (fd, SERIAL_GETPROTO, &protocol) >= 0;
585	cfg_valid       = ioctl (fd, SERIAL_GETCFG, &cfg) >= 0;
586	baud_valid      = ioctl (fd, SERIAL_GETBAUD, &baud) >= 0;
587	loop_valid      = ioctl (fd, SERIAL_GETLOOP, &loop) >= 0;
588	dpll_valid      = ioctl (fd, SERIAL_GETDPLL, &dpll) >= 0;
589	nrzi_valid      = ioctl (fd, SERIAL_GETNRZI, &nrzi) >= 0;
590	invclk_valid    = ioctl (fd, SERIAL_GETINVCLK, &invclk) >= 0;
591	invrclk_valid	= ioctl (fd, SERIAL_GETINVRCLK, &invrclk) >= 0;
592	invtclk_valid	= ioctl (fd, SERIAL_GETINVTCLK, &invtclk) >= 0;
593	clk_valid       = ioctl (fd, SERIAL_GETCLK, &clk) >= 0;
594	timeslots_valid = ioctl (fd, SERIAL_GETTIMESLOTS, &timeslots) >= 0;
595	subchan_valid   = ioctl (fd, SERIAL_GETSUBCHAN, &subchan) >= 0;
596	higain_valid    = ioctl (fd, SERIAL_GETHIGAIN, &higain) >= 0;
597	phony_valid     = ioctl (fd, SERIAL_GETPHONY, &phony) >= 0;
598	unfram_valid    = ioctl (fd, SERIAL_GETUNFRAM, &unfram) >= 0;
599	monitor_valid   = ioctl (fd, SERIAL_GETMONITOR, &monitor) >= 0;
600	use16_valid     = ioctl (fd, SERIAL_GETUSE16, &use16) >= 0;
601	crc4_valid      = ioctl (fd, SERIAL_GETCRC4, &crc4) >= 0;
602	ami_valid	= ioctl (fd, SERIAL_GETLCODE, &ami) >= 0;
603	level_valid     = ioctl (fd, SERIAL_GETLEVEL, &level) >= 0;
604	keepalive_valid = ioctl (fd, SERIAL_GETKEEPALIVE, &keepalive) >= 0;
605	debug_valid     = ioctl (fd, SERIAL_GETDEBUG, &debug) >= 0;
606	port_valid	= ioctl (fd, SERIAL_GETPORT, &port) >= 0;
607	cable_valid	= ioctl (fd, SERIAL_GETCABLE, &cable) >= 0;
608	dir_valid	= ioctl (fd, SERIAL_GETDIR, &dir) >= 0;
609	scrambler_valid	= ioctl (fd, SERIAL_GETSCRAMBLER, &scrambler) >= 0;
610	cablen_valid	= ioctl (fd, SERIAL_GETCABLEN, &cablen) >= 0;
611	rloop_valid	= ioctl (fd, SERIAL_GETRLOOP, &rloop) >= 0;
612	mtu_valid	= ioctl (fd, SERIAL_GETMTU, &mtu) >= 0;
613	rqlen_valid	= ioctl (fd, SERIAL_GETRQLEN, &rqlen) >= 0;
614
615	printf ("%s", chan_name);
616	if (port_valid)
617		switch (port) {
618		case 0:	printf (" (rs232)"); break;
619		case 1:	printf (" (v35)"); break;
620		case 2:	printf (" (rs530)"); break;
621		}
622	else if (cable_valid)
623		switch (cable) {
624		case 0:	printf (" (rs232)"); break;
625		case 1:	printf (" (v35)"); break;
626		case 2:	printf (" (rs530)"); break;
627		case 3:	printf (" (x21)"); break;
628		case 4:	printf (" (rs485)"); break;
629		case 9:	printf (" (no cable)"); break;
630		}
631	if (debug_valid && debug)
632		printf (" debug=%d", debug);
633	if (protocol_valid && *protocol)
634		printf (" %.8s", protocol);
635	else
636		printf (" idle");
637	if (cablen_valid)
638		printf (" cablen=%s", cablen ? "on" : "off");
639	if (keepalive_valid)
640		printf (" keepalive=%s", keepalive ? "on" : "off");
641
642	if (cfg_valid)
643		switch (cfg) {
644		case 'a' :	printf (" cfg=A");	break;
645		case 'b' :	printf (" cfg=B");	break;
646		case 'c' :	printf (" cfg=C");	break;
647		case 'd' :	printf (" cfg=D");	break;
648		default  :	printf (" cfg=unknown");
649		}
650	if (dir_valid)
651		printf (" dir=%d", dir);
652
653	if (baud_valid) {
654		if (baud)
655			printf (" %ld", baud);
656		else
657			printf (" extclock");
658	}
659	if (mtu_valid)
660		printf (" mtu=%d", mtu);
661
662	if (aflag && rqlen_valid)
663		printf (" rqlen=%d", rqlen);
664
665	if (clk_valid)
666		switch (clk) {
667		case E1CLK_INTERNAL:	  printf (" syn=int");     break;
668		case E1CLK_RECEIVE:	  printf (" syn=rcv");     break;
669		case E1CLK_RECEIVE_CHAN0: printf (" syn=rcv0");    break;
670		case E1CLK_RECEIVE_CHAN1: printf (" syn=rcv1");    break;
671		case E1CLK_RECEIVE_CHAN2: printf (" syn=rcv2");    break;
672		case E1CLK_RECEIVE_CHAN3: printf (" syn=rcv3");    break;
673		default:                  printf (" syn=%d", clk); break;
674		}
675
676	if (dpll_valid)
677		printf (" dpll=%s", dpll ? "on" : "off");
678	if (nrzi_valid)
679		printf (" nrzi=%s", nrzi ? "on" : "off");
680	if (invclk_valid)
681		printf (" invclk=%s", invclk ? "on" : "off");
682	if (invrclk_valid)
683		printf (" invrclk=%s", invrclk ? "on" : "off");
684	if (invtclk_valid)
685		printf (" invtclk=%s", invtclk ? "on" : "off");
686	if (unfram_valid)
687		printf (" unfram=%s", unfram ? "on" : "off");
688	if (use16_valid)
689		printf (" use16=%s", use16 ? "on" : "off");
690	if (aflag) {
691		if (crc4_valid)
692			printf (" crc4=%s", crc4 ? "on" : "off");
693		if (higain_valid)
694			printf (" higain=%s", higain ? "on" : "off");
695		if (monitor_valid)
696			printf (" monitor=%s", monitor ? "on" : "off");
697		if (phony_valid)
698			printf (" phony=%s", phony ? "on" : "off");
699		if (scrambler_valid)
700			printf (" scrambler=%s", scrambler ? "on" : "off");
701		if (loop_valid)
702			printf (" loop=%s", loop ? "on" : "off");
703		if (rloop_valid)
704			printf (" rloop=%s", rloop ? "on" : "off");
705		if (ami_valid)
706			printf (" ami=%s", ami ? "on" : "off");
707	}
708	if (timeslots_valid)
709		printf (" ts=%s", format_timeslots (timeslots));
710	if (subchan_valid)
711		printf (" pass=%s", format_timeslots (subchan));
712	if (level_valid)
713		printf (" (level=-%.1fdB)", level / 10.0);
714	printf ("\n");
715}
716
717static void
718setup_chan (int fd, int argc, char **argv)
719{
720	int i, mode, loop, nrzi, dpll, invclk, phony, use16, crc4, unfram, ami;
721	int higain, clk, keepalive, debug, port, dlci, invrclk, invtclk;
722	int monitor, dir, scrambler, rloop, cablen;
723	long baud, timeslots, mtu, rqlen;
724
725	for (i=0; i<argc; ++i) {
726		if (argv[i][0] >= '0' && argv[i][0] <= '9') {
727			baud = strtol (argv[i], 0, 10);
728			ioctl (fd, SERIAL_SETBAUD, &baud);
729		} else if (strcasecmp ("extclock", argv[i]) == 0) {
730			baud = 0;
731			ioctl (fd, SERIAL_SETBAUD, &baud);
732		} else if (strncasecmp ("cfg=", argv[i], 4) == 0) {
733			if (strncasecmp ("a", argv[i]+4, 1) == 0)
734				ioctl (fd, SERIAL_SETCFG, "a");
735			else if (strncasecmp ("b", argv[i]+4, 1) == 0)
736				ioctl (fd, SERIAL_SETCFG, "b");
737			else if (strncasecmp ("c", argv[i]+4, 1) == 0)
738				ioctl (fd, SERIAL_SETCFG, "c");
739			else if (strncasecmp ("d", argv[i]+4, 1) == 0)
740				ioctl (fd, SERIAL_SETCFG, "d");
741			else {
742				fprintf (stderr, "invalid cfg\n");
743				exit (-1);
744			}
745		} else if (strcasecmp ("idle", argv[i]) == 0)
746			ioctl (fd, SERIAL_SETPROTO, "\0\0\0\0\0\0\0");
747		else if (strcasecmp ("async", argv[i]) == 0) {
748			mode = SERIAL_ASYNC;
749			if (ioctl (fd, SERIAL_SETMODE, &mode) >= 0)
750				ioctl (fd, SERIAL_SETPROTO, "async\0\0");
751		} else if (strcasecmp ("sync", argv[i]) == 0) {
752			mode = SERIAL_HDLC;
753			if (ioctl (fd, SERIAL_SETMODE, &mode) >= 0)
754				ioctl (fd, SERIAL_SETPROTO, "sync\0\0\0");
755		} else if (strcasecmp ("cisco", argv[i]) == 0) {
756			mode = SERIAL_HDLC;
757			ioctl (fd, SERIAL_SETMODE, &mode);
758			ioctl (fd, SERIAL_SETPROTO, "cisco\0\0");
759		} else if (strcasecmp ("rbrg", argv[i]) == 0) {
760			mode = SERIAL_HDLC;
761			ioctl (fd, SERIAL_SETMODE, &mode);
762			ioctl (fd, SERIAL_SETPROTO, "rbrg\0\0\0");
763		} else if (strcasecmp ("raw", argv[i]) == 0) {
764			mode = SERIAL_HDLC;
765			ioctl (fd, SERIAL_SETMODE, &mode);
766			ioctl (fd, SERIAL_SETPROTO, "raw\0\0\0\0");
767		} else if (strcasecmp ("packet", argv[i]) == 0) {
768			mode = SERIAL_HDLC;
769			ioctl (fd, SERIAL_SETMODE, &mode);
770			ioctl (fd, SERIAL_SETPROTO, "packet\0");
771		} else if (strcasecmp ("ppp", argv[i]) == 0) {
772			/* check that ppp line discipline is present */
773			if (ppp_ok ()) {
774				mode = SERIAL_HDLC;
775				ioctl (fd, SERIAL_SETMODE, &mode);
776				ioctl (fd, SERIAL_SETPROTO, "ppp\0\0\0\0");
777			}
778		} else if (strncasecmp ("keepalive=", argv[i], 10) == 0) {
779			keepalive = (strcasecmp ("on", argv[i] + 10) == 0);
780			ioctl (fd, SERIAL_SETKEEPALIVE, &keepalive);
781		} else if (strcasecmp ("fr", argv[i]) == 0) {
782			mode = SERIAL_HDLC;
783			ioctl (fd, SERIAL_SETMODE, &mode);
784			ioctl (fd, SERIAL_SETPROTO, "fr\0\0\0\0\0");
785		} else if (strcasecmp ("zaptel", argv[i]) == 0) {
786			mode = SERIAL_HDLC;
787			ioctl (fd, SERIAL_SETMODE, &mode);
788			ioctl (fd, SERIAL_SETPROTO, "zaptel\0");
789		} else if (strncasecmp ("debug=", argv[i], 6) == 0) {
790			debug = strtol (argv[i]+6, 0, 10);
791			ioctl (fd, SERIAL_SETDEBUG, &debug);
792		} else if (strncasecmp ("loop=", argv[i], 5) == 0) {
793			loop = (strcasecmp ("on", argv[i] + 5) == 0);
794			ioctl (fd, SERIAL_SETLOOP, &loop);
795		} else if (strncasecmp ("rloop=", argv[i], 6) == 0) {
796			rloop = (strcasecmp ("on", argv[i] + 6) == 0);
797			ioctl (fd, SERIAL_SETRLOOP, &rloop);
798		} else if (strncasecmp ("dpll=", argv[i], 5) == 0) {
799			dpll = (strcasecmp ("on", argv[i] + 5) == 0);
800			ioctl (fd, SERIAL_SETDPLL, &dpll);
801		} else if (strncasecmp ("nrzi=", argv[i], 5) == 0) {
802			nrzi = (strcasecmp ("on", argv[i] + 5) == 0);
803			ioctl (fd, SERIAL_SETNRZI, &nrzi);
804		} else if (strncasecmp ("invclk=", argv[i], 7) == 0) {
805			invclk = (strcasecmp ("on", argv[i] + 7) == 0);
806			ioctl (fd, SERIAL_SETINVCLK, &invclk);
807		} else if (strncasecmp ("invrclk=", argv[i], 8) == 0) {
808			invrclk = (strcasecmp ("on", argv[i] + 8) == 0);
809			ioctl (fd, SERIAL_SETINVRCLK, &invrclk);
810		} else if (strncasecmp ("invtclk=", argv[i], 8) == 0) {
811			invtclk = (strcasecmp ("on", argv[i] + 8) == 0);
812			ioctl (fd, SERIAL_SETINVTCLK, &invtclk);
813		} else if (strncasecmp ("higain=", argv[i], 7) == 0) {
814			higain = (strcasecmp ("on", argv[i] + 7) == 0);
815			ioctl (fd, SERIAL_SETHIGAIN, &higain);
816		} else if (strncasecmp ("phony=", argv[i], 6) == 0) {
817			phony = (strcasecmp ("on", argv[i] + 6) == 0);
818			ioctl (fd, SERIAL_SETPHONY, &phony);
819		} else if (strncasecmp ("unfram=", argv[i], 7) == 0) {
820			unfram = (strcasecmp ("on", argv[i] + 7) == 0);
821			ioctl (fd, SERIAL_SETUNFRAM, &unfram);
822		} else if (strncasecmp ("scrambler=", argv[i], 10) == 0) {
823			scrambler = (strcasecmp ("on", argv[i] + 10) == 0);
824			ioctl (fd, SERIAL_SETSCRAMBLER, &scrambler);
825		} else if (strncasecmp ("monitor=", argv[i], 8) == 0) {
826			monitor = (strcasecmp ("on", argv[i] + 8) == 0);
827			ioctl (fd, SERIAL_SETMONITOR, &monitor);
828		} else if (strncasecmp ("use16=", argv[i], 6) == 0) {
829			use16 = (strcasecmp ("on", argv[i] + 6) == 0);
830			ioctl (fd, SERIAL_SETUSE16, &use16);
831		} else if (strncasecmp ("crc4=", argv[i], 5) == 0) {
832			crc4 = (strcasecmp ("on", argv[i] + 5) == 0);
833			ioctl (fd, SERIAL_SETCRC4, &crc4);
834		} else if (strncasecmp ("ami=", argv[i], 4) == 0) {
835			ami = (strcasecmp ("on", argv[i] + 4) == 0);
836			ioctl (fd, SERIAL_SETLCODE, &ami);
837		} else if (strncasecmp ("mtu=", argv[i], 4) == 0) {
838			mtu = strtol (argv[i] + 4, 0, 10);
839			ioctl (fd, SERIAL_SETMTU, &mtu);
840		} else if (strncasecmp ("rqlen=", argv[i], 6) == 0) {
841			rqlen = strtol (argv[i] + 6, 0, 10);
842			ioctl (fd, SERIAL_SETRQLEN, &rqlen);
843		} else if (strcasecmp ("syn=int", argv[i]) == 0) {
844			clk = E1CLK_INTERNAL;
845			ioctl (fd, SERIAL_SETCLK, &clk);
846		} else if (strcasecmp ("syn=rcv", argv[i]) == 0) {
847			clk = E1CLK_RECEIVE;
848			ioctl (fd, SERIAL_SETCLK, &clk);
849		} else if (strcasecmp ("syn=rcv0", argv[i]) == 0) {
850			clk = E1CLK_RECEIVE_CHAN0;
851			ioctl (fd, SERIAL_SETCLK, &clk);
852		} else if (strcasecmp ("syn=rcv1", argv[i]) == 0) {
853			clk = E1CLK_RECEIVE_CHAN1;
854			ioctl (fd, SERIAL_SETCLK, &clk);
855		} else if (strcasecmp ("syn=rcv2", argv[i]) == 0) {
856			clk = E1CLK_RECEIVE_CHAN2;
857			ioctl (fd, SERIAL_SETCLK, &clk);
858		} else if (strcasecmp ("syn=rcv3", argv[i]) == 0) {
859			clk = E1CLK_RECEIVE_CHAN3;
860			ioctl (fd, SERIAL_SETCLK, &clk);
861		} else if (strncasecmp ("ts=", argv[i], 3) == 0) {
862			timeslots = scan_timeslots (argv[i] + 3);
863			ioctl (fd, SERIAL_SETTIMESLOTS, &timeslots);
864		} else if (strncasecmp ("pass=", argv[i], 5) == 0) {
865			timeslots = scan_timeslots (argv[i] + 5);
866			ioctl (fd, SERIAL_SETSUBCHAN, &timeslots);
867		} else if (strncasecmp ("dlci", argv[i], 4) == 0) {
868			dlci = strtol (argv[i]+4, 0, 10);
869			ioctl (fd, SERIAL_ADDDLCI, &dlci);
870		} else if (strncasecmp ("dir=", argv[i], 4) == 0) {
871			dir = strtol (argv[i]+4, 0, 10);
872			ioctl (fd, SERIAL_SETDIR, &dir);
873		} else if (strncasecmp ("port=", argv[i], 5) == 0) {
874			if (strncasecmp ("rs232", argv[i]+5, 5) == 0) {
875				port = 0;
876				ioctl (fd, SERIAL_SETPORT, &port);
877			} else if (strncasecmp ("v35", argv[i]+5, 3) == 0) {
878				port = 1;
879				ioctl (fd, SERIAL_SETPORT, &port);
880			} else if (strncasecmp ("rs449", argv[i]+5, 5) == 0) {
881				port = 2;
882				ioctl (fd, SERIAL_SETPORT, &port);
883			} else
884				fprintf (stderr, "invalid port type\n");
885				exit (-1);
886#if 1
887		} else if (strcasecmp ("reset", argv[i]) == 0) {
888			ioctl (fd, SERIAL_RESET, 0);
889		} else if (strcasecmp ("hwreset", argv[i]) == 0) {
890			ioctl (fd, SERIAL_HARDRESET, 0);
891#endif
892		} else if (strncasecmp ("cablen=", argv[i], 7) == 0) {
893			loop = (strcasecmp ("on", argv[i] + 7) == 0);
894			ioctl (fd, SERIAL_SETCABLEN, &cablen);
895		}
896	}
897}
898
899static void
900get_mask (void)
901{
902#ifdef __linux__
903	int fd;
904
905	fd = open ("/dev/serial/ctl0", 0);
906	if (fd < 0) {
907		perror ("/dev/serial/ctl0");
908		exit (-1);
909	}
910	if (ioctl (fd, SERIAL_GETREGISTERED, &mask) < 0) {
911		perror ("getting list of channels");
912		exit (-1);
913	}
914	close (fd);
915#else
916	int fd, fd1, fd2, fd3, i;
917	char buf [80];
918
919	for (i=0, fd=-1; i<12 && fd<0; i++) {
920		sprintf (buf, "/dev/cx%d", i*4);
921		fd = open (buf, 0);
922	}
923
924	for (i=0, fd1=-1; i<3 && fd1<0; i++) {
925		sprintf (buf, "/dev/ct%d", i*2);
926		fd1 = open (buf, 0);
927	}
928
929	for (i=0, fd2=-1; i<3 && fd2<0; i++) {
930		sprintf (buf, "/dev/cp%d", i*4);
931		fd2 = open (buf, 0);
932	}
933
934	/* Try only one */
935	for (i=0, fd3=-1; i<1 && fd3<0; i++) {
936		sprintf (buf, "/dev/ce%d", i*4);
937		fd3 = open (buf, 0);
938	}
939
940	if ((fd < 0) && (fd1 < 0) && (fd2 < 0) && (fd3 < 0)) {
941		fprintf (stderr, "No Cronyx adapters installed\n");
942		exit (-1);
943	}
944
945	if (fd >= 0) {
946		if (ioctl (fd, SERIAL_GETREGISTERED, &mask) < 0) {
947			perror ("getting list of channels");
948			exit (-1);
949		}
950		close (fd);
951	}
952
953	if (fd1 >= 0) {
954		if (ioctl (fd1, SERIAL_GETREGISTERED, (mask+16)) < 0) {
955			perror ("getting list of channels");
956			exit (-1);
957		}
958		close (fd1);
959	}
960
961	if (fd2 >= 0) {
962		if (ioctl (fd2, SERIAL_GETREGISTERED, (mask+32)) < 0) {
963			perror ("getting list of channels");
964			exit (-1);
965		}
966		close (fd2);
967	}
968
969	if (fd3 >= 0) {
970		if (ioctl (fd3, SERIAL_GETREGISTERED, (mask+48)) < 0) {
971			perror ("getting list of channels");
972			exit (-1);
973		}
974		close (fd3);
975	}
976#endif
977}
978
979static int
980open_chan_ctl (int num)
981{
982	char device [80];
983	int fd;
984
985#ifdef __linux__
986	sprintf (device, "/dev/serial/ctl%d", num);
987#else
988	switch (adapter_type) {
989	case 0:
990		sprintf (device, "/dev/cx%d", num);
991		break;
992	case 1:
993		sprintf (device, "/dev/ct%d", num);
994		break;
995	case 2:
996		sprintf (device, "/dev/cp%d", num);
997		break;
998	case 3:
999		sprintf (device, "/dev/ce%d", num);
1000		break;
1001	}
1002#endif
1003	fd = open (device, 0);
1004	if (fd < 0) {
1005		if (errno == ENODEV)
1006			fprintf (stderr, "chan%d: not configured\n", num);
1007		else
1008			perror (device);
1009		exit (-1);
1010	}
1011#ifdef __linux__
1012	if (ioctl (fd, SERIAL_GETNAME, &chan_name) < 0)
1013		sprintf (chan_name, "chan%d", num);
1014#else
1015	switch (adapter_type) {
1016	case 0: sprintf (chan_name, "cx%d", num); break;
1017	case 1: sprintf (chan_name, "ct%d", num); break;
1018	case 2: sprintf (chan_name, "cp%d", num); break;
1019	case 3: sprintf (chan_name, "ce%d", num); break;
1020	}
1021#endif
1022	return fd;
1023}
1024
1025int
1026main (int argc, char **argv)
1027{
1028	char *p;
1029	int fd, need_header, chan_num;
1030
1031	if (argc > 1 && strcmp(argv[1], "help") == 0)
1032		usage();
1033
1034	for (;;) {
1035		switch (getopt (argc, argv, "mseftucviax")) {
1036		case EOF:
1037			break;
1038		case 'a':
1039			++aflag;
1040			continue;
1041		case 'm':
1042			++mflag;
1043			continue;
1044		case 's':
1045			++sflag;
1046			continue;
1047		case 'e':
1048			++eflag;
1049			continue;
1050		case 'f':
1051			++eflag;
1052			++fflag;
1053			continue;
1054		case 't':
1055			++tflag;
1056			continue;
1057		case 'u':
1058			++tflag;
1059			++uflag;
1060			continue;
1061		case 'c':
1062			++cflag;
1063			continue;
1064		case 'v':
1065			++vflag;
1066			continue;
1067		case 'i':
1068			++iflag;
1069			continue;
1070		case 'x':
1071			++xflag;
1072			continue;
1073		default:
1074			usage();
1075		}
1076		break;
1077	}
1078	argc -= optind;
1079	argv += optind;
1080
1081	if (argc <= 0) {
1082		get_mask ();
1083		need_header = 1;
1084		adapter_type = 0;
1085#ifndef __linux__
1086		for (; adapter_type < 4; ++adapter_type)
1087#endif
1088		{
1089		for (chan_num=0; chan_num<MAXCHAN; ++chan_num)
1090			if (mask[adapter_type*16+chan_num/8] & 1 << (chan_num & 7)) {
1091				fd = open_chan_ctl (chan_num);
1092				if (vflag) {
1093#ifdef __linux__
1094				char buf[256];
1095				if (ioctl (fd, SERIAL_GETVERSIONSTRING, &buf) >= 0) {
1096					printf ("Version: %s\n", buf);
1097					close (fd);
1098					return (0);
1099				}
1100#endif
1101				}
1102				if (iflag) {
1103					print_chan (fd);
1104					print_ifconfig (fd);
1105				} else if (sflag||xflag)
1106					print_stats (fd, need_header);
1107				else if (mflag)
1108					print_modems (fd, need_header);
1109				else if (eflag)
1110					print_e1_stats (fd, need_header);
1111				else if (tflag)
1112					print_e3_stats (fd, need_header);
1113				else if (cflag)
1114					clear_stats (fd);
1115				else
1116					print_chan (fd);
1117				close (fd);
1118				need_header = 0;
1119			}
1120		}
1121		return (0);
1122	}
1123
1124	p = argv[0] + strlen (argv[0]);
1125	while (p > argv[0] && p[-1] >= '0' && p[-1] <= '9')
1126		--p;
1127	chan_num = strtol (p, 0, 10);
1128#ifndef __linux__
1129	if (strncasecmp ("cx", argv[0], 2)==0)
1130		adapter_type = 0;
1131	else if (strncasecmp ("ct", argv[0], 2)==0)
1132		adapter_type = 1;
1133	else if (strncasecmp ("cp", argv[0], 2)==0)
1134		adapter_type = 2;
1135	else if (strncasecmp ("ce", argv[0], 2)==0)
1136		adapter_type = 3;
1137	else {
1138		fprintf (stderr, "Wrong channel name\n");
1139		exit (-1);
1140	}
1141#endif
1142	argc--;
1143	argv++;
1144
1145	fd = open_chan_ctl (chan_num);
1146	if (vflag) {
1147#ifdef __linux__
1148		char buf[256];
1149		if (ioctl (fd, SERIAL_GETVERSIONSTRING, &buf) >= 0)
1150			printf ("Version: %s\n", buf);
1151#endif
1152	}
1153	if (iflag) {
1154		print_chan (fd);
1155		print_ifconfig (fd);
1156		close (fd);
1157		return (0);
1158	}
1159	if (sflag||xflag) {
1160		print_stats (fd, 1);
1161		close (fd);
1162		return (0);
1163	}
1164	if (mflag) {
1165		print_modems (fd, 1);
1166		close (fd);
1167		return (0);
1168	}
1169	if (eflag) {
1170		print_e1_stats (fd, 1);
1171		close (fd);
1172		return (0);
1173	}
1174	if (tflag) {
1175		print_e3_stats (fd, 1);
1176		close (fd);
1177		return (0);
1178	}
1179	if (cflag) {
1180		clear_stats (fd);
1181		close (fd);
1182		return (0);
1183	}
1184	if (argc > 0)
1185		setup_chan (fd, argc, argv);
1186	else
1187		print_chan (fd);
1188	close (fd);
1189	return (0);
1190}
1191