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