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