xref: /original-bsd/usr.bin/netstat/iso.c (revision c3e32dec)
1 /*
2  * Copyright (c) 1983, 1988, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char sccsid[] = "@(#)iso.c	8.1 (Berkeley) 06/06/93";
10 #endif /* not lint */
11 
12 /*
13  * $Header: iso.c,v 1.5 92/06/04 00:36:32 leres Exp $
14  * $Source: /usr/src/usr.bin/netstat/RCS/iso.c,v $
15  */
16 /*******************************************************************************
17 	          Copyright IBM Corporation 1987
18 
19                       All Rights Reserved
20 
21 Permission to use, copy, modify, and distribute this software and its
22 documentation for any purpose and without fee is hereby granted,
23 provided that the above copyright notice appear in all copies and that
24 both that copyright notice and this permission notice appear in
25 supporting documentation, and that the name of IBM not be
26 used in advertising or publicity pertaining to distribution of the
27 software without specific, written prior permission.
28 
29 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
30 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
31 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
32 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
33 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
34 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
35 SOFTWARE.
36 
37 *******************************************************************************/
38 
39 /*
40  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
41  */
42 
43 #include <sys/param.h>
44 #include <sys/mbuf.h>
45 #include <sys/time.h>
46 #include <sys/domain.h>
47 #include <sys/protosw.h>
48 #include <sys/socket.h>
49 #include <sys/socketvar.h>
50 #include <errno.h>
51 #include <net/if.h>
52 #include <net/route.h>
53 #include <netinet/in.h>
54 #include <netinet/in_systm.h>
55 #include <netinet/ip.h>
56 #include <netinet/in_pcb.h>
57 #include <netinet/ip_var.h>
58 #include <netiso/iso.h>
59 #include <netiso/iso_errno.h>
60 #include <netiso/clnp.h>
61 #include <netiso/esis.h>
62 #include <netiso/clnp_stat.h>
63 #include <netiso/argo_debug.h>
64 #undef satosiso
65 #include <netiso/tp_param.h>
66 #include <netiso/tp_states.h>
67 #include <netiso/tp_pcb.h>
68 #include <netiso/tp_stat.h>
69 #include <netiso/iso_pcb.h>
70 #include <netiso/cltp_var.h>
71 #include <netiso/cons.h>
72 #ifdef IncStat
73 #undef IncStat
74 #endif
75 #include <netiso/cons_pcb.h>
76 #include <arpa/inet.h>
77 #include <netdb.h>
78 #include <string.h>
79 #include <stdio.h>
80 #include <stdlib.h>
81 #include "netstat.h"
82 
83 static void tprintstat __P((struct tp_stat *, int));
84 static void isonetprint __P((struct sockaddr_iso *, int));
85 static void hexprint __P((int, char *, char *));
86 extern void inetprint __P((struct in_addr *, int, char *));
87 
88 /*
89  *	Dump esis stats
90  */
91 void
92 esis_stats(off, name)
93 	u_long	off;
94 	char	*name;
95 {
96 	struct esis_stat esis_stat;
97 
98 	if (off == 0 ||
99 	    kread(off, (char *)&esis_stat, sizeof (struct esis_stat)))
100 		return;
101 	printf("%s:\n", name);
102 	printf("\t%d esh sent, %d esh received\n", esis_stat.es_eshsent,
103 		esis_stat.es_eshrcvd);
104 	printf("\t%d ish sent, %d ish received\n", esis_stat.es_ishsent,
105 		esis_stat.es_ishrcvd);
106 	printf("\t%d rd sent, %d rd received\n", esis_stat.es_rdsent,
107 		esis_stat.es_rdrcvd);
108 	printf("\t%d pdus not sent due to insufficient memory\n",
109 		esis_stat.es_nomem);
110 	printf("\t%d pdus received with bad checksum\n", esis_stat.es_badcsum);
111 	printf("\t%d pdus received with bad version number\n",
112 		esis_stat.es_badvers);
113 	printf("\t%d pdus received with bad type field\n", esis_stat.es_badtype);
114 	printf("\t%d short pdus received\n", esis_stat.es_toosmall);
115 }
116 
117 /*
118  * Dump clnp statistics structure.
119  */
120 void
121 clnp_stats(off, name)
122 	u_long off;
123 	char *name;
124 {
125 	struct clnp_stat clnp_stat;
126 
127 	if (off == 0 ||
128 	    kread(off, (char *)&clnp_stat, sizeof (clnp_stat)))
129 		return;
130 
131 	printf("%s:\n\t%d total packets sent\n", name, clnp_stat.cns_sent);
132 	printf("\t%d total fragments sent\n", clnp_stat.cns_fragments);
133 	printf("\t%d total packets received\n", clnp_stat.cns_total);
134 	printf("\t%d with fixed part of header too small\n",
135 		clnp_stat.cns_toosmall);
136 	printf("\t%d with header length not reasonable\n", clnp_stat.cns_badhlen);
137 	printf("\t%d incorrect checksum%s\n",
138 		clnp_stat.cns_badcsum, plural(clnp_stat.cns_badcsum));
139 	printf("\t%d with unreasonable address lengths\n", clnp_stat.cns_badaddr);
140 	printf("\t%d with forgotten segmentation information\n",
141 		clnp_stat.cns_noseg);
142 	printf("\t%d with an incorrect protocol identifier\n", clnp_stat.cns_noproto);
143 	printf("\t%d with an incorrect version\n", clnp_stat.cns_badvers);
144 	printf("\t%d dropped because the ttl has expired\n",
145 		clnp_stat.cns_ttlexpired);
146 	printf("\t%d clnp cache misses\n", clnp_stat.cns_cachemiss);
147 	printf("\t%d clnp congestion experience bits set\n",
148 		clnp_stat.cns_congest_set);
149 	printf("\t%d clnp congestion experience bits received\n",
150 		clnp_stat.cns_congest_rcvd);
151 }
152 /*
153  * Dump CLTP statistics structure.
154  */
155 void
156 cltp_stats(off, name)
157 	u_long off;
158 	char *name;
159 {
160 	struct cltpstat cltpstat;
161 
162 	if (off == 0 ||
163 	    kread(off, (char *)&cltpstat, sizeof (cltpstat)))
164 		return;
165 	printf("%s:\n\t%u incomplete header%s\n", name,
166 		cltpstat.cltps_hdrops, plural(cltpstat.cltps_hdrops));
167 	printf("\t%u bad data length field%s\n",
168 		cltpstat.cltps_badlen, plural(cltpstat.cltps_badlen));
169 	printf("\t%u bad checksum%s\n",
170 		cltpstat.cltps_badsum, plural(cltpstat.cltps_badsum));
171 }
172 
173 struct	tp_pcb tpcb;
174 struct	isopcb isopcb;
175 struct	socket sockb;
176 union	{
177 	struct sockaddr_iso	siso;
178 	char	data[128];
179 } laddr, faddr;
180 #define kget(o, p) \
181 	(kread((u_long)(o), (char *)&p, sizeof (p)))
182 
183 static	int first = 1;
184 
185 /*
186  * Print a summary of connections related to an Internet
187  * protocol.  For TP, also give state of connection.
188  * Listening processes (aflag) are suppressed unless the
189  * -a (all) flag is specified.
190  */
191 void
192 iso_protopr(off, name)
193 	u_long off;
194 	char *name;
195 {
196 	struct isopcb cb;
197 	register struct isopcb *prev, *next;
198 
199 	if (off == 0) {
200 		printf("%s control block: symbol not in namelist\n", name);
201 		return;
202 	}
203 	if (strcmp(name, "tp") == 0) {
204 		tp_protopr(off, name);
205 		return;
206 	}
207 	if (kread(off, (char *)&cb, sizeof(cb)))
208 		return;
209 	isopcb = cb;
210 	prev = (struct isopcb *)off;
211 	if (isopcb.isop_next == (struct isopcb *)off)
212 		return;
213 	while (isopcb.isop_next != (struct isopcb *)off) {
214 		next = isopcb.isop_next;
215 		kget(next, isopcb);
216 		if (isopcb.isop_prev != prev) {
217 			printf("prev 0x%x next 0x%x isop_prev 0x%x isop_next 0x%x???\n",
218 				prev, next, isopcb.isop_prev, isopcb.isop_next);
219 			break;
220 		}
221 		kget(isopcb.isop_socket, sockb);
222 		iso_protopr1((u_long)next, 0);
223 		putchar('\n');
224 		prev = next;
225 	}
226 }
227 
228 void
229 iso_protopr1(kern_addr, istp)
230 	u_long kern_addr;
231 	int istp;
232 {
233 	if (first) {
234 		printf("Active ISO net connections");
235 		if (aflag)
236 			printf(" (including servers)");
237 		putchar('\n');
238 		if (Aflag)
239 			printf("%-8.8s ", "PCB");
240 		printf(Aflag ?
241 			"%-5.5s %-6.6s %-6.6s  %-18.18s %-18.18s %s\n" :
242 			"%-5.5s %-6.6s %-6.6s  %-22.22s %-22.22s %s\n",
243 			"Proto", "Recv-Q", "Send-Q",
244 			"Local Address", "Foreign Address", "(state)");
245 		first = 0;
246 	}
247 	if (Aflag)
248 			printf("%8x ",
249 					(sockb.so_pcb ? (void *)sockb.so_pcb : (void *)kern_addr));
250 	printf("%-5.5s %6d %6d ", "tp", sockb.so_rcv.sb_cc, sockb.so_snd.sb_cc);
251 	if (istp && tpcb.tp_lsuffixlen) {
252 			hexprint(tpcb.tp_lsuffixlen, tpcb.tp_lsuffix, "()");
253 			printf("\t");
254 	} else if (isopcb.isop_laddr == 0)
255 			printf("*.*\t");
256 	else {
257 			if ((char *)isopcb.isop_laddr == ((char *)kern_addr) +
258 					_offsetof(struct isopcb, isop_sladdr))
259 					laddr.siso = isopcb.isop_sladdr;
260 			else
261 					kget(isopcb.isop_laddr, laddr);
262 			isonetprint((struct sockaddr_iso *)&laddr, 1);
263 	}
264 	if (istp && tpcb.tp_fsuffixlen) {
265 			hexprint(tpcb.tp_fsuffixlen, tpcb.tp_fsuffix, "()");
266 			printf("\t");
267 	} else if (isopcb.isop_faddr == 0)
268 		printf("*.*\t");
269 	else {
270 		if ((char *)isopcb.isop_faddr == ((char *)kern_addr) +
271 			_offsetof(struct isopcb, isop_sfaddr))
272 			faddr.siso = isopcb.isop_sfaddr;
273 		else
274 			kget(isopcb.isop_faddr, faddr);
275 		isonetprint((struct sockaddr_iso *)&faddr, 0);
276 	}
277 }
278 
279 void
280 tp_protopr(off, name)
281 	u_long off;
282 	char *name;
283 {
284 	extern char *tp_sstring[];
285 	struct tp_ref *tpr, *tpr_base;
286 	struct tp_refinfo tpkerninfo;
287 	int size;
288 
289 	kget(off, tpkerninfo);
290 	size = tpkerninfo.tpr_size * sizeof (*tpr);
291 	tpr_base = (struct tp_ref *)malloc(size);
292 	if (tpr_base == 0)
293 		return;
294 	kread((u_long)(tpkerninfo.tpr_base), (char *)tpr_base, size);
295 	for (tpr = tpr_base; tpr < tpr_base + tpkerninfo.tpr_size; tpr++) {
296 		if (tpr->tpr_pcb == 0)
297 			continue;
298 		kget(tpr->tpr_pcb, tpcb);
299 		if (tpcb.tp_state == ST_ERROR)
300 			printf("undefined tpcb state: 0x%x\n", tpr->tpr_pcb);
301 		if (!aflag &&
302 			(tpcb.tp_state == TP_LISTENING ||
303 			 tpcb.tp_state == TP_CLOSED ||
304 			 tpcb.tp_state == TP_REFWAIT)) {
305 			continue;
306 		}
307 		kget(tpcb.tp_sock, sockb);
308 		if (tpcb.tp_npcb) switch(tpcb.tp_netservice) {
309 			case IN_CLNS:
310 				tp_inproto((u_long)tpkerninfo.tpr_base);
311 				break;
312 			default:
313 				kget(tpcb.tp_npcb, isopcb);
314 				iso_protopr1((u_long)tpcb.tp_npcb, 1);
315 				break;
316 		}
317 		if (tpcb.tp_state >= tp_NSTATES)
318 			printf(" %d", tpcb.tp_state);
319 		else
320 			printf(" %-12.12s", tp_sstring[tpcb.tp_state]);
321 		putchar('\n');
322 	}
323 }
324 
325 void
326 tp_inproto(pcb)
327 	u_long pcb;
328 {
329 	struct inpcb inpcb;
330 	kget(tpcb.tp_npcb, inpcb);
331 	if (!aflag && inet_lnaof(inpcb.inp_laddr) == INADDR_ANY)
332 		return;
333 	if (Aflag)
334 		printf("%8x ", pcb);
335 	printf("%-5.5s %6d %6d ", "tpip",
336 	    sockb.so_rcv.sb_cc, sockb.so_snd.sb_cc);
337 	inetprint(&inpcb.inp_laddr, inpcb.inp_lport, "tp");
338 	inetprint(&inpcb.inp_faddr, inpcb.inp_fport, "tp");
339 }
340 
341 /*
342  * Pretty print an iso address (net address + port).
343  * If the nflag was specified, use numbers instead of names.
344  */
345 
346 #ifdef notdef
347 char *
348 isonetname(iso)
349 	register struct iso_addr *iso;
350 {
351 	struct sockaddr_iso sa;
352 	struct iso_hostent *ihe = 0;
353 	struct iso_hostent *iso_gethostentrybyaddr();
354 	struct iso_hostent *iso_getserventrybytsel();
355 	struct iso_hostent Ihe;
356 	static char line[80];
357 
358 	bzero(line, sizeof(line));
359 	if( iso->isoa_afi ) {
360 		sa.siso_family = AF_ISO;
361 		sa.siso_addr = *iso;
362 		sa.siso_tsuffix = 0;
363 
364 		if (!nflag )
365 			ihe = iso_gethostentrybyaddr( &sa, 0, 0 );
366 		if( ihe ) {
367 			Ihe = *ihe;
368 			ihe = &Ihe;
369 			sprintf(line, "%s", ihe->isoh_hname);
370 		} else {
371 			sprintf(line, "%s", iso_ntoa(iso));
372 		}
373 	} else {
374 		sprintf(line, "*");
375 	}
376 	return line;
377 }
378 
379 static void
380 isonetprint(iso, sufx, sufxlen, islocal)
381 	register struct iso_addr *iso;
382 	char *sufx;
383 	u_short	sufxlen;
384 	int islocal;
385 {
386 	struct iso_hostent *iso_getserventrybytsel(), *ihe;
387 	struct iso_hostent Ihe;
388 	char *line, *cp;
389 	int Alen = Aflag?18:22;
390 
391 	line =  isonetname(iso);
392 	cp = index(line, '\0');
393 	ihe = (struct iso_hostent *)0;
394 
395 	if( islocal )
396 		islocal = 20;
397 	else
398 		islocal = 22 + Alen;
399 
400 	if(Aflag)
401 		islocal += 10 ;
402 
403 	if(!nflag) {
404 		if( (cp -line)>10 ) {
405 			cp = line+10;
406 			bzero(cp, sizeof(line)-10);
407 		}
408 	}
409 
410 	*cp++ = '.';
411 	if(sufxlen) {
412 		if( !Aflag && !nflag && (ihe=iso_getserventrybytsel(sufx, sufxlen))) {
413 			Ihe = *ihe;
414 			ihe = &Ihe;
415 		}
416 		if( ihe && (strlen(ihe->isoh_aname)>0) ) {
417 			sprintf(cp, "%s", ihe->isoh_aname);
418 		} else  {
419 			iso_sprinttsel(cp, sufx, sufxlen);
420 		}
421 	} else
422 		sprintf(cp, "*");
423 	/*
424 	fprintf(stdout, Aflag?" %-18.18s":" %-22.22s", line);
425 	*/
426 
427 	if( strlen(line) > Alen ) {
428 		fprintf(stdout, " %s", line);
429 		fprintf(stdout, "\n %*.s", islocal+Alen," ");
430 	} else {
431 		fprintf(stdout, " %-*.*s", Alen, Alen,line);
432 	}
433 }
434 #endif
435 
436 #ifdef notdef
437 static void
438 x25_protopr(off, name)
439 	u_long off;
440 	char *name;
441 {
442 	static char *xpcb_states[] = {
443 		"CLOSED",
444 		"LISTENING",
445 		"CLOSING",
446 		"CONNECTING",
447 		"ACKWAIT",
448 		"OPEN",
449 	};
450 	register struct isopcb *prev, *next;
451 	struct x25_pcb xpcb;
452 
453 	if (off == 0) {
454 		printf("%s control block: symbol not in namelist\n", name);
455 		return;
456 	}
457 	kread(off, &xpcb, sizeof (struct x25_pcb));
458 	prev = (struct isopcb *)off;
459 	if (xpcb.x_next == (struct isopcb *)off)
460 		return;
461 	while (xpcb.x_next != (struct isopcb *)off) {
462 		next = isopcb.isop_next;
463 		kread((u_long)next, &xpcb, sizeof (struct x25_pcb));
464 		if (xpcb.x_prev != prev) {
465 			printf("???\n");
466 			break;
467 		}
468 		kread((u_long)xpcb.x_socket, &sockb, sizeof (sockb));
469 
470 		if (!aflag &&
471 			xpcb.x_state == LISTENING ||
472 			xpcb.x_state == TP_CLOSED ) {
473 			prev = next;
474 			continue;
475 		}
476 		if (first) {
477 			printf("Active X25 net connections");
478 			if (aflag)
479 				printf(" (including servers)");
480 			putchar('\n');
481 			if (Aflag)
482 				printf("%-8.8s ", "PCB");
483 			printf(Aflag ?
484 				"%-5.5s %-6.6s %-6.6s  %-18.18s %-18.18s %s\n" :
485 				"%-5.5s %-6.6s %-6.6s  %-22.22s %-22.22s %s\n",
486 				"Proto", "Recv-Q", "Send-Q",
487 				"Local Address", "Foreign Address", "(state)");
488 			first = 0;
489 		}
490 		printf("%-5.5s %6d %6d ", name, sockb.so_rcv.sb_cc,
491 			sockb.so_snd.sb_cc);
492 		isonetprint(&xpcb.x_laddr.siso_addr, &xpcb.x_lport,
493 			sizeof(xpcb.x_lport), 1);
494 		isonetprint(&xpcb.x_faddr.siso_addr, &xpcb.x_fport,
495 			sizeof(xpcb.x_lport), 0);
496 		if (xpcb.x_state < 0 || xpcb.x_state >= x25_NSTATES)
497 			printf(" 0x0x0x0x0x0x0x0x0x%x", xpcb.x_state);
498 		else
499 			printf(" %-12.12s", xpcb_states[xpcb.x_state]);
500 		putchar('\n');
501 		prev = next;
502 	}
503 }
504 #endif
505 
506 struct	tp_stat tp_stat;
507 
508 void
509 tp_stats(off, name)
510 	caddr_t off, name;
511 {
512 	if (off == 0) {
513 		printf("TP not configured\n\n");
514 		return;
515 	}
516 	printf("%s:\n", name);
517 	kget(off, tp_stat);
518 	tprintstat(&tp_stat, 8);
519 }
520 
521 #define OUT stdout
522 
523 static void
524 tprintstat(s, indent)
525 	register struct tp_stat *s;
526 	int indent;
527 {
528 	fprintf(OUT,
529 		"%*sReceiving:\n",indent," ");
530 	fprintf(OUT,
531 		"\t%*s%d variable parameter%s ignored\n", indent," ",
532 		s->ts_param_ignored ,plural(s->ts_param_ignored));
533 	fprintf(OUT,
534 		"\t%*s%d invalid parameter code%s\n", indent, " ",
535 		s->ts_inv_pcode ,plural(s->ts_inv_pcode));
536 	fprintf(OUT,
537 		"\t%*s%d invalid parameter value%s\n", indent, " ",
538 		s->ts_inv_pval ,plural(s->ts_inv_pval));
539 	fprintf(OUT,
540 		"\t%*s%d invalid dutype%s\n", indent, " ",
541 		s->ts_inv_dutype ,plural(s->ts_inv_dutype));
542 	fprintf(OUT,
543 		"\t%*s%d negotiation failure%s\n", indent, " ",
544 		s->ts_negotfailed ,plural(s->ts_negotfailed));
545 	fprintf(OUT,
546 		"\t%*s%d invalid destination reference%s\n", indent, " ",
547 		s->ts_inv_dref ,plural(s->ts_inv_dref));
548 	fprintf(OUT,
549 		"\t%*s%d invalid suffix parameter%s\n", indent, " ",
550 		s->ts_inv_sufx ,plural(s->ts_inv_sufx));
551 	fprintf(OUT,
552 		"\t%*s%d invalid length\n",indent, " ", s->ts_inv_length);
553 	fprintf(OUT,
554 		"\t%*s%d invalid checksum%s\n", indent, " ",
555 		s->ts_bad_csum ,plural(s->ts_bad_csum));
556 	fprintf(OUT,
557 		"\t%*s%d DT%s out of order\n", indent, " ",
558 		s->ts_dt_ooo ,plural(s->ts_dt_ooo));
559 	fprintf(OUT,
560 		"\t%*s%d DT%s not in window\n", indent, " ",
561 		s->ts_dt_niw ,plural(s->ts_dt_niw));
562 	fprintf(OUT,
563 		"\t%*s%d duplicate DT%s\n", indent, " ",
564 		s->ts_dt_dup ,plural(s->ts_dt_dup));
565 	fprintf(OUT,
566 			"\t%*s%d XPD%s not in window\n", indent, " ",
567 			s->ts_xpd_niw ,plural(s->ts_xpd_niw));
568 		fprintf(OUT,
569 			"\t%*s%d XPD%s w/o credit to stash\n", indent, " ",
570 		s->ts_xpd_dup ,plural(s->ts_xpd_dup));
571 	fprintf(OUT,
572 		"\t%*s%d time%s local credit reneged\n", indent, " ",
573 		s->ts_lcdt_reduced ,plural(s->ts_lcdt_reduced));
574 	fprintf(OUT,
575 		"\t%*s%d concatenated TPDU%s\n", indent, " ",
576 		s->ts_concat_rcvd ,plural(s->ts_concat_rcvd));
577 	fprintf(OUT,
578 		"%*sSending:\n", indent, " ");
579 	fprintf(OUT,
580 		"\t%*s%d XPD mark%s discarded\n", indent, " ",
581 		s->ts_xpdmark_del ,plural(s->ts_xpdmark_del));
582 	fprintf(OUT,
583 		"\t%*sXPD stopped data flow %d time%s\n", indent, " ",
584 		s->ts_xpd_intheway ,plural(s->ts_xpd_intheway));
585 	fprintf(OUT,
586 		"\t%*s%d time%s foreign window closed\n", indent, " ",
587 		s->ts_zfcdt ,plural(s->ts_zfcdt));
588 	fprintf(OUT,
589 		"%*sMiscellaneous:\n", indent, " ");
590 	fprintf(OUT,
591 		"\t%*s%d small mbuf%s\n", indent, " ",
592 		s->ts_mb_small ,plural(s->ts_mb_small));
593 	fprintf(OUT,
594 		"\t%*s%d cluster%s\n", indent, " ",
595 		s->ts_mb_cluster, plural(s->ts_mb_cluster));
596 	fprintf(OUT,
597 		"\t%*s%d source quench \n",indent, " ",
598 		s->ts_quench);
599 	fprintf(OUT,
600 		"\t%*s%d dec bit%s\n", indent, " ",
601 		s->ts_rcvdecbit, plural(s->ts_rcvdecbit));
602 	fprintf(OUT,
603 		"\t%*sM:L ( M mbuf chains of length L)\n", indent, " ");
604 	{
605 		register int j;
606 
607 		fprintf(OUT, "\t%*s%d: over 16\n", indent, " ",
608 		s->ts_mb_len_distr[0]);
609 		for( j=1; j<=8; j++) {
610 			fprintf(OUT,
611 				"\t%*s%d: %d\t\t%d: %d\n", indent, " ",
612 				s->ts_mb_len_distr[j],j,
613 				s->ts_mb_len_distr[j<<1],j<<1
614 				);
615 		}
616 	}
617 	fprintf(OUT,
618 		"\t%*s%d EOT rcvd\n",  indent, " ", s->ts_eot_input);
619 	fprintf(OUT,
620 		"\t%*s%d EOT sent\n",  indent, " ", s->ts_EOT_sent);
621 	fprintf(OUT,
622 		"\t%*s%d EOT indication%s\n",  indent, " ",
623 		s->ts_eot_user ,plural(s->ts_eot_user));
624 
625 	fprintf(OUT,
626 		"%*sConnections:\n", indent, " ");
627 	fprintf(OUT,
628 		"\t%*s%d connection%s used extended format\n",  indent, " ",
629 		s->ts_xtd_fmt ,plural(s->ts_xtd_fmt));
630 	fprintf(OUT,
631 		"\t%*s%d connection%s allowed transport expedited data\n",  indent, " ",
632 		s->ts_use_txpd ,plural(s->ts_use_txpd));
633 	fprintf(OUT,
634 		"\t%*s%d connection%s turned off checksumming\n",  indent, " ",
635 		s->ts_csum_off ,plural(s->ts_csum_off));
636 	fprintf(OUT,
637 		"\t%*s%d connection%s dropped due to retrans limit\n",  indent, " ",
638 		s->ts_conn_gaveup ,plural(s->ts_conn_gaveup));
639 	fprintf(OUT,
640 		"\t%*s%d tp 4 connection%s\n",  indent, " ",
641 		s->ts_tp4_conn ,plural(s->ts_tp4_conn));
642 	fprintf(OUT,
643 		"\t%*s%d tp 0 connection%s\n",  indent, " ",
644 		s->ts_tp0_conn ,plural(s->ts_tp0_conn));
645     {
646 		register int j;
647 		static char *name[]= {
648 			"~LOCAL, PDN",
649 			"~LOCAL,~PDN",
650 			" LOCAL,~PDN",
651 			" LOCAL, PDN"
652 		};
653 
654 		fprintf(OUT,
655 			"\n%*sRound trip times, listed in ticks:\n", indent, " ");
656 		fprintf(OUT,
657 			"\t%*s%11.11s  %12.12s | %12.12s | %s\n", indent, " ",
658 				"Category",
659 				"Smoothed avg", "Deviation", "Deviation/Avg");
660 		for (j = 0; j <= 3; j++) {
661 			fprintf(OUT,
662 				"\t%*s%11.11s: %-11d | %-11d | %-11d | %-11d\n", indent, " ",
663 				name[j],
664 				s->ts_rtt[j],
665 				s->ts_rtt[j],
666 				s->ts_rtv[j],
667 				s->ts_rtv[j]);
668 		}
669 	}
670 	fprintf(OUT,
671 "\n%*sTpdus RECVD [%d valid, %3.6f %% of total (%d); %d dropped]\n",indent," ",
672 		s->ts_tpdu_rcvd ,
673 		((s->ts_pkt_rcvd > 0) ?
674 			((100 * (float)s->ts_tpdu_rcvd)/(float)s->ts_pkt_rcvd)
675 			: 0),
676 		s->ts_pkt_rcvd,
677 		s->ts_recv_drop );
678 
679 	fprintf(OUT,
680 		"\t%*sDT  %6d   AK  %6d   DR  %4d   CR  %4d \n", indent, " ",
681 		s->ts_DT_rcvd, s->ts_AK_rcvd, s->ts_DR_rcvd, s->ts_CR_rcvd);
682 	fprintf(OUT,
683 		"\t%*sXPD %6d   XAK %6d   DC  %4d   CC  %4d   ER  %4d\n",  indent, " ",
684 		s->ts_XPD_rcvd, s->ts_XAK_rcvd, s->ts_DC_rcvd, s->ts_CC_rcvd,
685 		s->ts_ER_rcvd);
686 	fprintf(OUT,
687 		"\n%*sTpdus SENT [%d total, %d dropped]\n",  indent, " ",
688 		s->ts_tpdu_sent, s->ts_send_drop);
689 
690 	fprintf(OUT,
691 		"\t%*sDT  %6d   AK  %6d   DR  %4d   CR  %4d \n", indent, " ",
692 		s->ts_DT_sent, s->ts_AK_sent, s->ts_DR_sent, s->ts_CR_sent);
693 	fprintf(OUT,
694 		"\t%*sXPD %6d   XAK %6d   DC  %4d   CC  %4d   ER  %4d\n",  indent, " ",
695 		s->ts_XPD_sent, s->ts_XAK_sent, s->ts_DC_sent, s->ts_CC_sent,
696 		s->ts_ER_sent);
697 
698 	fprintf(OUT,
699 		"\n%*sRetransmissions:\n", indent, " ");
700 #define PERCENT(X,Y) (((Y)>0)?((100 *(float)(X)) / (float) (Y)):0)
701 
702 	fprintf(OUT,
703 	"\t%*sCR  %6d   CC  %6d   DR  %6d \n", indent, " ",
704 		s->ts_retrans_cr, s->ts_retrans_cc, s->ts_retrans_dr);
705 	fprintf(OUT,
706 	"\t%*sDT  %6d (%5.2f%%)\n", indent, " ",
707 		s->ts_retrans_dt,
708 		PERCENT(s->ts_retrans_dt, s->ts_DT_sent));
709 	fprintf(OUT,
710 	"\t%*sXPD %6d (%5.2f%%)\n",  indent, " ",
711 		s->ts_retrans_xpd,
712 		PERCENT(s->ts_retrans_xpd, s->ts_XPD_sent));
713 
714 
715 	fprintf(OUT,
716 		"\n%*sE Timers: [%6d ticks]\n", indent, " ", s->ts_Eticks);
717 	fprintf(OUT,
718 		"%*s%6d timer%s set \t%6d timer%s expired \t%6d timer%s cancelled\n",indent, " ",
719 		s->ts_Eset ,plural(s->ts_Eset),
720 		s->ts_Eexpired ,plural(s->ts_Eexpired),
721 		s->ts_Ecan_act ,plural(s->ts_Ecan_act));
722 
723 	fprintf(OUT,
724 		"\n%*sC Timers: [%6d ticks]\n",  indent, " ",s->ts_Cticks);
725 	fprintf(OUT,
726 	"%*s%6d timer%s set \t%6d timer%s expired \t%6d timer%s cancelled\n",
727 		indent, " ",
728 		s->ts_Cset ,plural(s->ts_Cset),
729 		s->ts_Cexpired ,plural(s->ts_Cexpired),
730 		s->ts_Ccan_act ,plural(s->ts_Ccan_act));
731 	fprintf(OUT,
732 		"%*s%6d inactive timer%s cancelled\n", indent, " ",
733 		s->ts_Ccan_inact ,plural(s->ts_Ccan_inact));
734 
735 	fprintf(OUT,
736 		"\n%*sPathological debugging activity:\n", indent, " ");
737 	fprintf(OUT,
738 		"\t%*s%6d CC%s sent to zero dref\n", indent, " ",
739 		s->ts_zdebug ,plural(s->ts_zdebug));
740 	/* SAME LINE AS ABOVE */
741 	fprintf(OUT,
742 		"\t%*s%6d random DT%s dropped\n", indent, " ",
743 		s->ts_ydebug ,plural(s->ts_ydebug));
744 	fprintf(OUT,
745 		"\t%*s%6d illegally large XPD TPDU%s\n", indent, " ",
746 		s->ts_vdebug ,plural(s->ts_vdebug));
747 	fprintf(OUT,
748 		"\t%*s%6d faked reneging of cdt\n", indent, " ",
749 		s->ts_ldebug );
750 
751 	fprintf(OUT,
752 		"\n%*sACK reasons:\n", indent, " ");
753 	fprintf(OUT, "\t%*s%6d not acked immediately\n", indent, " ",
754 		s->ts_ackreason[_ACK_DONT_] );
755 	fprintf(OUT, "\t%*s%6d strategy==each\n", indent, " ",
756 		s->ts_ackreason[_ACK_STRAT_EACH_] );
757 	fprintf(OUT, "\t%*s%6d strategy==fullwindow\n", indent, " ",
758 		s->ts_ackreason[_ACK_STRAT_FULLWIN_] );
759 	fprintf(OUT, "\t%*s%6d duplicate DT\n", indent, " ",
760 		s->ts_ackreason[_ACK_DUP_] );
761 	fprintf(OUT, "\t%*s%6d EOTSDU\n", indent, " ",
762 		s->ts_ackreason[_ACK_EOT_] );
763 	fprintf(OUT, "\t%*s%6d reordered DT\n", indent, " ",
764 		s->ts_ackreason[_ACK_REORDER_] );
765 	fprintf(OUT, "\t%*s%6d user rcvd\n", indent, " ",
766 		s->ts_ackreason[_ACK_USRRCV_] );
767 	fprintf(OUT, "\t%*s%6d fcc reqd\n", indent, " ",
768 		s->ts_ackreason[_ACK_FCC_] );
769 }
770 #ifndef SSEL
771 #define SSEL(s) ((s)->siso_tlen + TSEL(s))
772 #define PSEL(s) ((s)->siso_slen + SSEL(s))
773 #endif
774 
775 static void
776 isonetprint(siso, islocal)
777 	register struct sockaddr_iso *siso;
778 	int islocal;
779 {
780 	hexprint(siso->siso_nlen, siso->siso_addr.isoa_genaddr, "{}");
781 	if (siso->siso_tlen || siso->siso_slen || siso->siso_plen)
782 		hexprint(siso->siso_tlen, TSEL(siso), "()");
783 	if (siso->siso_slen || siso->siso_plen)
784 		hexprint(siso->siso_slen, SSEL(siso), "[]");
785 	if (siso->siso_plen)
786 		hexprint(siso->siso_plen, PSEL(siso), "<>");
787 	putchar(' ');
788 }
789 
790 static char hexlist[] = "0123456789abcdef", obuf[128];
791 
792 static void
793 hexprint(n, buf, delim)
794 	int n;
795 	char *buf, *delim;
796 {
797 	register u_char *in = (u_char *)buf, *top = in + n;
798 	register char *out = obuf;
799 	register int i;
800 
801 	if (n == 0)
802 		return;
803 	while (in < top) {
804 		i = *in++;
805 		*out++ = '.';
806 		if (i > 0xf) {
807 			out[1] = hexlist[i & 0xf];
808 			i >>= 4;
809 			out[0] = hexlist[i];
810 			out += 2;
811 		} else
812 			*out++ = hexlist[i];
813 	}
814 	*obuf = *delim; *out++ = delim[1]; *out = 0;
815 	printf("%s", obuf);
816 }
817