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