netstat: Reduce SACK scoreboard statistics description verbosity
[dragonfly.git] / usr.bin / netstat / inet.c
1 /*
2  * Copyright (c) 1983, 1988, 1993, 1995
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  * @(#)inet.c   8.5 (Berkeley) 5/24/95
34  * $FreeBSD: src/usr.bin/netstat/inet.c,v 1.37.2.11 2003/11/27 14:46:49 ru Exp $
35  */
36
37 #include <sys/param.h>
38 #include <sys/queue.h>
39 #include <sys/socket.h>
40 #include <sys/socketvar.h>
41 #include <sys/sysctl.h>
42 #include <sys/protosw.h>
43 #include <sys/time.h>
44
45 #include <net/route.h>
46 #include <netinet/in.h>
47 #include <netinet/in_systm.h>
48 #include <netinet/ip.h>
49 #include <netinet/ip_carp.h>
50 #ifdef INET6
51 #include <netinet/ip6.h>
52 #endif /* INET6 */
53 #include <netinet/in_pcb.h>
54 #include <netinet/ip_icmp.h>
55 #include <netinet/icmp_var.h>
56 #include <netinet/igmp_var.h>
57 #include <netinet/ip_var.h>
58 #include <netinet/pim_var.h>
59 #include <netinet/tcp.h>
60 #include <netinet/tcpip.h>
61 #include <netinet/tcp_seq.h>
62 #define TCPSTATES
63 #include <netinet/tcp_fsm.h>
64 #include <netinet/tcp_timer.h>
65 #include <netinet/tcp_var.h>
66 #include <netinet/tcp_debug.h>
67 #include <netinet/udp.h>
68 #include <netinet/udp_var.h>
69
70 #include <arpa/inet.h>
71 #include <err.h>
72 #include <errno.h>
73 #include <libutil.h>
74 #include <netdb.h>
75 #include <stdio.h>
76 #include <stdlib.h>
77 #include <string.h>
78 #include <unistd.h>
79 #include "netstat.h"
80
81 char    *inetname (struct in_addr *);
82 void    inetprint (struct in_addr *, int, const char *, int);
83 #ifdef INET6
84 extern void     inet6print (struct in6_addr *, int, const char *, int);
85 static int udp_done, tcp_done;
86 #endif /* INET6 */
87
88 /*
89  * Print a summary of connections related to an Internet
90  * protocol.  For TCP, also give state of connection.
91  * Listening processes (aflag) are suppressed unless the
92  * -a (all) flag is specified.
93  */
94
95 static int ppr_first = 1;
96 static void outputpcb(int proto, const char *name, struct inpcb *inp, struct xsocket *so, struct tcpcb *tp);
97
98 void
99 protopr(u_long proto, const char *name, int af1 __unused)
100 {
101         int istcp;
102         void *buf;
103         const char *mibvar;
104         size_t i, len;
105
106         istcp = 0;
107         switch (proto) {
108         case IPPROTO_TCP:
109 #ifdef INET6
110                 if (tcp_done != 0)
111                         return;
112                 else
113                         tcp_done = 1;
114 #endif
115                 istcp = 1;
116                 mibvar = "net.inet.tcp.pcblist";
117                 break;
118         case IPPROTO_UDP:
119 #ifdef INET6
120                 if (udp_done != 0)
121                         return;
122                 else
123                         udp_done = 1;
124 #endif
125                 mibvar = "net.inet.udp.pcblist";
126                 break;
127         case IPPROTO_DIVERT:
128                 mibvar = "net.inet.divert.pcblist";
129                 break;
130         default:
131                 mibvar = "net.inet.raw.pcblist";
132                 break;
133         }
134         len = 0;
135         if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) {
136                 if (errno != ENOENT)
137                         warn("sysctl: %s", mibvar);
138                 return;
139         }
140         if (len == 0)
141                 return;
142         if ((buf = malloc(len)) == NULL) {
143                 warn("malloc %lu bytes", (u_long)len);
144                 return;
145         }
146         if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) {
147                 warn("sysctl: %s", mibvar);
148                 free(buf);
149                 return;
150         }
151
152         if (istcp) {
153                 struct xtcpcb *tcp = buf;
154                 len /= sizeof(*tcp);
155                 for (i = 0; i < len; i++) {
156                         if (tcp[i].xt_len != sizeof(*tcp))
157                                 break;
158                         outputpcb(proto, name, &tcp[i].xt_inp,
159                                   &tcp[i].xt_socket, &tcp[i].xt_tp);
160                 }
161         } else {
162                 struct xinpcb *in = buf;
163                 len /= sizeof(*in);
164                 for (i = 0; i < len; i++) {
165                         if (in[i].xi_len != sizeof(*in))
166                                 break;
167                         outputpcb(proto, name, &in[i].xi_inp,
168                                   &in[i].xi_socket, NULL);
169                 }
170         }
171         free(buf);
172 }
173
174 static void
175 outputpcb(int proto, const char *name, struct inpcb *inp, struct xsocket *so, struct tcpcb *tp)
176 {
177         const char *vchar;
178         static struct clockinfo clockinfo;
179
180         if (clockinfo.hz == 0) {
181                 size_t size = sizeof(clockinfo);
182                 sysctlbyname("kern.clockrate", &clockinfo, &size, NULL, 0);
183                 if (clockinfo.hz == 0)
184                         clockinfo.hz = 100;
185         }
186
187         /* Ignore sockets for protocols other than the desired one. */
188         if (so->xso_protocol != (int)proto)
189                 return;
190
191         if ((af == AF_INET && (inp->inp_vflag & INP_IPV4) == 0)
192 #ifdef INET6
193             || (af == AF_INET6 && (inp->inp_vflag & INP_IPV6) == 0)
194 #endif /* INET6 */
195             || (af == AF_UNSPEC && ((inp->inp_vflag & INP_IPV4) == 0
196 #ifdef INET6
197                 && (inp->inp_vflag & INP_IPV6) == 0
198 #endif /* INET6 */
199                 ))
200             ) {
201                 return;
202         }
203         if (!aflag && ( 
204                 (proto == IPPROTO_TCP && tp->t_state == TCPS_LISTEN) ||
205                 (af == AF_INET && inet_lnaof(inp->inp_laddr) == INADDR_ANY)
206 #ifdef INET6
207             || (af == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr))
208 #endif /* INET6 */
209             || (af == AF_UNSPEC && (((inp->inp_vflag & INP_IPV4) != 0 &&
210                 inet_lnaof(inp->inp_laddr) == INADDR_ANY)
211 #ifdef INET6
212             || ((inp->inp_vflag & INP_IPV6) != 0 &&
213                 IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr))
214 #endif
215                   ))
216              )) {
217                 return;
218         }
219
220         if (ppr_first) {
221                 if (!Lflag) {
222                         printf("Active Internet connections");
223                         if (aflag)
224                                 printf(" (including servers)");
225                 } else {
226                         printf("Current listen queue sizes "
227                                 "(qlen/incqlen/maxqlen)");
228                 }
229                 putchar('\n');
230                 if (Aflag)
231                         printf("%-8.8s ", "Socket");
232                 if (Pflag)
233                         printf("%8.8s %8.8s %8.8s ", "TxWin", "Unacked", "RTT/ms");
234                 if (Lflag) {
235                         printf("%-5.5s %-14.14s %-22.22s\n",
236                                 "Proto", "Listen", "Local Address");
237                 } else {
238                         printf((Aflag && !Wflag) ?
239                             "%-5.5s %-6.6s %-6.6s %-17.17s %-17.17s %s\n" :
240                             "%-5.5s %-6.6s %-6.6s %-21.21s %-21.21s %s\n",
241                             "Proto", "Recv-Q", "Send-Q",
242                             "Local Address", "Foreign Address",
243                             "(state)");
244                 }
245                 ppr_first = 0;
246         }
247         if (Lflag && so->so_qlimit == 0)
248                 return;
249         if (Aflag) {
250                 if (tp)
251                         printf("%8lx ", (u_long)inp->inp_ppcb);
252                 else
253                         printf("%8lx ", (u_long)so->so_pcb);
254         }
255         if (Pflag) {
256                 if (tp) {
257                         int window = MIN(tp->snd_cwnd, tp->snd_bwnd);
258                         if (window == 1073725440)
259                                 printf("%8s ", "max");
260                         else
261                                 printf("%8d ", (int)MIN(tp->snd_cwnd, tp->snd_bwnd));
262                         printf("%8d ", (int)(tp->snd_max - tp->snd_una));
263                         if (tp->t_srtt == 0)
264                             printf("%8s ", "-");
265                         else
266                             printf("%8.3f ", (double)tp->t_srtt * 1000.0 / TCP_RTT_SCALE / clockinfo.hz);
267                 } else {
268                         printf("%8s %8s %8s ", "-", "-", "-");
269                 }
270         }
271 #ifdef INET6
272         if ((inp->inp_vflag & INP_IPV6) != 0)
273                 vchar = ((inp->inp_vflag & INP_IPV4) != 0) ? "46" : "6 ";
274         else
275 #endif
276                 vchar = ((inp->inp_vflag & INP_IPV4) != 0) ? "4 " : "  ";
277
278         printf("%-3.3s%-2.2s ", name, vchar);
279         if (Lflag) {
280                 char buf[15];
281
282                 snprintf(buf, sizeof(buf), "%d/%d/%d", so->so_qlen,
283                          so->so_incqlen, so->so_qlimit);
284                 printf("%-13.13s ", buf);
285         } else if (Bflag) {
286                 printf("%6ld %6ld ",
287                        so->so_rcv.sb_hiwat,
288                        so->so_snd.sb_hiwat);
289         } else {
290                 printf("%6ld %6ld ",
291                        so->so_rcv.sb_cc,
292                        so->so_snd.sb_cc);
293         }
294         if (numeric_port) {
295                 if (inp->inp_vflag & INP_IPV4) {
296                         inetprint(&inp->inp_laddr, (int)inp->inp_lport,
297                                   name, 1);
298                         if (!Lflag)
299                                 inetprint(&inp->inp_faddr,
300                                           (int)inp->inp_fport, name, 1);
301                 }
302 #ifdef INET6
303                 else if (inp->inp_vflag & INP_IPV6) {
304                         inet6print(&inp->in6p_laddr,
305                                    (int)inp->inp_lport, name, 1);
306                         if (!Lflag)
307                                 inet6print(&inp->in6p_faddr,
308                                            (int)inp->inp_fport, name, 1);
309                 } /* else nothing printed now */
310 #endif /* INET6 */
311         } else if (inp->inp_flags & INP_ANONPORT) {
312                 if (inp->inp_vflag & INP_IPV4) {
313                         inetprint(&inp->inp_laddr, (int)inp->inp_lport,
314                                   name, 1);
315                         if (!Lflag)
316                                 inetprint(&inp->inp_faddr,
317                                           (int)inp->inp_fport, name, 0);
318                 }
319 #ifdef INET6
320                 else if (inp->inp_vflag & INP_IPV6) {
321                         inet6print(&inp->in6p_laddr,
322                                    (int)inp->inp_lport, name, 1);
323                         if (!Lflag)
324                                 inet6print(&inp->in6p_faddr,
325                                            (int)inp->inp_fport, name, 0);
326                 } /* else nothing printed now */
327 #endif /* INET6 */
328         } else {
329                 if (inp->inp_vflag & INP_IPV4) {
330                         inetprint(&inp->inp_laddr, (int)inp->inp_lport,
331                                   name, 0);
332                         if (!Lflag)
333                                 inetprint(&inp->inp_faddr,
334                                           (int)inp->inp_fport, name,
335                                           inp->inp_lport !=
336                                                 inp->inp_fport);
337                 }
338 #ifdef INET6
339                 else if (inp->inp_vflag & INP_IPV6) {
340                         inet6print(&inp->in6p_laddr,
341                                    (int)inp->inp_lport, name, 0);
342                         if (!Lflag)
343                                 inet6print(&inp->in6p_faddr,
344                                            (int)inp->inp_fport, name,
345                                            inp->inp_lport !=
346                                                 inp->inp_fport);
347                 } /* else nothing printed now */
348 #endif /* INET6 */
349         }
350         if (tp && !Lflag) {
351                 if (tp->t_state < 0 || tp->t_state >= TCP_NSTATES)
352                         printf("%d", tp->t_state);
353               else {
354                         printf("%s", tcpstates[tp->t_state]);
355 #if defined(TF_NEEDSYN) && defined(TF_NEEDFIN)
356                       /* Show T/TCP `hidden state' */
357                       if (tp->t_flags & (TF_NEEDSYN|TF_NEEDFIN))
358                               putchar('*');
359 #endif /* defined(TF_NEEDSYN) && defined(TF_NEEDFIN) */
360               }
361         }
362         putchar('\n');
363 }
364
365
366
367 #define CPU_STATS_FUNC(proto,type)                            \
368 static void                                                   \
369 proto ##_stats_agg(type *ary, type *ttl, int cpucnt)          \
370 {                                                             \
371     int i, off, siz;                                          \
372     siz = sizeof(type);                                       \
373                                                               \
374     if (!ary && !ttl)                                         \
375         return;                                               \
376                                                               \
377     bzero(ttl, siz);                                          \
378     if (cpucnt == 1) {                                        \
379         *ttl = ary[0];                                        \
380     } else {                                                  \
381         for (i = 0; i < cpucnt; ++i) {                        \
382             for (off = 0; off < siz; off += sizeof(u_long)) { \
383                 *(u_long *)((char *)(*(&ttl)) + off) +=       \
384                 *(u_long *)((char *)&ary[i] + off);           \
385             }                                                 \
386         }                                                     \
387     }                                                         \
388 }
389 CPU_STATS_FUNC(tcp, struct tcp_stats);
390 CPU_STATS_FUNC(ip, struct ip_stats);
391
392 /*
393  * Dump TCP statistics structure.
394  */
395 void
396 tcp_stats(u_long off __unused, const char *name, int af1 __unused)
397 {
398         struct tcp_stats tcpstat, *stattmp;
399         struct tcp_stats zerostat[SMP_MAXCPU];
400         size_t len = sizeof(struct tcp_stats) * SMP_MAXCPU;
401         int cpucnt;
402         
403         if (zflag)
404                 memset(zerostat, 0, len);
405
406         if ((stattmp = malloc(len)) == NULL) {
407                 return;
408         } else {
409                 if (sysctlbyname("net.inet.tcp.stats", stattmp, &len,
410                         zflag ? zerostat : NULL, zflag ? len : 0) < 0) {
411                         warn("sysctl: net.inet.tcp.stats");
412                         free(stattmp);
413                         return;
414                 } else {
415                         if ((stattmp = realloc(stattmp, len)) == NULL) {
416                                 warn("tcp_stats");
417                                 return;
418                         }
419                 }
420         }
421         cpucnt = len / sizeof(struct tcp_stats);
422         tcp_stats_agg(stattmp, &tcpstat, cpucnt);
423
424 #ifdef INET6
425         if (tcp_done != 0)
426                 return;
427         else
428                 tcp_done = 1;
429 #endif
430
431         printf ("%s:\n", name);
432
433 #define p(f, m) if (tcpstat.f || sflag <= 1) \
434     printf(m, tcpstat.f, plural(tcpstat.f))
435 #define p1a(f, m) if (tcpstat.f || sflag <= 1) \
436     printf(m, tcpstat.f)
437 #define p2(f1, f2, m) if (tcpstat.f1 || tcpstat.f2 || sflag <= 1) \
438     printf(m, tcpstat.f1, plural(tcpstat.f1), tcpstat.f2, plural(tcpstat.f2))
439 #define p2a(f1, f2, m) if (tcpstat.f1 || tcpstat.f2 || sflag <= 1) \
440     printf(m, tcpstat.f1, plural(tcpstat.f1), tcpstat.f2)
441 #define p3(f, m) if (tcpstat.f || sflag <= 1) \
442     printf(m, tcpstat.f, plurales(tcpstat.f))
443
444         p(tcps_sndtotal, "\t%lu packet%s sent\n");
445         p2(tcps_sndpack,tcps_sndbyte,
446                 "\t\t%lu data packet%s (%lu byte%s)\n");
447         p2(tcps_sndrexmitpack, tcps_sndrexmitbyte,
448                 "\t\t%lu data packet%s (%lu byte%s) retransmitted\n");
449         p2(tcps_sndsackpack, tcps_sndsackbyte,
450                 "\t\t%lu data packet%s (%lu byte%s) sent by SACK recovery\n");
451         p2(tcps_sndsackrtopack, tcps_sndsackrtobyte,
452                 "\t\t%lu data packet%s (%lu byte%s) retransmitted by SACK\n");
453         p2a(tcps_sndfastrexmit, tcps_sndearlyrexmit,
454                 "\t\t%lu Fast Retransmit%s (%lu early)\n");
455         p(tcps_sndlimited, "\t\t%lu packet%s sent by Limited Transmit\n");
456         p(tcps_sndrtobad, "\t\t%lu spurious RTO retransmit%s\n");
457         p2a(tcps_sndfastrexmitbad, tcps_sndearlyrexmitbad,
458                 "\t\t%lu spurious Fast Retransmit%s (%lu early)\n");
459         p2a(tcps_eifeldetected, tcps_rttcantdetect,
460                 "\t\t%lu Eifel-detected spurious retransmit%s (%lu non-RTT)\n");
461         p(tcps_rttdetected, "\t\t%lu RTT-detected spurious retransmit%s\n");
462         p(tcps_mturesent, "\t\t%lu resend%s initiated by MTU discovery\n");
463         p(tcps_sndsackopt, "\t\t%lu SACK option%s sent\n");
464         p(tcps_snddsackopt, "\t\t%lu D-SACK option%s sent\n");
465         p2a(tcps_sndacks, tcps_delack,
466                 "\t\t%lu ack-only packet%s (%lu delayed)\n");
467         p(tcps_sndurg, "\t\t%lu URG only packet%s\n");
468         p(tcps_sndprobe, "\t\t%lu window probe packet%s\n");
469         p(tcps_sndwinup, "\t\t%lu window update packet%s\n");
470         p(tcps_sndctrl, "\t\t%lu control packet%s\n");
471         p(tcps_rcvtotal, "\t%lu packet%s received\n");
472         p2(tcps_rcvackpack, tcps_rcvackbyte, "\t\t%lu ack%s (for %lu byte%s)\n");
473         p(tcps_rcvdupack, "\t\t%lu duplicate ack%s\n");
474         p(tcps_rcvacktoomuch, "\t\t%lu ack%s for unsent data\n");
475         p2(tcps_rcvpack, tcps_rcvbyte,
476                 "\t\t%lu packet%s (%lu byte%s) received in-sequence\n");
477         p2(tcps_rcvduppack, tcps_rcvdupbyte,
478                 "\t\t%lu completely duplicate packet%s (%lu byte%s)\n");
479         p(tcps_pawsdrop, "\t\t%lu old duplicate packet%s\n");
480         p2(tcps_rcvpartduppack, tcps_rcvpartdupbyte,
481                 "\t\t%lu packet%s with some dup. data (%lu byte%s duped)\n");
482         p2(tcps_rcvoopack, tcps_rcvoobyte,
483                 "\t\t%lu out-of-order packet%s (%lu byte%s)\n");
484         p2(tcps_rcvpackafterwin, tcps_rcvbyteafterwin,
485                 "\t\t%lu packet%s (%lu byte%s) of data after window\n");
486         p(tcps_rcvwinprobe, "\t\t%lu window probe%s\n");
487         p(tcps_rcvwinupd, "\t\t%lu window update packet%s\n");
488         p(tcps_rcvafterclose, "\t\t%lu packet%s received after close\n");
489         p(tcps_rcvbadsum, "\t\t%lu discarded for bad checksum%s\n");
490         p(tcps_rcvbadoff, "\t\t%lu discarded for bad header offset field%s\n");
491         p1a(tcps_rcvshort, "\t\t%lu discarded because packet too short\n");
492         p(tcps_rcvbadsackopt, "\t\t%lu bad SACK option%s\n");
493         p(tcps_connattempt, "\t%lu connection request%s\n");
494         p(tcps_accepts, "\t%lu connection accept%s\n");
495         p(tcps_badsyn, "\t%lu bad connection attempt%s\n");
496         p(tcps_listendrop, "\t%lu listen queue overflow%s\n");
497         p(tcps_connects, "\t%lu connection%s established (including accepts)\n");
498         p2(tcps_closed, tcps_drops,
499                 "\t%lu connection%s closed (including %lu drop%s)\n");
500         p(tcps_cachedrtt, "\t\t%lu connection%s updated cached RTT on close\n");
501         p(tcps_cachedrttvar, 
502           "\t\t%lu connection%s updated cached RTT variance on close\n");
503         p(tcps_cachedssthresh,
504           "\t\t%lu connection%s updated cached ssthresh on close\n");
505         p(tcps_conndrops, "\t%lu embryonic connection%s dropped\n");
506         p2(tcps_rttupdated, tcps_segstimed,
507                 "\t%lu segment%s updated rtt (of %lu attempt%s)\n");
508         p(tcps_rexmttimeo, "\t%lu retransmit timeout%s\n");
509         p(tcps_timeoutdrop, "\t\t%lu connection%s dropped by rexmit timeout\n");
510         p(tcps_persisttimeo, "\t%lu persist timeout%s\n");
511         p(tcps_persistdrop, "\t\t%lu connection%s dropped by persist timeout\n");
512         p(tcps_keeptimeo, "\t%lu keepalive timeout%s\n");
513         p(tcps_keepprobe, "\t\t%lu keepalive probe%s sent\n");
514         p(tcps_keepdrops, "\t\t%lu connection%s dropped by keepalive\n");
515         p(tcps_predack, "\t%lu correct ACK header prediction%s\n");
516         p(tcps_preddat, "\t%lu correct data packet header prediction%s\n");
517
518         p1a(tcps_sc_added, "\t%lu syncache entries added\n"); 
519         p1a(tcps_sc_retransmitted, "\t\t%lu retransmitted\n"); 
520         p1a(tcps_sc_dupsyn, "\t\t%lu dupsyn\n"); 
521         p1a(tcps_sc_dropped, "\t\t%lu dropped\n"); 
522         p1a(tcps_sc_completed, "\t\t%lu completed\n"); 
523         p1a(tcps_sc_bucketoverflow, "\t\t%lu bucket overflow\n"); 
524         p1a(tcps_sc_cacheoverflow, "\t\t%lu cache overflow\n"); 
525         p1a(tcps_sc_reset, "\t\t%lu reset\n"); 
526         p1a(tcps_sc_stale, "\t\t%lu stale\n"); 
527         p1a(tcps_sc_aborted, "\t\t%lu aborted\n"); 
528         p1a(tcps_sc_badack, "\t\t%lu badack\n"); 
529         p1a(tcps_sc_unreach, "\t\t%lu unreach\n"); 
530         p1a(tcps_sc_zonefail, "\t\t%lu zone failures\n"); 
531         p1a(tcps_sc_sendcookie, "\t\t%lu cookies sent\n"); 
532         p1a(tcps_sc_recvcookie, "\t\t%lu cookies received\n"); 
533
534         p(tcps_sacksbupdate, "\t%lu SACK scoreboard update%s\n");
535         p(tcps_sacksboverflow, "\t\t%lu overflow%s\n");
536         p(tcps_sacksbfailed, "\t\t%lu failure%s\n");
537         p(tcps_sacksbreused, "\t\t%lu record%s reused\n");
538
539         free(stattmp);
540 #undef p
541 #undef p1a
542 #undef p2
543 #undef p2a
544 #undef p3
545 }
546
547 /*
548  * Dump UDP statistics structure.
549  */
550 void
551 udp_stats(u_long off __unused, const char *name, int af1 __unused)
552 {
553         struct udpstat udpstat, zerostat;
554         size_t len = sizeof udpstat;
555         u_long delivered;
556
557         if (zflag)
558                 memset(&zerostat, 0, len);
559         if (sysctlbyname("net.inet.udp.stats", &udpstat, &len,
560             zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
561                 warn("sysctl: net.inet.udp.stats");
562                 return;
563         }
564
565 #ifdef INET6
566         if (udp_done != 0)
567                 return;
568         else
569                 udp_done = 1;
570 #endif
571
572         printf("%s:\n", name);
573 #define p(f, m) if (udpstat.f || sflag <= 1) \
574     printf(m, udpstat.f, plural(udpstat.f))
575 #define p1a(f, m) if (udpstat.f || sflag <= 1) \
576     printf(m, udpstat.f)
577         p(udps_ipackets, "\t%lu datagram%s received\n");
578         p1a(udps_hdrops, "\t%lu with incomplete header\n");
579         p1a(udps_badlen, "\t%lu with bad data length field\n");
580         p1a(udps_badsum, "\t%lu with bad checksum\n");
581         p1a(udps_nosum, "\t%lu with no checksum\n");
582         p1a(udps_noport, "\t%lu dropped due to no socket\n");
583         p(udps_noportbcast,
584             "\t%lu broadcast/multicast datagram%s dropped due to no socket\n");
585         p1a(udps_fullsock, "\t%lu dropped due to full socket buffers\n");
586         p1a(udpps_pcbhashmiss, "\t%lu not for hashed pcb\n");
587         delivered = udpstat.udps_ipackets -
588                     udpstat.udps_hdrops -
589                     udpstat.udps_badlen -
590                     udpstat.udps_badsum -
591                     udpstat.udps_noport -
592                     udpstat.udps_noportbcast -
593                     udpstat.udps_fullsock;
594         if (delivered || sflag <= 1)
595                 printf("\t%lu delivered\n", delivered);
596         p(udps_opackets, "\t%lu datagram%s output\n");
597 #undef p
598 #undef p1a
599 }
600
601 /* 
602  * Dump CARP statistics structure.
603  */
604 void
605 carp_stats(u_long off __unused, const char *name, int af1 __unused)
606 {
607        struct carpstats carpstat, zerostat;
608        size_t len = sizeof(struct carpstats);
609
610        if (zflag)
611                memset(&zerostat, 0, len);
612        if (sysctlbyname("net.inet.carp.stats", &carpstat, &len,
613            zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
614                warn("sysctl: net.inet.carp.stats");
615                return;
616        }
617
618        printf("%s:\n", name);
619
620 #define p(f, m) if (carpstat.f || sflag <= 1) \
621        printf(m, (uintmax_t)carpstat.f, plural((int)carpstat.f))
622 #define p2(f, m) if (carpstat.f || sflag <= 1) \
623        printf(m, (uintmax_t)carpstat.f)
624
625        p(carps_ipackets, "\t%ju packet%s received (IPv4)\n");
626        p(carps_ipackets6, "\t%ju packet%s received (IPv6)\n");
627        p(carps_badttl, "\t\t%ju packet%s discarded for wrong TTL\n");
628        p(carps_hdrops, "\t\t%ju packet%s shorter than header\n");
629        p(carps_badsum, "\t\t%ju discarded for bad checksum%s\n");
630        p(carps_badver, "\t\t%ju discarded packet%s with a bad version\n");
631        p2(carps_badlen, "\t\t%ju discarded because packet too short\n");
632        p2(carps_badauth, "\t\t%ju discarded for bad authentication\n");
633        p2(carps_badvhid, "\t\t%ju discarded for bad vhid\n");
634        p2(carps_badaddrs, "\t\t%ju discarded because of a bad address list\n");
635        p(carps_opackets, "\t%ju packet%s sent (IPv4)\n");
636        p(carps_opackets6, "\t%ju packet%s sent (IPv6)\n");
637        p2(carps_onomem, "\t\t%ju send failed due to mbuf memory error\n");
638 #if notyet
639        p(carps_ostates, "\t\t%s state update%s sent\n");
640 #endif
641 #undef p
642 #undef p2
643 }
644
645 /*
646  * Dump IP statistics structure.
647  */
648 void
649 ip_stats(u_long off __unused, const char *name, int af1 __unused)
650 {
651         struct ip_stats ipstat, *stattmp;
652         struct ip_stats zerostat[SMP_MAXCPU];
653         size_t len = sizeof(struct ip_stats) * SMP_MAXCPU;
654         int cpucnt;
655
656         if (zflag)
657                 memset(zerostat, 0, len);
658         if ((stattmp = malloc(len)) == NULL) {
659                 return;
660         } else {
661                 if (sysctlbyname("net.inet.ip.stats", stattmp, &len,
662                         zflag ? zerostat : NULL, zflag ? len : 0) < 0) {
663                                 warn("sysctl: net.inet.ip.stats");
664                                 free(stattmp);
665                                 return;
666                 } else {
667                         if ((stattmp = realloc(stattmp, len)) == NULL) {
668                                 warn("ip_stats");
669                                 return;
670                         }
671                 }
672         }
673         cpucnt = len / sizeof(struct ip_stats);
674         ip_stats_agg(stattmp, &ipstat, cpucnt);
675
676         printf("%s:\n", name);
677
678 #define p(f, m) if (ipstat.f || sflag <= 1) \
679     printf(m, ipstat.f, plural(ipstat.f))
680 #define p1a(f, m) if (ipstat.f || sflag <= 1) \
681     printf(m, ipstat.f)
682
683         p(ips_total, "\t%lu total packet%s received\n");
684         p(ips_badsum, "\t%lu bad header checksum%s\n");
685         p1a(ips_toosmall, "\t%lu with size smaller than minimum\n");
686         p1a(ips_tooshort, "\t%lu with data size < data length\n");
687         p1a(ips_toolong, "\t%lu with ip length > max ip packet size\n");
688         p1a(ips_badhlen, "\t%lu with header length < data size\n");
689         p1a(ips_badlen, "\t%lu with data length < header length\n");
690         p1a(ips_badoptions, "\t%lu with bad options\n");
691         p1a(ips_badvers, "\t%lu with incorrect version number\n");
692         p(ips_fragments, "\t%lu fragment%s received\n");
693         p(ips_fragdropped, "\t%lu fragment%s dropped (dup or out of space)\n");
694         p(ips_fragtimeout, "\t%lu fragment%s dropped after timeout\n");
695         p(ips_reassembled, "\t%lu packet%s reassembled ok\n");
696         p(ips_delivered, "\t%lu packet%s for this host\n");
697         p(ips_noproto, "\t%lu packet%s for unknown/unsupported protocol\n");
698         p(ips_forward, "\t%lu packet%s forwarded");
699         p(ips_fastforward, " (%lu packet%s fast forwarded)");
700         if (ipstat.ips_forward || sflag <= 1) 
701                 putchar('\n');
702         p(ips_cantforward, "\t%lu packet%s not forwardable\n");
703         p(ips_notmember,
704           "\t%lu packet%s received for unknown multicast group\n");
705         p(ips_redirectsent, "\t%lu redirect%s sent\n");
706         p(ips_localout, "\t%lu packet%s sent from this host\n");
707         p(ips_rawout, "\t%lu packet%s sent with fabricated ip header\n");
708         p(ips_odropped,
709           "\t%lu output packet%s dropped due to no bufs, etc.\n");
710         p(ips_noroute, "\t%lu output packet%s discarded due to no route\n");
711         p(ips_fragmented, "\t%lu output datagram%s fragmented\n");
712         p(ips_ofragments, "\t%lu fragment%s created\n");
713         p(ips_cantfrag, "\t%lu datagram%s that can't be fragmented\n");
714         p(ips_nogif, "\t%lu tunneling packet%s that can't find gif\n");
715         p(ips_badaddr, "\t%lu datagram%s with bad address in header\n");
716         free(stattmp);
717 #undef p
718 #undef p1a
719 }
720
721 static  const char *icmpnames[] = {
722         "echo reply",
723         "#1",
724         "#2",
725         "destination unreachable",
726         "source quench",
727         "routing redirect",
728         "#6",
729         "#7",
730         "echo",
731         "router advertisement",
732         "router solicitation",
733         "time exceeded",
734         "parameter problem",
735         "time stamp",
736         "time stamp reply",
737         "information request",
738         "information request reply",
739         "address mask request",
740         "address mask reply",
741 };
742
743 /*
744  * Dump ICMP statistics.
745  */
746 void
747 icmp_stats(u_long off __unused, const char *name, int af1 __unused)
748 {
749         struct icmpstat icmpstat, zerostat;
750         int i, first;
751         int mib[4];             /* CTL_NET + PF_INET + IPPROTO_ICMP + req */
752         size_t len;
753
754         mib[0] = CTL_NET;
755         mib[1] = PF_INET;
756         mib[2] = IPPROTO_ICMP;
757         mib[3] = ICMPCTL_STATS;
758
759         len = sizeof icmpstat;
760         if (zflag)
761                 memset(&zerostat, 0, len);
762         if (sysctl(mib, 4, &icmpstat, &len,
763             zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
764                 warn("sysctl: net.inet.icmp.stats");
765                 return;
766         }
767
768         printf("%s:\n", name);
769
770 #define p(f, m) if (icmpstat.f || sflag <= 1) \
771     printf(m, icmpstat.f, plural(icmpstat.f))
772 #define p1a(f, m) if (icmpstat.f || sflag <= 1) \
773     printf(m, icmpstat.f)
774 #define p2(f, m) if (icmpstat.f || sflag <= 1) \
775     printf(m, icmpstat.f, plurales(icmpstat.f))
776
777         p(icps_error, "\t%lu call%s to icmp_error\n");
778         p(icps_oldicmp,
779             "\t%lu error%s not generated 'cuz old message was icmp\n");
780         for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
781                 if (icmpstat.icps_outhist[i] != 0) {
782                         if (first) {
783                                 printf("\tOutput histogram:\n");
784                                 first = 0;
785                         }
786                         printf("\t\t%s: %lu\n", icmpnames[i],
787                                 icmpstat.icps_outhist[i]);
788                 }
789         p(icps_badcode, "\t%lu message%s with bad code fields\n");
790         p(icps_tooshort, "\t%lu message%s < minimum length\n");
791         p(icps_checksum, "\t%lu bad checksum%s\n");
792         p(icps_badlen, "\t%lu message%s with bad length\n");
793         p1a(icps_bmcastecho, "\t%lu multicast echo requests ignored\n");
794         p1a(icps_bmcasttstamp, "\t%lu multicast timestamp requests ignored\n");
795         for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
796                 if (icmpstat.icps_inhist[i] != 0) {
797                         if (first) {
798                                 printf("\tInput histogram:\n");
799                                 first = 0;
800                         }
801                         printf("\t\t%s: %lu\n", icmpnames[i],
802                                 icmpstat.icps_inhist[i]);
803                 }
804         p(icps_reflect, "\t%lu message response%s generated\n");
805         p2(icps_badaddr, "\t%lu invalid return address%s\n");
806         p(icps_noroute, "\t%lu no return route%s\n");
807 #undef p
808 #undef p1a
809 #undef p2
810         mib[3] = ICMPCTL_MASKREPL;
811         len = sizeof i;
812         if (sysctl(mib, 4, &i, &len, NULL, 0) < 0)
813                 return;
814         printf("\tICMP address mask responses are %sabled\n", 
815                i ? "en" : "dis");
816 }
817
818 /*
819  * Dump IGMP statistics structure.
820  */
821 void
822 igmp_stats(u_long off __unused, const char *name, int af1 __unused)
823 {
824         struct igmpstat igmpstat, zerostat;
825         size_t len = sizeof igmpstat;
826
827         if (zflag)
828                 memset(&zerostat, 0, len);
829         if (sysctlbyname("net.inet.igmp.stats", &igmpstat, &len,
830             zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
831                 warn("sysctl: net.inet.igmp.stats");
832                 return;
833         }
834
835         printf("%s:\n", name);
836
837 #define p(f, m) if (igmpstat.f || sflag <= 1) \
838     printf(m, igmpstat.f, plural(igmpstat.f))
839 #define py(f, m) if (igmpstat.f || sflag <= 1) \
840     printf(m, igmpstat.f, igmpstat.f != 1 ? "ies" : "y")
841         p(igps_rcv_total, "\t%u message%s received\n");
842         p(igps_rcv_tooshort, "\t%u message%s received with too few bytes\n");
843         p(igps_rcv_badsum, "\t%u message%s received with bad checksum\n");
844         py(igps_rcv_queries, "\t%u membership quer%s received\n");
845         py(igps_rcv_badqueries, "\t%u membership quer%s received with invalid field(s)\n");
846         p(igps_rcv_reports, "\t%u membership report%s received\n");
847         p(igps_rcv_badreports, "\t%u membership report%s received with invalid field(s)\n");
848         p(igps_rcv_ourreports, "\t%u membership report%s received for groups to which we belong\n");
849         p(igps_snd_reports, "\t%u membership report%s sent\n");
850 #undef p
851 #undef py
852 }
853
854 /*
855  * Dump PIM statistics structure.
856  */
857 void
858 pim_stats(u_long off __unused, const char *name, int af1 __unused)
859 {
860         struct pimstat pimstat, zerostat;
861         size_t len = sizeof pimstat;
862
863         if (zflag)
864                 memset(&zerostat, 0, len);
865         if (sysctlbyname("net.inet.pim.stats", &pimstat, &len,
866             zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
867                 if (errno != ENOENT)
868                         warn("sysctl: net.inet.pim.stats");
869                 return;
870         }
871
872         printf("%s:\n", name);
873
874 #define p(f, m) if (pimstat.f || sflag <= 1) \
875     printf(m, (uintmax_t)pimstat.f, plural(pimstat.f))
876 #define py(f, m) if (pimstat.f || sflag <= 1) \
877     printf(m, (uintmax_t)pimstat.f, pimstat.f != 1 ? "ies" : "y")
878         p(pims_rcv_total_msgs, "\t%ju message%s received\n");
879         p(pims_rcv_total_bytes, "\t%ju byte%s received\n");
880         p(pims_rcv_tooshort, "\t%ju message%s received with too few bytes\n");
881         p(pims_rcv_badsum, "\t%ju message%s received with bad checksum\n");
882         p(pims_rcv_badversion, "\t%ju message%s received with bad version\n");
883         p(pims_rcv_registers_msgs, "\t%ju data register message%s received\n");
884         p(pims_rcv_registers_bytes, "\t%ju data register byte%s received\n");
885         p(pims_rcv_registers_wrongiif, "\t%ju data register message%s received on wrong iif\n");
886         p(pims_rcv_badregisters, "\t%ju bad register%s received\n");
887         p(pims_snd_registers_msgs, "\t%ju data register message%s sent\n");
888         p(pims_snd_registers_bytes, "\t%ju data register byte%s sent\n");
889 #undef p
890 #undef py
891 }
892
893 /*
894  * Pretty print an Internet address (net address + port).
895  */
896 void
897 inetprint(struct in_addr *in, int port, const char *proto, int num_port)
898 {
899         struct servent *sp = NULL;
900         char line[80], *cp;
901         int width;
902
903         if (Wflag)
904             sprintf(line, "%s.", inetname(in));
905         else
906             sprintf(line, "%.*s.", (Aflag && !num_port) ? 12 : 16, inetname(in));
907         cp = strchr(line, '\0');
908         if (!num_port && port)
909                 sp = getservbyport((int)port, proto);
910         if (sp || port == 0)
911                 sprintf(cp, "%.15s ", sp ? sp->s_name : "*");
912         else
913                 sprintf(cp, "%d ", ntohs((u_short)port));
914         width = (Aflag && !Wflag) ? 17 : 21;
915         if (Wflag)
916             printf("%-*s ", width, line);
917         else
918             printf("%-*.*s ", width, width, line);
919 }
920
921 /*
922  * Construct an Internet address representation.
923  * If numeric_addr has been supplied, give
924  * numeric value, otherwise try for symbolic name.
925  */
926 char *
927 inetname(struct in_addr *inp)
928 {
929         char *cp;
930         static char line[MAXHOSTNAMELEN];
931         struct hostent *hp;
932         struct netent *np;
933
934         cp = NULL;
935         if (!numeric_addr && inp->s_addr != INADDR_ANY) {
936                 int net = inet_netof(*inp);
937                 int lna = inet_lnaof(*inp);
938
939                 if (lna == INADDR_ANY) {
940                         np = getnetbyaddr(net, AF_INET);
941                         if (np)
942                                 cp = np->n_name;
943                 }
944                 if (cp == NULL) {
945                         hp = gethostbyaddr(inp, sizeof (*inp), AF_INET);
946                         if (hp) {
947                                 cp = hp->h_name;
948                                 trimdomain(cp, strlen(cp));
949                         }
950                 }
951         }
952         if (inp->s_addr == INADDR_ANY)
953                 strcpy(line, "*");
954         else if (cp) {
955                 strncpy(line, cp, sizeof(line) - 1);
956                 line[sizeof(line) - 1] = '\0';
957         } else {
958                 inp->s_addr = ntohl(inp->s_addr);
959 #define C(x)    ((u_int)((x) & 0xff))
960                 sprintf(line, "%u.%u.%u.%u", C(inp->s_addr >> 24),
961                     C(inp->s_addr >> 16), C(inp->s_addr >> 8), C(inp->s_addr));
962         }
963         return (line);
964 }