1/*
2 * Channel configuration utility for Cronyx serial adapters.
3 *
4 * Copyright (C) 1997-2002 Cronyx Engineering.
5 * Author: Serge Vakulenko, <vak@cronyx.ru>
6 *
7 * Copyright (C) 1999-2005 Cronyx Engineering.
8 * Author: Roman Kurakin, <rik@cronyx.ru>
9 *
10 * This software is distributed with NO WARRANTIES, not even the implied
11 * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 *
13 * Authors grant any other persons or organisations permission to use
14 * or modify this software as long as this message is kept with the software,
15 * all derivative works or modified versions.
16 *
17 * Cronyx Id: sconfig.c,v 1.4.2.2 2005/11/09 13:01:35 rik Exp $
18 */
19
20#include <sys/cdefs.h>
21__FBSDID("$FreeBSD: stable/11/sbin/sconfig/sconfig.c 358078 2020-02-18 18:15:33Z dim $");
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <unistd.h>
27#include <fcntl.h>
28#include <errno.h>
29#include <ctype.h>
30#include <sys/ioctl.h>
31#include <sys/types.h>
32#include <sys/stat.h>
33#include <sys/socket.h>
34#include <net/if.h>
35#include <machine/cserial.h>
36
37#define MAXCHAN 128
38
39int vflag, eflag, sflag, mflag, cflag, fflag, iflag, aflag, xflag;
40int tflag, uflag;
41char mask[64];
42int adapter_type;		/* 0-sigma, 1-tau, 2-taupci, 3-tau32 */
43char chan_name[16];
44
45static void
46usage (void)
47{
48	printf(
49"Serial Adapter Configuration Utility\n"
50"Copyright (C) 1998-2005 Cronyx Engineering.\n"
51"See also man sconfig (8)\n"
52"Usage:\n"
53"\tsconfig [-aimsxeftuc] [device [parameters ...]]\n"
54"\n"
55"Options:\n"
56"\t<no options>\t\t -- print channel options\n"
57"\t-a\t\t\t -- print all settings of the channel\n"
58"\t-i\t\t\t -- print network interface status\n"
59"\t-m\t\t\t -- print modem signal status\n"
60"\t-s\t\t\t -- print channel statistics\n"
61"\t-x\t\t\t -- print extended channel statistics\n"
62"\t-e\t\t\t -- print short E1/G703 statistics\n"
63"\t-f\t\t\t -- print full E1/G703 statistics\n"
64"\t-t\t\t\t -- print short E3/T3/STS-1 statistics\n"
65"\t-u\t\t\t -- print full E3/T3/STS-1 statistics\n"
66"\t-c\t\t\t -- clear statistics\n"
67"\nParameters:\n"
68"\t<number>\t\t -- baud rate, internal clock\n"
69"\textclock\t\t -- external clock (default)\n"
70"\nProtocol options:\n"
71"\tasync\t\t\t -- asynchronous protocol\n"
72#ifdef __linux__
73"\tsync\t\t\t -- synchronous protocol\n"
74#endif
75"\tcisco\t\t\t -- Cisco/HDLC protocol\n"
76"\tfr\t\t\t -- Frame Relay protocol\n"
77#ifdef __linux__
78"\t    dlci<number>\t -- Add new DLCI\n"
79#endif
80"\tppp\t\t\t -- PPP protocol\n"
81#ifdef __linux__
82"\trbrg\t\t\t -- Remote bridge\n"
83"\traw\t\t\t -- raw HDLC protocol\n"
84"\tpacket\t\t\t -- packetized HDLC protocol\n"
85"\tidle\t\t\t -- no protocol\n"
86#else
87"\t    keepalive={on,of}\t -- Enable/disable keepalive\n"
88#endif
89"\nInterface options:\n"
90"\tport={rs232,v35,rs449}\t -- port type (for old models of Sigma)\n"
91"\tcfg={A,B,C}\t\t -- adapter configuration\n"
92"\tloop={on,off}\t\t -- internal loopback\n"
93"\trloop={on,off}\t\t -- remote loopback\n"
94"\tdpll={on,off}\t\t -- DPLL mode\n"
95"\tnrzi={on,off}\t\t -- NRZI encoding\n"
96"\tinvclk={on,off}\t\t -- invert receive and transmit clock\n"
97"\tinvrclk={on,off}\t -- invert receive clock\n"
98"\tinvtclk={on,off}\t -- invert transmit clock\n"
99"\thigain={on,off}\t\t -- E1 high non linear input sensitivity \n\t\t\t\t    (long line)\n"
100"\tmonitor={on,off}\t -- E1 high linear input sensitivity \n\t\t\t\t    (interception mode)\n"
101"\tphony={on,off}\t\t -- E1 telepnony mode\n"
102"\tunfram={on,off}\t\t -- E1 unframed mode\n"
103"\tscrambler={on,off}\t -- G.703 scrambling mode\n"
104"\tuse16={on,off}\t\t -- E1 timeslot 16 usage\n"
105"\tcrc4={on,off}\t\t -- E1 CRC4 mode\n"
106#ifdef __linux__
107"\tami={on,off}\t\t -- E1 AMI or HDB3 line code\n"
108"\tmtu={size}\t\t -- set MTU in bytes\n"
109#endif
110"\tsyn={int,rcv,rcvX}\t -- G.703 transmit clock\n"
111"\tts=...\t\t\t -- E1 timeslots\n"
112"\tpass=...\t\t -- E1 subchannel timeslots\n"
113"\tdir=<num>\t\t -- connect channel to link<num>\n"
114/*"\trqken={size}\t\t -- set receive queue length in packets\n"*/
115/*"\tcablen={on,off}\t\t -- T3/STS-1 high transmitter output for long cable\n"*/
116"\tdebug={0,1,2}\t\t -- enable/disable debug messages\n"
117	);
118	exit (0);
119}
120
121static unsigned long
122scan_timeslots (char *s)
123{
124	char *e;
125	long v;
126	int i;
127	unsigned long ts, lastv;
128
129	ts = lastv = 0;
130	for (;;) {
131		v = strtol (s, &e, 10);
132		if (e == s)
133			break;
134		if (*e == '-') {
135			lastv = v;
136			s = e+1;
137			continue;
138		}
139		if (*e == ',')
140			++e;
141
142		if (lastv)
143			for (i=lastv; i<v; ++i)
144				ts |= 1L << i;
145		ts |= 1L << v;
146
147		lastv = 0;
148		s = e;
149	}
150	return ts;
151}
152
153static int
154ppp_ok (void)
155{
156#ifdef __linux__
157	int s, p;
158	struct ifreq ifr;
159	char pttyname[32];
160	char *p1, *p2;
161	int i, j;
162	int ppp_disc = N_PPP;
163
164	/*
165	 * Open a socket for doing the ioctl operations.
166	 */
167	s = socket (AF_INET, SOCK_DGRAM, 0);
168	if (s < 0) {
169		fprintf (stderr, "Error opening socket.\n");
170		return 0;
171	}
172	strncpy (ifr.ifr_name, "ppp0", sizeof (ifr.ifr_name));
173	if (ioctl (s, SIOCGIFFLAGS, (caddr_t) &ifr) >= 0) {
174		/* Ok. */
175		close (s);
176		return 1;
177	}
178	close (s);
179
180	/* open pseudo-tty and try to set PPP discipline */
181	sprintf (pttyname, "/dev/ptyXX");
182	p1 = &pttyname[8];
183	p2 = &pttyname[9];
184	for (i=0; i<16; i++) {
185		struct stat stb;
186
187		*p1 = "pqrstuvwxyzabcde"[i];
188		*p2 = '0';
189		if (stat (pttyname, &stb) < 0)
190			continue;
191		for (j=0; j<16; j++) {
192			*p2 = "0123456789abcdef"[j];
193			p = open (pttyname, 2);
194			if (p > 0) {
195				if (ioctl (p, TIOCSETD, &ppp_disc) < 0) {
196					fprintf (stderr, "No PPP discipline in kernel.\n");
197					close (p);
198					return 0;
199				}
200				close (p);
201				return 1;
202			}
203		}
204	}
205	fprintf (stderr, "Cannot get pseudo-tty.\n");
206	return 0;
207#else
208	return 1;
209#endif
210}
211
212static char *
213format_timeslots (unsigned long s)
214{
215	static char buf [100];
216	char *p = buf;
217	int i;
218
219	for (i=1; i<32; ++i)
220		if ((s >> i) & 1) {
221			int prev = (i > 1)  & (s >> (i-1));
222			int next = (i < 31) & (s >> (i+1));
223
224			if (prev) {
225				if (next)
226					continue;
227				*p++ = '-';
228			} else if (p > buf)
229				*p++ = ',';
230
231			if (i >= 10)
232				*p++ = '0' + i / 10;
233			*p++ = '0' + i % 10;
234		}
235	*p = 0;
236	return buf;
237}
238
239static void
240print_modems (int fd, int need_header)
241{
242	int status;
243
244	if (ioctl (fd, TIOCMGET, &status) < 0) {
245		perror ("getting modem status");
246		return;
247	}
248	if (need_header)
249		printf ("Channel\tLE\tDTR\tDSR\tRTS\tCTS\tCD\n");
250	printf ("%s\t%s\t%s\t%s\t%s\t%s\t%s\n", chan_name,
251		status & TIOCM_LE  ? "On" : "-",
252		status & TIOCM_DTR ? "On" : "-",
253		status & TIOCM_DSR ? "On" : "-",
254		status & TIOCM_RTS ? "On" : "-",
255		status & TIOCM_CTS ? "On" : "-",
256		status & TIOCM_CD  ? "On" : "-");
257}
258
259static void
260#ifdef __linux__
261print_ifconfig (int fd)
262#else
263print_ifconfig (int fd __unused)
264#endif
265{
266	char buf [64];
267#ifdef __linux__
268	char protocol [8];
269
270	if (ioctl (fd, SERIAL_GETPROTO, &protocol) >= 0 &&
271	    strcmp (protocol, "fr") == 0)
272		sprintf (buf, "ifconfig %sd16 2>/dev/null", chan_name);
273	else
274#endif
275	sprintf (buf, "ifconfig %s 2>/dev/null", chan_name);
276	system (buf);
277}
278
279static void
280set_debug_ifconfig (int on)
281{
282	char buf [64];
283	sprintf (buf, "ifconfig %s %sdebug 2>/dev/null", chan_name,
284		 on ? "" : "-");
285	system (buf);
286}
287
288static char *
289format_long (unsigned long val)
290{
291	static char s[32];
292	int l;
293	l = sprintf (s, "%lu", val);
294	if (l>7 && !sflag) {
295		s[3] = s[2];
296		s[2] = s[1];
297		s[1] = '.';
298		s[4] = 'e';
299		sprintf (s + 5, "%02d", l-1);
300	}
301	return s;
302}
303
304static void
305print_stats (int fd, int need_header)
306{
307	struct serial_statistics st;
308	unsigned long sarr [9];
309	int i;
310
311	if (ioctl (fd, SERIAL_GETSTAT, &st) < 0) {
312		perror ("getting statistics");
313		return;
314	}
315	if (need_header) {
316		if (sflag) {
317			printf ("        ------------Receive-----------      "
318				"------------Transmit----------\n");
319			printf ("Channel Interrupts  Packets     Errors      "
320				"Interrupts  Packets     Errors\n");
321		}
322		else    {
323			printf ("        --------Receive---------------  "
324				"--------Transmit--------------  Modem\n");
325			printf ("Channel Intrs   Bytes   Packets Errors  "
326				"Intrs   Bytes   Packets Errors  Intrs\n");
327		}
328	}
329
330	sarr [0] = st.rintr;
331	sarr [1] = st.ibytes;
332	sarr [2] = st.ipkts;
333	sarr [3] = st.ierrs;
334	sarr [4] = st.tintr;
335	sarr [5] = st.obytes;
336	sarr [6] = st.opkts;
337	sarr [7] = st.oerrs;
338	sarr [8] = st.mintr;
339	printf ("%s", chan_name);
340	if (sflag) {
341		printf ("\t%-12lu%-12lu%-12lu%-12lu%-12lu%-12lu", sarr[0],
342			sarr[2], sarr[3], sarr[4], sarr[6], sarr[7]);
343	} else {
344		for (i = 0; i < 9; i++)
345			printf ("\t%s", format_long (sarr [i]));
346		printf ("\n");
347	}
348}
349
350static void
351clear_stats (int fd)
352{
353	if (ioctl (fd, SERIAL_CLRSTAT, 0) < 0) {
354		perror ("clearing statistics");
355		exit (-1);
356	}
357}
358
359static char *
360format_e1_status (unsigned long status)
361{
362	static char buf [80];
363
364	if (status == 0)
365		return "n/a";
366	if (status & E1_NOALARM)
367		return "Ok";
368	buf[0] = 0;
369	if (status & E1_LOS)     strcat (buf, ",LOS");
370	if (status & E1_AIS)     strcat (buf, ",AIS");
371	if (status & E1_LOF)     strcat (buf, ",LOF");
372	if (status & E1_LOMF)    strcat (buf, ",LOMF");
373	if (status & E1_CRC4E)   strcat (buf, ",CRC4E");
374	if (status & E1_FARLOF)  strcat (buf, ",FARLOF");
375	if (status & E1_AIS16)   strcat (buf, ",AIS16");
376	if (status & E1_FARLOMF) strcat (buf, ",FARLOMF");
377/*	if (status & E1_TSTREQ)  strcat (buf, ",TSTREQ");*/
378/*	if (status & E1_TSTERR)  strcat (buf, ",TSTERR");*/
379	if (buf[0] == ',')
380		return buf+1;
381	return "Unknown";
382}
383
384static void
385print_frac (int leftalign, unsigned long numerator, unsigned long divider)
386{
387	int n;
388
389	if (numerator < 1 || divider < 1) {
390		printf (leftalign ? "/-   " : "    -");
391		return;
392	}
393	n = (int) (0.5 + 1000.0 * numerator / divider);
394	if (n < 1000) {
395		printf (leftalign ? "/.%-3d" : " .%03d", n);
396		return;
397	}
398	putchar (leftalign ? '/' : ' ');
399
400	if      (n >= 1000000) n = (n+500) / 1000 * 1000;
401	else if (n >= 100000)  n = (n+50)  / 100 * 100;
402	else if (n >= 10000)   n = (n+5)   / 10 * 10;
403
404	switch (n) {
405	case 1000:    printf (".999"); return;
406	case 10000:   n = 9990;   break;
407	case 100000:  n = 99900;  break;
408	case 1000000: n = 999000; break;
409	}
410	if (n < 10000)        printf ("%d.%d", n/1000, n/10%100);
411	else if (n < 100000)  printf ("%d.%d", n/1000, n/100%10);
412	else if (n < 1000000) printf ("%d.", n/1000);
413	else                  printf ("%d", n/1000);
414}
415
416static void
417print_e1_stats (int fd, int need_header)
418{
419	struct e1_statistics st;
420	int i, maxi;
421
422	if (need_header)
423		printf ("Chan\t Unav/Degr  Bpv/Fsyn  CRC/RCRC  Err/Lerr  Sev/Bur   Oof/Slp  Status\n");
424
425	if (ioctl (fd, SERIAL_GETESTAT, &st) < 0)
426		return;
427	printf ("%s\t", chan_name);
428
429	/* Unavailable seconds, degraded minutes */
430	print_frac (0, st.currnt.uas, st.cursec);
431	print_frac (1, 60 * st.currnt.dm, st.cursec);
432
433	/* Bipolar violations, frame sync errors */
434	print_frac (0, st.currnt.bpv, st.cursec);
435	print_frac (1, st.currnt.fse, st.cursec);
436
437	/* CRC errors, remote CRC errors (E-bit) */
438	print_frac (0, st.currnt.crce, st.cursec);
439	print_frac (1, st.currnt.rcrce, st.cursec);
440
441	/* Errored seconds, line errored seconds */
442	print_frac (0, st.currnt.es, st.cursec);
443	print_frac (1, st.currnt.les, st.cursec);
444
445	/* Severely errored seconds, bursty errored seconds */
446	print_frac (0, st.currnt.ses, st.cursec);
447	print_frac (1, st.currnt.bes, st.cursec);
448
449	/* Out of frame seconds, controlled slip seconds */
450	print_frac (0, st.currnt.oofs, st.cursec);
451	print_frac (1, st.currnt.css, st.cursec);
452
453	printf (" %s\n", format_e1_status (st.status));
454
455	if (fflag) {
456		/* Print total statistics. */
457		printf ("\t");
458		print_frac (0, st.total.uas, st.totsec);
459		print_frac (1, 60 * st.total.dm, st.totsec);
460
461		print_frac (0, st.total.bpv, st.totsec);
462		print_frac (1, st.total.fse, st.totsec);
463
464		print_frac (0, st.total.crce, st.totsec);
465		print_frac (1, st.total.rcrce, st.totsec);
466
467		print_frac (0, st.total.es, st.totsec);
468		print_frac (1, st.total.les, st.totsec);
469
470		print_frac (0, st.total.ses, st.totsec);
471		print_frac (1, st.total.bes, st.totsec);
472
473		print_frac (0, st.total.oofs, st.totsec);
474		print_frac (1, st.total.css, st.totsec);
475
476		printf (" -- Total\n");
477
478		/* Print 24-hour history. */
479		maxi = (st.totsec - st.cursec) / 900;
480		if (maxi > 48)
481			maxi = 48;
482		for (i=0; i<maxi; ++i) {
483			printf ("       ");
484			print_frac (0, st.interval[i].uas, 15*60);
485			print_frac (1, 60 * st.interval[i].dm, 15*60);
486
487			print_frac (0, st.interval[i].bpv, 15*60);
488			print_frac (1, st.interval[i].fse, 15*60);
489
490			print_frac (0, st.interval[i].crce, 15*60);
491			print_frac (1, st.interval[i].rcrce, 15*60);
492
493			print_frac (0, st.interval[i].es, 15*60);
494			print_frac (1, st.interval[i].les, 15*60);
495
496			print_frac (0, st.interval[i].ses, 15*60);
497			print_frac (1, st.interval[i].bes, 15*60);
498
499			print_frac (0, st.interval[i].oofs, 15*60);
500			print_frac (1, st.interval[i].css, 15*60);
501
502			if (i < 3)
503				printf (" -- %dm\n", (i+1)*15);
504			else
505				printf (" -- %dh %dm\n", (i+1)/4, (i+1)%4*15);
506		}
507	}
508}
509
510static char *
511format_e3_status (unsigned long status)
512{
513	static char buf [80];
514
515	buf[0] = 0;
516	if (status & E3_LOS)     strcat (buf, ",LOS");
517	if (status & E3_TXE)     strcat (buf, ",XMIT");
518	if (buf[0] == ',')
519		return buf+1;
520	return "Ok";
521}
522
523static char *
524format_e3_cv (unsigned long cv, unsigned long baud, unsigned long atime)
525{
526	static char buf[80];
527
528	if (!cv || !baud || !atime)
529		sprintf (buf, "         -         ");
530	else
531		sprintf (buf, "%10lu (%.1e)", cv, (double)cv/baud/atime);
532	return buf;
533}
534
535static void
536print_e3_stats (int fd, int need_header)
537{
538	struct e3_statistics st;
539	int i, maxi;
540	long baud;
541
542	if (need_header)
543		printf ("Chan\t--Code Violations---\t\t\t\t\t ----Status----\n");
544
545	if (ioctl (fd, SERIAL_GETE3STAT, &st) < 0 ||
546	    ioctl (fd, SERIAL_GETBAUD, &baud) < 0)
547		return;
548
549	if (!st.cursec)
550		st.cursec = 1;
551
552	printf ("%s\t%s\t\t\t\t\t", chan_name,
553		format_e3_cv (st.ccv, baud, st.cursec));
554
555	printf (" %s\n", format_e3_status (st.status));
556
557
558	if (uflag) {
559		/* Print total statistics. */
560		printf ("\t%s\t\t\t\t\t",
561			format_e3_cv (st.tcv, baud, st.totsec));
562		printf (" -- Total\n");
563
564		/* Print 24-hour history. */
565		maxi = (st.totsec - st.cursec) / 900;
566		if (maxi > 48)
567			maxi = 48;
568		for (i=0; i<maxi; ++i) {
569			printf ("\t%s\t\t\t\t\t",
570				format_e3_cv (st.icv[i], baud, 15*60));
571			if (i < 3)
572				printf (" -- %2dm\n", (i+1)*15);
573			else
574				printf (" -- %2dh %2dm\n", (i+1)/4, (i+1)%4*15);
575		}
576	}
577}
578
579static void
580print_chan (int fd)
581{
582	char protocol [8];
583	char cfg;
584	int loop, dpll, nrzi, invclk, clk, higain, phony, use16, crc4;
585	int level, keepalive, debug, port, invrclk, invtclk, unfram, monitor;
586	int cable, dir, scrambler, ami, mtu;
587	int cablen, rloop, rqlen;
588	long baud, timeslots, subchan;
589	int protocol_valid, baud_valid, loop_valid, use16_valid, crc4_valid;
590	int dpll_valid, nrzi_valid, invclk_valid, clk_valid, phony_valid;
591	int timeslots_valid, subchan_valid, higain_valid, level_valid;
592	int keepalive_valid, debug_valid, cfg_valid, port_valid;
593	int invrclk_valid, invtclk_valid, unfram_valid, monitor_valid;
594	int cable_valid, dir_valid, scrambler_valid, ami_valid, mtu_valid;
595	int cablen_valid, rloop_valid, rqlen_valid;
596
597	protocol_valid  = ioctl (fd, SERIAL_GETPROTO, &protocol) >= 0;
598	cfg_valid       = ioctl (fd, SERIAL_GETCFG, &cfg) >= 0;
599	baud_valid      = ioctl (fd, SERIAL_GETBAUD, &baud) >= 0;
600	loop_valid      = ioctl (fd, SERIAL_GETLOOP, &loop) >= 0;
601	dpll_valid      = ioctl (fd, SERIAL_GETDPLL, &dpll) >= 0;
602	nrzi_valid      = ioctl (fd, SERIAL_GETNRZI, &nrzi) >= 0;
603	invclk_valid    = ioctl (fd, SERIAL_GETINVCLK, &invclk) >= 0;
604	invrclk_valid	= ioctl (fd, SERIAL_GETINVRCLK, &invrclk) >= 0;
605	invtclk_valid	= ioctl (fd, SERIAL_GETINVTCLK, &invtclk) >= 0;
606	clk_valid       = ioctl (fd, SERIAL_GETCLK, &clk) >= 0;
607	timeslots_valid = ioctl (fd, SERIAL_GETTIMESLOTS, &timeslots) >= 0;
608	subchan_valid   = ioctl (fd, SERIAL_GETSUBCHAN, &subchan) >= 0;
609	higain_valid    = ioctl (fd, SERIAL_GETHIGAIN, &higain) >= 0;
610	phony_valid     = ioctl (fd, SERIAL_GETPHONY, &phony) >= 0;
611	unfram_valid    = ioctl (fd, SERIAL_GETUNFRAM, &unfram) >= 0;
612	monitor_valid   = ioctl (fd, SERIAL_GETMONITOR, &monitor) >= 0;
613	use16_valid     = ioctl (fd, SERIAL_GETUSE16, &use16) >= 0;
614	crc4_valid      = ioctl (fd, SERIAL_GETCRC4, &crc4) >= 0;
615	ami_valid	= ioctl (fd, SERIAL_GETLCODE, &ami) >= 0;
616	level_valid     = ioctl (fd, SERIAL_GETLEVEL, &level) >= 0;
617	keepalive_valid = ioctl (fd, SERIAL_GETKEEPALIVE, &keepalive) >= 0;
618	debug_valid     = ioctl (fd, SERIAL_GETDEBUG, &debug) >= 0;
619	port_valid	= ioctl (fd, SERIAL_GETPORT, &port) >= 0;
620	cable_valid	= ioctl (fd, SERIAL_GETCABLE, &cable) >= 0;
621	dir_valid	= ioctl (fd, SERIAL_GETDIR, &dir) >= 0;
622	scrambler_valid	= ioctl (fd, SERIAL_GETSCRAMBLER, &scrambler) >= 0;
623	cablen_valid	= ioctl (fd, SERIAL_GETCABLEN, &cablen) >= 0;
624	rloop_valid	= ioctl (fd, SERIAL_GETRLOOP, &rloop) >= 0;
625	mtu_valid	= ioctl (fd, SERIAL_GETMTU, &mtu) >= 0;
626	rqlen_valid	= ioctl (fd, SERIAL_GETRQLEN, &rqlen) >= 0;
627
628	printf ("%s", chan_name);
629	if (port_valid)
630		switch (port) {
631		case 0:	printf (" (rs232)"); break;
632		case 1:	printf (" (v35)"); break;
633		case 2:	printf (" (rs530)"); break;
634		}
635	else if (cable_valid)
636		switch (cable) {
637		case 0:	printf (" (rs232)"); break;
638		case 1:	printf (" (v35)"); break;
639		case 2:	printf (" (rs530)"); break;
640		case 3:	printf (" (x21)"); break;
641		case 4:	printf (" (rs485)"); break;
642		case 9:	printf (" (no cable)"); break;
643		}
644	if (debug_valid && debug)
645		printf (" debug=%d", debug);
646	if (protocol_valid && *protocol)
647		printf (" %.8s", protocol);
648	else
649		printf (" idle");
650	if (cablen_valid)
651		printf (" cablen=%s", cablen ? "on" : "off");
652	if (keepalive_valid)
653		printf (" keepalive=%s", keepalive ? "on" : "off");
654
655	if (cfg_valid)
656		switch (cfg) {
657		case 'a' :	printf (" cfg=A");	break;
658		case 'b' :	printf (" cfg=B");	break;
659		case 'c' :	printf (" cfg=C");	break;
660		case 'd' :	printf (" cfg=D");	break;
661		default  :	printf (" cfg=unknown");
662		}
663	if (dir_valid)
664		printf (" dir=%d", dir);
665
666	if (baud_valid) {
667		if (baud)
668			printf (" %ld", baud);
669		else
670			printf (" extclock");
671	}
672	if (mtu_valid)
673		printf (" mtu=%d", mtu);
674
675	if (aflag && rqlen_valid)
676		printf (" rqlen=%d", rqlen);
677
678	if (clk_valid)
679		switch (clk) {
680		case E1CLK_INTERNAL:	  printf (" syn=int");     break;
681		case E1CLK_RECEIVE:	  printf (" syn=rcv");     break;
682		case E1CLK_RECEIVE_CHAN0: printf (" syn=rcv0");    break;
683		case E1CLK_RECEIVE_CHAN1: printf (" syn=rcv1");    break;
684		case E1CLK_RECEIVE_CHAN2: printf (" syn=rcv2");    break;
685		case E1CLK_RECEIVE_CHAN3: printf (" syn=rcv3");    break;
686		default:                  printf (" syn=%d", clk); break;
687		}
688
689	if (dpll_valid)
690		printf (" dpll=%s", dpll ? "on" : "off");
691	if (nrzi_valid)
692		printf (" nrzi=%s", nrzi ? "on" : "off");
693	if (invclk_valid)
694		printf (" invclk=%s", invclk ? "on" : "off");
695	if (invrclk_valid)
696		printf (" invrclk=%s", invrclk ? "on" : "off");
697	if (invtclk_valid)
698		printf (" invtclk=%s", invtclk ? "on" : "off");
699	if (unfram_valid)
700		printf (" unfram=%s", unfram ? "on" : "off");
701	if (use16_valid)
702		printf (" use16=%s", use16 ? "on" : "off");
703	if (aflag) {
704		if (crc4_valid)
705			printf (" crc4=%s", crc4 ? "on" : "off");
706		if (higain_valid)
707			printf (" higain=%s", higain ? "on" : "off");
708		if (monitor_valid)
709			printf (" monitor=%s", monitor ? "on" : "off");
710		if (phony_valid)
711			printf (" phony=%s", phony ? "on" : "off");
712		if (scrambler_valid)
713			printf (" scrambler=%s", scrambler ? "on" : "off");
714		if (loop_valid)
715			printf (" loop=%s", loop ? "on" : "off");
716		if (rloop_valid)
717			printf (" rloop=%s", rloop ? "on" : "off");
718		if (ami_valid)
719			printf (" ami=%s", ami ? "on" : "off");
720	}
721	if (timeslots_valid)
722		printf (" ts=%s", format_timeslots (timeslots));
723	if (subchan_valid)
724		printf (" pass=%s", format_timeslots (subchan));
725	if (level_valid)
726		printf (" (level=-%.1fdB)", level / 10.0);
727	printf ("\n");
728}
729
730static void
731setup_chan (int fd, int argc, char **argv)
732{
733	int i, mode, loop, nrzi, dpll, invclk, phony, use16, crc4, unfram, ami;
734	int higain, clk, keepalive, debug, port, dlci, invrclk, invtclk;
735	int monitor, dir, scrambler, rloop, cablen;
736	int mode_valid;
737	long baud, timeslots, mtu, rqlen;
738
739	for (i=0; i<argc; ++i) {
740		if (argv[i][0] >= '0' && argv[i][0] <= '9') {
741			baud = strtol (argv[i], 0, 10);
742			ioctl (fd, SERIAL_SETBAUD, &baud);
743		} else if (strcasecmp ("extclock", argv[i]) == 0) {
744			baud = 0;
745			ioctl (fd, SERIAL_SETBAUD, &baud);
746		} else if (strncasecmp ("cfg=", argv[i], 4) == 0) {
747			if (strncasecmp ("a", argv[i]+4, 1) == 0)
748				ioctl (fd, SERIAL_SETCFG, "a");
749			else if (strncasecmp ("b", argv[i]+4, 1) == 0)
750				ioctl (fd, SERIAL_SETCFG, "b");
751			else if (strncasecmp ("c", argv[i]+4, 1) == 0)
752				ioctl (fd, SERIAL_SETCFG, "c");
753			else if (strncasecmp ("d", argv[i]+4, 1) == 0)
754				ioctl (fd, SERIAL_SETCFG, "d");
755			else {
756				fprintf (stderr, "invalid cfg\n");
757				exit (-1);
758			}
759		} else if (strcasecmp ("idle", argv[i]) == 0)
760			ioctl (fd, SERIAL_SETPROTO, "\0\0\0\0\0\0\0");
761		else if (strcasecmp ("async", argv[i]) == 0) {
762			mode = SERIAL_ASYNC;
763			if (ioctl (fd, SERIAL_SETMODE, &mode) >= 0)
764				ioctl (fd, SERIAL_SETPROTO, "async\0\0");
765		} else if (strcasecmp ("sync", argv[i]) == 0) {
766			mode = SERIAL_HDLC;
767			if (ioctl (fd, SERIAL_SETMODE, &mode) >= 0)
768				ioctl (fd, SERIAL_SETPROTO, "sync\0\0\0");
769		} else if (strcasecmp ("cisco", argv[i]) == 0) {
770			mode = SERIAL_HDLC;
771			ioctl (fd, SERIAL_SETMODE, &mode);
772			ioctl (fd, SERIAL_SETPROTO, "cisco\0\0");
773		} else if (strcasecmp ("rbrg", argv[i]) == 0) {
774			mode = SERIAL_HDLC;
775			ioctl (fd, SERIAL_SETMODE, &mode);
776			ioctl (fd, SERIAL_SETPROTO, "rbrg\0\0\0");
777		} else if (strcasecmp ("raw", argv[i]) == 0) {
778			mode = SERIAL_HDLC;
779			ioctl (fd, SERIAL_SETMODE, &mode);
780			ioctl (fd, SERIAL_SETPROTO, "raw\0\0\0\0");
781		} else if (strcasecmp ("packet", argv[i]) == 0) {
782			mode = SERIAL_HDLC;
783			ioctl (fd, SERIAL_SETMODE, &mode);
784			ioctl (fd, SERIAL_SETPROTO, "packet\0");
785		} else if (strcasecmp ("ppp", argv[i]) == 0) {
786			/* check that ppp line discipline is present */
787			if (ppp_ok ()) {
788				mode = SERIAL_HDLC;
789				ioctl (fd, SERIAL_SETMODE, &mode);
790				ioctl (fd, SERIAL_SETPROTO, "ppp\0\0\0\0");
791			}
792		} else if (strncasecmp ("keepalive=", argv[i], 10) == 0) {
793			keepalive = (strcasecmp ("on", argv[i] + 10) == 0);
794			ioctl (fd, SERIAL_SETKEEPALIVE, &keepalive);
795		} else if (strcasecmp ("fr", argv[i]) == 0) {
796			mode = SERIAL_HDLC;
797			ioctl (fd, SERIAL_SETMODE, &mode);
798			ioctl (fd, SERIAL_SETPROTO, "fr\0\0\0\0\0");
799		} else if (strcasecmp ("zaptel", argv[i]) == 0) {
800			mode = SERIAL_HDLC;
801			ioctl (fd, SERIAL_SETMODE, &mode);
802			ioctl (fd, SERIAL_SETPROTO, "zaptel\0");
803		} else if (strncasecmp ("debug=", argv[i], 6) == 0) {
804			debug = strtol (argv[i]+6, 0, 10);
805			mode_valid = ioctl (fd, SERIAL_GETMODE, &mode) >= 0;
806			if (!mode_valid || mode != SERIAL_ASYNC) {
807				if (debug == 0) {
808					set_debug_ifconfig(0);
809				} else {
810					ioctl (fd, SERIAL_SETDEBUG, &debug);
811					set_debug_ifconfig(1);
812				}
813			} else {
814				ioctl (fd, SERIAL_SETDEBUG, &debug);
815			}
816		} else if (strncasecmp ("loop=", argv[i], 5) == 0) {
817			loop = (strcasecmp ("on", argv[i] + 5) == 0);
818			ioctl (fd, SERIAL_SETLOOP, &loop);
819		} else if (strncasecmp ("rloop=", argv[i], 6) == 0) {
820			rloop = (strcasecmp ("on", argv[i] + 6) == 0);
821			ioctl (fd, SERIAL_SETRLOOP, &rloop);
822		} else if (strncasecmp ("dpll=", argv[i], 5) == 0) {
823			dpll = (strcasecmp ("on", argv[i] + 5) == 0);
824			ioctl (fd, SERIAL_SETDPLL, &dpll);
825		} else if (strncasecmp ("nrzi=", argv[i], 5) == 0) {
826			nrzi = (strcasecmp ("on", argv[i] + 5) == 0);
827			ioctl (fd, SERIAL_SETNRZI, &nrzi);
828		} else if (strncasecmp ("invclk=", argv[i], 7) == 0) {
829			invclk = (strcasecmp ("on", argv[i] + 7) == 0);
830			ioctl (fd, SERIAL_SETINVCLK, &invclk);
831		} else if (strncasecmp ("invrclk=", argv[i], 8) == 0) {
832			invrclk = (strcasecmp ("on", argv[i] + 8) == 0);
833			ioctl (fd, SERIAL_SETINVRCLK, &invrclk);
834		} else if (strncasecmp ("invtclk=", argv[i], 8) == 0) {
835			invtclk = (strcasecmp ("on", argv[i] + 8) == 0);
836			ioctl (fd, SERIAL_SETINVTCLK, &invtclk);
837		} else if (strncasecmp ("higain=", argv[i], 7) == 0) {
838			higain = (strcasecmp ("on", argv[i] + 7) == 0);
839			ioctl (fd, SERIAL_SETHIGAIN, &higain);
840		} else if (strncasecmp ("phony=", argv[i], 6) == 0) {
841			phony = (strcasecmp ("on", argv[i] + 6) == 0);
842			ioctl (fd, SERIAL_SETPHONY, &phony);
843		} else if (strncasecmp ("unfram=", argv[i], 7) == 0) {
844			unfram = (strcasecmp ("on", argv[i] + 7) == 0);
845			ioctl (fd, SERIAL_SETUNFRAM, &unfram);
846		} else if (strncasecmp ("scrambler=", argv[i], 10) == 0) {
847			scrambler = (strcasecmp ("on", argv[i] + 10) == 0);
848			ioctl (fd, SERIAL_SETSCRAMBLER, &scrambler);
849		} else if (strncasecmp ("monitor=", argv[i], 8) == 0) {
850			monitor = (strcasecmp ("on", argv[i] + 8) == 0);
851			ioctl (fd, SERIAL_SETMONITOR, &monitor);
852		} else if (strncasecmp ("use16=", argv[i], 6) == 0) {
853			use16 = (strcasecmp ("on", argv[i] + 6) == 0);
854			ioctl (fd, SERIAL_SETUSE16, &use16);
855		} else if (strncasecmp ("crc4=", argv[i], 5) == 0) {
856			crc4 = (strcasecmp ("on", argv[i] + 5) == 0);
857			ioctl (fd, SERIAL_SETCRC4, &crc4);
858		} else if (strncasecmp ("ami=", argv[i], 4) == 0) {
859			ami = (strcasecmp ("on", argv[i] + 4) == 0);
860			ioctl (fd, SERIAL_SETLCODE, &ami);
861		} else if (strncasecmp ("mtu=", argv[i], 4) == 0) {
862			mtu = strtol (argv[i] + 4, 0, 10);
863			ioctl (fd, SERIAL_SETMTU, &mtu);
864		} else if (strncasecmp ("rqlen=", argv[i], 6) == 0) {
865			rqlen = strtol (argv[i] + 6, 0, 10);
866			ioctl (fd, SERIAL_SETRQLEN, &rqlen);
867		} else if (strcasecmp ("syn=int", argv[i]) == 0) {
868			clk = E1CLK_INTERNAL;
869			ioctl (fd, SERIAL_SETCLK, &clk);
870		} else if (strcasecmp ("syn=rcv", argv[i]) == 0) {
871			clk = E1CLK_RECEIVE;
872			ioctl (fd, SERIAL_SETCLK, &clk);
873		} else if (strcasecmp ("syn=rcv0", argv[i]) == 0) {
874			clk = E1CLK_RECEIVE_CHAN0;
875			ioctl (fd, SERIAL_SETCLK, &clk);
876		} else if (strcasecmp ("syn=rcv1", argv[i]) == 0) {
877			clk = E1CLK_RECEIVE_CHAN1;
878			ioctl (fd, SERIAL_SETCLK, &clk);
879		} else if (strcasecmp ("syn=rcv2", argv[i]) == 0) {
880			clk = E1CLK_RECEIVE_CHAN2;
881			ioctl (fd, SERIAL_SETCLK, &clk);
882		} else if (strcasecmp ("syn=rcv3", argv[i]) == 0) {
883			clk = E1CLK_RECEIVE_CHAN3;
884			ioctl (fd, SERIAL_SETCLK, &clk);
885		} else if (strncasecmp ("ts=", argv[i], 3) == 0) {
886			timeslots = scan_timeslots (argv[i] + 3);
887			ioctl (fd, SERIAL_SETTIMESLOTS, &timeslots);
888		} else if (strncasecmp ("pass=", argv[i], 5) == 0) {
889			timeslots = scan_timeslots (argv[i] + 5);
890			ioctl (fd, SERIAL_SETSUBCHAN, &timeslots);
891		} else if (strncasecmp ("dlci", argv[i], 4) == 0) {
892			dlci = strtol (argv[i]+4, 0, 10);
893			ioctl (fd, SERIAL_ADDDLCI, &dlci);
894		} else if (strncasecmp ("dir=", argv[i], 4) == 0) {
895			dir = strtol (argv[i]+4, 0, 10);
896			ioctl (fd, SERIAL_SETDIR, &dir);
897		} else if (strncasecmp ("port=", argv[i], 5) == 0) {
898			if (strncasecmp ("rs232", argv[i]+5, 5) == 0) {
899				port = 0;
900				ioctl (fd, SERIAL_SETPORT, &port);
901			} else if (strncasecmp ("v35", argv[i]+5, 3) == 0) {
902				port = 1;
903				ioctl (fd, SERIAL_SETPORT, &port);
904			} else if (strncasecmp ("rs449", argv[i]+5, 5) == 0) {
905				port = 2;
906				ioctl (fd, SERIAL_SETPORT, &port);
907			} else {
908				fprintf (stderr, "invalid port type\n");
909				exit (-1);
910			}
911#if 1
912		} else if (strcasecmp ("reset", argv[i]) == 0) {
913			ioctl (fd, SERIAL_RESET, 0);
914		} else if (strcasecmp ("hwreset", argv[i]) == 0) {
915			ioctl (fd, SERIAL_HARDRESET, 0);
916#endif
917		} else if (strncasecmp ("cablen=", argv[i], 7) == 0) {
918			loop = (strcasecmp ("on", argv[i] + 7) == 0);
919			ioctl (fd, SERIAL_SETCABLEN, &cablen);
920		}
921	}
922}
923
924static void
925get_mask (void)
926{
927#ifdef __linux__
928	int fd;
929
930	fd = open ("/dev/serial/ctl0", 0);
931	if (fd < 0) {
932		perror ("/dev/serial/ctl0");
933		exit (-1);
934	}
935	if (ioctl (fd, SERIAL_GETREGISTERED, &mask) < 0) {
936		perror ("getting list of channels");
937		exit (-1);
938	}
939	close (fd);
940#else
941	int fd, fd1, fd2, fd3, i;
942	char buf [80];
943
944	for (i=0, fd=-1; i<12 && fd<0; i++) {
945		sprintf (buf, "/dev/cx%d", i*4);
946		fd = open (buf, 0);
947	}
948
949	for (i=0, fd1=-1; i<3 && fd1<0; i++) {
950		sprintf (buf, "/dev/ct%d", i*2);
951		fd1 = open (buf, 0);
952	}
953
954	for (i=0, fd2=-1; i<3 && fd2<0; i++) {
955		sprintf (buf, "/dev/cp%d", i*4);
956		fd2 = open (buf, 0);
957	}
958
959	/* Try only one */
960	for (i=0, fd3=-1; i<1 && fd3<0; i++) {
961		sprintf (buf, "/dev/ce%d", i*4);
962		fd3 = open (buf, 0);
963	}
964
965	if ((fd < 0) && (fd1 < 0) && (fd2 < 0) && (fd3 < 0)) {
966		fprintf (stderr, "No Cronyx adapters installed\n");
967		exit (-1);
968	}
969
970	if (fd >= 0) {
971		if (ioctl (fd, SERIAL_GETREGISTERED, &mask) < 0) {
972			perror ("getting list of channels");
973			exit (-1);
974		}
975		close (fd);
976	}
977
978	if (fd1 >= 0) {
979		if (ioctl (fd1, SERIAL_GETREGISTERED, (mask+16)) < 0) {
980			perror ("getting list of channels");
981			exit (-1);
982		}
983		close (fd1);
984	}
985
986	if (fd2 >= 0) {
987		if (ioctl (fd2, SERIAL_GETREGISTERED, (mask+32)) < 0) {
988			perror ("getting list of channels");
989			exit (-1);
990		}
991		close (fd2);
992	}
993
994	if (fd3 >= 0) {
995		if (ioctl (fd3, SERIAL_GETREGISTERED, (mask+48)) < 0) {
996			perror ("getting list of channels");
997			exit (-1);
998		}
999		close (fd3);
1000	}
1001#endif
1002}
1003
1004static int
1005open_chan_ctl (int num)
1006{
1007	char device [80];
1008	int fd;
1009
1010#ifdef __linux__
1011	sprintf (device, "/dev/serial/ctl%d", num);
1012#else
1013	switch (adapter_type) {
1014	case 0:
1015		sprintf (device, "/dev/cx%d", num);
1016		break;
1017	case 1:
1018		sprintf (device, "/dev/ct%d", num);
1019		break;
1020	case 2:
1021		sprintf (device, "/dev/cp%d", num);
1022		break;
1023	case 3:
1024		sprintf (device, "/dev/ce%d", num);
1025		break;
1026	}
1027#endif
1028	fd = open (device, 0);
1029	if (fd < 0) {
1030		if (errno == ENODEV)
1031			fprintf (stderr, "chan%d: not configured\n", num);
1032		else
1033			perror (device);
1034		exit (-1);
1035	}
1036#ifdef __linux__
1037	if (ioctl (fd, SERIAL_GETNAME, &chan_name) < 0)
1038		sprintf (chan_name, "chan%d", num);
1039#else
1040	switch (adapter_type) {
1041	case 0: sprintf (chan_name, "cx%d", num); break;
1042	case 1: sprintf (chan_name, "ct%d", num); break;
1043	case 2: sprintf (chan_name, "cp%d", num); break;
1044	case 3: sprintf (chan_name, "ce%d", num); break;
1045	}
1046#endif
1047	return fd;
1048}
1049
1050int
1051main (int argc, char **argv)
1052{
1053	char *p;
1054	int fd, need_header, chan_num;
1055
1056	if (argc > 1 && strcmp(argv[1], "help") == 0)
1057		usage();
1058
1059	for (;;) {
1060		switch (getopt (argc, argv, "mseftucviax")) {
1061		case -1:
1062			break;
1063		case 'a':
1064			++aflag;
1065			continue;
1066		case 'm':
1067			++mflag;
1068			continue;
1069		case 's':
1070			++sflag;
1071			continue;
1072		case 'e':
1073			++eflag;
1074			continue;
1075		case 'f':
1076			++eflag;
1077			++fflag;
1078			continue;
1079		case 't':
1080			++tflag;
1081			continue;
1082		case 'u':
1083			++tflag;
1084			++uflag;
1085			continue;
1086		case 'c':
1087			++cflag;
1088			continue;
1089		case 'v':
1090			++vflag;
1091			continue;
1092		case 'i':
1093			++iflag;
1094			continue;
1095		case 'x':
1096			++xflag;
1097			continue;
1098		default:
1099			usage();
1100		}
1101		break;
1102	}
1103	argc -= optind;
1104	argv += optind;
1105
1106	if (argc <= 0) {
1107		get_mask ();
1108		need_header = 1;
1109		adapter_type = 0;
1110#ifndef __linux__
1111		for (; adapter_type < 4; ++adapter_type)
1112#endif
1113		{
1114		for (chan_num=0; chan_num<MAXCHAN; ++chan_num)
1115			if (mask[adapter_type*16+chan_num/8] & 1 << (chan_num & 7)) {
1116				fd = open_chan_ctl (chan_num);
1117				if (vflag) {
1118#ifdef __linux__
1119				char buf[256];
1120				if (ioctl (fd, SERIAL_GETVERSIONSTRING, &buf) >= 0) {
1121					printf ("Version: %s\n", buf);
1122					close (fd);
1123					return (0);
1124				}
1125#endif
1126				}
1127				if (iflag) {
1128					print_chan (fd);
1129					print_ifconfig (fd);
1130				} else if (sflag||xflag)
1131					print_stats (fd, need_header);
1132				else if (mflag)
1133					print_modems (fd, need_header);
1134				else if (eflag)
1135					print_e1_stats (fd, need_header);
1136				else if (tflag)
1137					print_e3_stats (fd, need_header);
1138				else if (cflag)
1139					clear_stats (fd);
1140				else
1141					print_chan (fd);
1142				close (fd);
1143				need_header = 0;
1144			}
1145		}
1146		return (0);
1147	}
1148
1149	p = argv[0] + strlen (argv[0]);
1150	while (p > argv[0] && p[-1] >= '0' && p[-1] <= '9')
1151		--p;
1152	chan_num = strtol (p, 0, 10);
1153#ifndef __linux__
1154	if (strncasecmp ("cx", argv[0], 2)==0)
1155		adapter_type = 0;
1156	else if (strncasecmp ("ct", argv[0], 2)==0)
1157		adapter_type = 1;
1158	else if (strncasecmp ("cp", argv[0], 2)==0)
1159		adapter_type = 2;
1160	else if (strncasecmp ("ce", argv[0], 2)==0)
1161		adapter_type = 3;
1162	else {
1163		fprintf (stderr, "Wrong channel name\n");
1164		exit (-1);
1165	}
1166#endif
1167	argc--;
1168	argv++;
1169
1170	fd = open_chan_ctl (chan_num);
1171	if (vflag) {
1172#ifdef __linux__
1173		char buf[256];
1174		if (ioctl (fd, SERIAL_GETVERSIONSTRING, &buf) >= 0)
1175			printf ("Version: %s\n", buf);
1176#endif
1177	}
1178	if (iflag) {
1179		print_chan (fd);
1180		print_ifconfig (fd);
1181		close (fd);
1182		return (0);
1183	}
1184	if (sflag||xflag) {
1185		print_stats (fd, 1);
1186		close (fd);
1187		return (0);
1188	}
1189	if (mflag) {
1190		print_modems (fd, 1);
1191		close (fd);
1192		return (0);
1193	}
1194	if (eflag) {
1195		print_e1_stats (fd, 1);
1196		close (fd);
1197		return (0);
1198	}
1199	if (tflag) {
1200		print_e3_stats (fd, 1);
1201		close (fd);
1202		return (0);
1203	}
1204	if (cflag) {
1205		clear_stats (fd);
1206		close (fd);
1207		return (0);
1208	}
1209	if (argc > 0)
1210		setup_chan (fd, argc, argv);
1211	else
1212		print_chan (fd);
1213	close (fd);
1214	return (0);
1215}
1216