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