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