tcp: Balance aggressiveness of SACK rescue retransmission
[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_sndsackrtopack, tcps_sndsackrtobyte,
450                 "\t\t%lu data packet%s (%lu byte%s) retransmitted by SACK\n");
451         p2(tcps_sndsackpack, tcps_sndsackbyte,
452                 "\t\t%lu data packet%s (%lu byte%s) sent by SACK recovery\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         p(tcps_sndidle, "\t%lu send idle%s\n");
518
519         p1a(tcps_sc_added, "\t%lu syncache entries added\n"); 
520         p1a(tcps_sc_retransmitted, "\t\t%lu retransmitted\n"); 
521         p1a(tcps_sc_dupsyn, "\t\t%lu dupsyn\n"); 
522         p1a(tcps_sc_dropped, "\t\t%lu dropped\n"); 
523         p1a(tcps_sc_completed, "\t\t%lu completed\n"); 
524         p1a(tcps_sc_bucketoverflow, "\t\t%lu bucket overflow\n"); 
525         p1a(tcps_sc_cacheoverflow, "\t\t%lu cache overflow\n"); 
526         p1a(tcps_sc_reset, "\t\t%lu reset\n"); 
527         p1a(tcps_sc_stale, "\t\t%lu stale\n"); 
528         p1a(tcps_sc_aborted, "\t\t%lu aborted\n"); 
529         p1a(tcps_sc_badack, "\t\t%lu badack\n"); 
530         p1a(tcps_sc_unreach, "\t\t%lu unreach\n"); 
531         p1a(tcps_sc_zonefail, "\t\t%lu zone failures\n"); 
532         p1a(tcps_sc_sendcookie, "\t\t%lu cookies sent\n"); 
533         p1a(tcps_sc_recvcookie, "\t\t%lu cookies received\n"); 
534
535         p(tcps_sacksbupdate, "\t%lu SACK scoreboard update%s\n");
536         p(tcps_sacksboverflow, "\t\t%lu overflow%s\n");
537         p(tcps_sacksbfailed, "\t\t%lu failure%s\n");
538         p(tcps_sacksbreused, "\t\t%lu record%s reused\n");
539         p(tcps_sacksbfast, "\t\t%lu record%s fast allocated\n");
540
541         p2(tcps_sackrescue, tcps_sackrescue_try,
542             "\t%lu SACK rescue%s (of %lu attempt%s)\n");
543
544         free(stattmp);
545 #undef p
546 #undef p1a
547 #undef p2
548 #undef p2a
549 #undef p3
550 }
551
552 /*
553  * Dump UDP statistics structure.
554  */
555 void
556 udp_stats(u_long off __unused, const char *name, int af1 __unused)
557 {
558         struct udpstat udpstat, zerostat;
559         size_t len = sizeof udpstat;
560         u_long delivered;
561
562         if (zflag)
563                 memset(&zerostat, 0, len);
564         if (sysctlbyname("net.inet.udp.stats", &udpstat, &len,
565             zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
566                 warn("sysctl: net.inet.udp.stats");
567                 return;
568         }
569
570 #ifdef INET6
571         if (udp_done != 0)
572                 return;
573         else
574                 udp_done = 1;
575 #endif
576
577         printf("%s:\n", name);
578 #define p(f, m) if (udpstat.f || sflag <= 1) \
579     printf(m, udpstat.f, plural(udpstat.f))
580 #define p1a(f, m) if (udpstat.f || sflag <= 1) \
581     printf(m, udpstat.f)
582         p(udps_ipackets, "\t%lu datagram%s received\n");
583         p1a(udps_hdrops, "\t%lu with incomplete header\n");
584         p1a(udps_badlen, "\t%lu with bad data length field\n");
585         p1a(udps_badsum, "\t%lu with bad checksum\n");
586         p1a(udps_nosum, "\t%lu with no checksum\n");
587         p1a(udps_noport, "\t%lu dropped due to no socket\n");
588         p(udps_noportbcast,
589             "\t%lu broadcast/multicast datagram%s dropped due to no socket\n");
590         p1a(udps_fullsock, "\t%lu dropped due to full socket buffers\n");
591         p1a(udpps_pcbhashmiss, "\t%lu not for hashed pcb\n");
592         delivered = udpstat.udps_ipackets -
593                     udpstat.udps_hdrops -
594                     udpstat.udps_badlen -
595                     udpstat.udps_badsum -
596                     udpstat.udps_noport -
597                     udpstat.udps_noportbcast -
598                     udpstat.udps_fullsock;
599         if (delivered || sflag <= 1)
600                 printf("\t%lu delivered\n", delivered);
601         p(udps_opackets, "\t%lu datagram%s output\n");
602 #undef p
603 #undef p1a
604 }
605
606 /* 
607  * Dump CARP statistics structure.
608  */
609 void
610 carp_stats(u_long off __unused, const char *name, int af1 __unused)
611 {
612        struct carpstats carpstat, zerostat;
613        size_t len = sizeof(struct carpstats);
614
615        if (zflag)
616                memset(&zerostat, 0, len);
617        if (sysctlbyname("net.inet.carp.stats", &carpstat, &len,
618            zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
619                warn("sysctl: net.inet.carp.stats");
620                return;
621        }
622
623        printf("%s:\n", name);
624
625 #define p(f, m) if (carpstat.f || sflag <= 1) \
626        printf(m, (uintmax_t)carpstat.f, plural((int)carpstat.f))
627 #define p2(f, m) if (carpstat.f || sflag <= 1) \
628        printf(m, (uintmax_t)carpstat.f)
629
630        p(carps_ipackets, "\t%ju packet%s received (IPv4)\n");
631        p(carps_ipackets6, "\t%ju packet%s received (IPv6)\n");
632        p(carps_badttl, "\t\t%ju packet%s discarded for wrong TTL\n");
633        p(carps_hdrops, "\t\t%ju packet%s shorter than header\n");
634        p(carps_badsum, "\t\t%ju discarded for bad checksum%s\n");
635        p(carps_badver, "\t\t%ju discarded packet%s with a bad version\n");
636        p2(carps_badlen, "\t\t%ju discarded because packet too short\n");
637        p2(carps_badauth, "\t\t%ju discarded for bad authentication\n");
638        p2(carps_badvhid, "\t\t%ju discarded for bad vhid\n");
639        p2(carps_badaddrs, "\t\t%ju discarded because of a bad address list\n");
640        p(carps_opackets, "\t%ju packet%s sent (IPv4)\n");
641        p(carps_opackets6, "\t%ju packet%s sent (IPv6)\n");
642        p2(carps_onomem, "\t\t%ju send failed due to mbuf memory error\n");
643 #if notyet
644        p(carps_ostates, "\t\t%s state update%s sent\n");
645 #endif
646 #undef p
647 #undef p2
648 }
649
650 /*
651  * Dump IP statistics structure.
652  */
653 void
654 ip_stats(u_long off __unused, const char *name, int af1 __unused)
655 {
656         struct ip_stats ipstat, *stattmp;
657         struct ip_stats zerostat[SMP_MAXCPU];
658         size_t len = sizeof(struct ip_stats) * SMP_MAXCPU;
659         int cpucnt;
660
661         if (zflag)
662                 memset(zerostat, 0, len);
663         if ((stattmp = malloc(len)) == NULL) {
664                 return;
665         } else {
666                 if (sysctlbyname("net.inet.ip.stats", stattmp, &len,
667                         zflag ? zerostat : NULL, zflag ? len : 0) < 0) {
668                                 warn("sysctl: net.inet.ip.stats");
669                                 free(stattmp);
670                                 return;
671                 } else {
672                         if ((stattmp = realloc(stattmp, len)) == NULL) {
673                                 warn("ip_stats");
674                                 return;
675                         }
676                 }
677         }
678         cpucnt = len / sizeof(struct ip_stats);
679         ip_stats_agg(stattmp, &ipstat, cpucnt);
680
681         printf("%s:\n", name);
682
683 #define p(f, m) if (ipstat.f || sflag <= 1) \
684     printf(m, ipstat.f, plural(ipstat.f))
685 #define p1a(f, m) if (ipstat.f || sflag <= 1) \
686     printf(m, ipstat.f)
687
688         p(ips_total, "\t%lu total packet%s received\n");
689         p(ips_badsum, "\t%lu bad header checksum%s\n");
690         p1a(ips_toosmall, "\t%lu with size smaller than minimum\n");
691         p1a(ips_tooshort, "\t%lu with data size < data length\n");
692         p1a(ips_toolong, "\t%lu with ip length > max ip packet size\n");
693         p1a(ips_badhlen, "\t%lu with header length < data size\n");
694         p1a(ips_badlen, "\t%lu with data length < header length\n");
695         p1a(ips_badoptions, "\t%lu with bad options\n");
696         p1a(ips_badvers, "\t%lu with incorrect version number\n");
697         p(ips_fragments, "\t%lu fragment%s received\n");
698         p(ips_fragdropped, "\t%lu fragment%s dropped (dup or out of space)\n");
699         p(ips_fragtimeout, "\t%lu fragment%s dropped after timeout\n");
700         p(ips_reassembled, "\t%lu packet%s reassembled ok\n");
701         p(ips_delivered, "\t%lu packet%s for this host\n");
702         p(ips_noproto, "\t%lu packet%s for unknown/unsupported protocol\n");
703         p(ips_forward, "\t%lu packet%s forwarded");
704         p(ips_fastforward, " (%lu packet%s fast forwarded)");
705         if (ipstat.ips_forward || sflag <= 1) 
706                 putchar('\n');
707         p(ips_cantforward, "\t%lu packet%s not forwardable\n");
708         p(ips_notmember,
709           "\t%lu packet%s received for unknown multicast group\n");
710         p(ips_redirectsent, "\t%lu redirect%s sent\n");
711         p(ips_localout, "\t%lu packet%s sent from this host\n");
712         p(ips_rawout, "\t%lu packet%s sent with fabricated ip header\n");
713         p(ips_odropped,
714           "\t%lu output packet%s dropped due to no bufs, etc.\n");
715         p(ips_noroute, "\t%lu output packet%s discarded due to no route\n");
716         p(ips_fragmented, "\t%lu output datagram%s fragmented\n");
717         p(ips_ofragments, "\t%lu fragment%s created\n");
718         p(ips_cantfrag, "\t%lu datagram%s that can't be fragmented\n");
719         p(ips_nogif, "\t%lu tunneling packet%s that can't find gif\n");
720         p(ips_badaddr, "\t%lu datagram%s with bad address in header\n");
721         free(stattmp);
722 #undef p
723 #undef p1a
724 }
725
726 static  const char *icmpnames[] = {
727         "echo reply",
728         "#1",
729         "#2",
730         "destination unreachable",
731         "source quench",
732         "routing redirect",
733         "#6",
734         "#7",
735         "echo",
736         "router advertisement",
737         "router solicitation",
738         "time exceeded",
739         "parameter problem",
740         "time stamp",
741         "time stamp reply",
742         "information request",
743         "information request reply",
744         "address mask request",
745         "address mask reply",
746 };
747
748 /*
749  * Dump ICMP statistics.
750  */
751 void
752 icmp_stats(u_long off __unused, const char *name, int af1 __unused)
753 {
754         struct icmpstat icmpstat, zerostat;
755         int i, first;
756         int mib[4];             /* CTL_NET + PF_INET + IPPROTO_ICMP + req */
757         size_t len;
758
759         mib[0] = CTL_NET;
760         mib[1] = PF_INET;
761         mib[2] = IPPROTO_ICMP;
762         mib[3] = ICMPCTL_STATS;
763
764         len = sizeof icmpstat;
765         if (zflag)
766                 memset(&zerostat, 0, len);
767         if (sysctl(mib, 4, &icmpstat, &len,
768             zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
769                 warn("sysctl: net.inet.icmp.stats");
770                 return;
771         }
772
773         printf("%s:\n", name);
774
775 #define p(f, m) if (icmpstat.f || sflag <= 1) \
776     printf(m, icmpstat.f, plural(icmpstat.f))
777 #define p1a(f, m) if (icmpstat.f || sflag <= 1) \
778     printf(m, icmpstat.f)
779 #define p2(f, m) if (icmpstat.f || sflag <= 1) \
780     printf(m, icmpstat.f, plurales(icmpstat.f))
781
782         p(icps_error, "\t%lu call%s to icmp_error\n");
783         p(icps_oldicmp,
784             "\t%lu error%s not generated 'cuz old message was icmp\n");
785         for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
786                 if (icmpstat.icps_outhist[i] != 0) {
787                         if (first) {
788                                 printf("\tOutput histogram:\n");
789                                 first = 0;
790                         }
791                         printf("\t\t%s: %lu\n", icmpnames[i],
792                                 icmpstat.icps_outhist[i]);
793                 }
794         p(icps_badcode, "\t%lu message%s with bad code fields\n");
795         p(icps_tooshort, "\t%lu message%s < minimum length\n");
796         p(icps_checksum, "\t%lu bad checksum%s\n");
797         p(icps_badlen, "\t%lu message%s with bad length\n");
798         p1a(icps_bmcastecho, "\t%lu multicast echo requests ignored\n");
799         p1a(icps_bmcasttstamp, "\t%lu multicast timestamp requests ignored\n");
800         for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
801                 if (icmpstat.icps_inhist[i] != 0) {
802                         if (first) {
803                                 printf("\tInput histogram:\n");
804                                 first = 0;
805                         }
806                         printf("\t\t%s: %lu\n", icmpnames[i],
807                                 icmpstat.icps_inhist[i]);
808                 }
809         p(icps_reflect, "\t%lu message response%s generated\n");
810         p2(icps_badaddr, "\t%lu invalid return address%s\n");
811         p(icps_noroute, "\t%lu no return route%s\n");
812 #undef p
813 #undef p1a
814 #undef p2
815         mib[3] = ICMPCTL_MASKREPL;
816         len = sizeof i;
817         if (sysctl(mib, 4, &i, &len, NULL, 0) < 0)
818                 return;
819         printf("\tICMP address mask responses are %sabled\n", 
820                i ? "en" : "dis");
821 }
822
823 /*
824  * Dump IGMP statistics structure.
825  */
826 void
827 igmp_stats(u_long off __unused, const char *name, int af1 __unused)
828 {
829         struct igmpstat igmpstat, zerostat;
830         size_t len = sizeof igmpstat;
831
832         if (zflag)
833                 memset(&zerostat, 0, len);
834         if (sysctlbyname("net.inet.igmp.stats", &igmpstat, &len,
835             zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
836                 warn("sysctl: net.inet.igmp.stats");
837                 return;
838         }
839
840         printf("%s:\n", name);
841
842 #define p(f, m) if (igmpstat.f || sflag <= 1) \
843     printf(m, igmpstat.f, plural(igmpstat.f))
844 #define py(f, m) if (igmpstat.f || sflag <= 1) \
845     printf(m, igmpstat.f, igmpstat.f != 1 ? "ies" : "y")
846         p(igps_rcv_total, "\t%u message%s received\n");
847         p(igps_rcv_tooshort, "\t%u message%s received with too few bytes\n");
848         p(igps_rcv_badsum, "\t%u message%s received with bad checksum\n");
849         py(igps_rcv_queries, "\t%u membership quer%s received\n");
850         py(igps_rcv_badqueries, "\t%u membership quer%s received with invalid field(s)\n");
851         p(igps_rcv_reports, "\t%u membership report%s received\n");
852         p(igps_rcv_badreports, "\t%u membership report%s received with invalid field(s)\n");
853         p(igps_rcv_ourreports, "\t%u membership report%s received for groups to which we belong\n");
854         p(igps_snd_reports, "\t%u membership report%s sent\n");
855 #undef p
856 #undef py
857 }
858
859 /*
860  * Dump PIM statistics structure.
861  */
862 void
863 pim_stats(u_long off __unused, const char *name, int af1 __unused)
864 {
865         struct pimstat pimstat, zerostat;
866         size_t len = sizeof pimstat;
867
868         if (zflag)
869                 memset(&zerostat, 0, len);
870         if (sysctlbyname("net.inet.pim.stats", &pimstat, &len,
871             zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
872                 if (errno != ENOENT)
873                         warn("sysctl: net.inet.pim.stats");
874                 return;
875         }
876
877         printf("%s:\n", name);
878
879 #define p(f, m) if (pimstat.f || sflag <= 1) \
880     printf(m, (uintmax_t)pimstat.f, plural(pimstat.f))
881 #define py(f, m) if (pimstat.f || sflag <= 1) \
882     printf(m, (uintmax_t)pimstat.f, pimstat.f != 1 ? "ies" : "y")
883         p(pims_rcv_total_msgs, "\t%ju message%s received\n");
884         p(pims_rcv_total_bytes, "\t%ju byte%s received\n");
885         p(pims_rcv_tooshort, "\t%ju message%s received with too few bytes\n");
886         p(pims_rcv_badsum, "\t%ju message%s received with bad checksum\n");
887         p(pims_rcv_badversion, "\t%ju message%s received with bad version\n");
888         p(pims_rcv_registers_msgs, "\t%ju data register message%s received\n");
889         p(pims_rcv_registers_bytes, "\t%ju data register byte%s received\n");
890         p(pims_rcv_registers_wrongiif, "\t%ju data register message%s received on wrong iif\n");
891         p(pims_rcv_badregisters, "\t%ju bad register%s received\n");
892         p(pims_snd_registers_msgs, "\t%ju data register message%s sent\n");
893         p(pims_snd_registers_bytes, "\t%ju data register byte%s sent\n");
894 #undef p
895 #undef py
896 }
897
898 /*
899  * Pretty print an Internet address (net address + port).
900  */
901 void
902 inetprint(struct in_addr *in, int port, const char *proto, int num_port)
903 {
904         struct servent *sp = NULL;
905         char line[80], *cp;
906         int width;
907
908         if (Wflag)
909             sprintf(line, "%s.", inetname(in));
910         else
911             sprintf(line, "%.*s.", (Aflag && !num_port) ? 12 : 16, inetname(in));
912         cp = strchr(line, '\0');
913         if (!num_port && port)
914                 sp = getservbyport((int)port, proto);
915         if (sp || port == 0)
916                 sprintf(cp, "%.15s ", sp ? sp->s_name : "*");
917         else
918                 sprintf(cp, "%d ", ntohs((u_short)port));
919         width = (Aflag && !Wflag) ? 17 : 21;
920         if (Wflag)
921             printf("%-*s ", width, line);
922         else
923             printf("%-*.*s ", width, width, line);
924 }
925
926 /*
927  * Construct an Internet address representation.
928  * If numeric_addr has been supplied, give
929  * numeric value, otherwise try for symbolic name.
930  */
931 char *
932 inetname(struct in_addr *inp)
933 {
934         char *cp;
935         static char line[MAXHOSTNAMELEN];
936         struct hostent *hp;
937         struct netent *np;
938
939         cp = NULL;
940         if (!numeric_addr && inp->s_addr != INADDR_ANY) {
941                 int net = inet_netof(*inp);
942                 int lna = inet_lnaof(*inp);
943
944                 if (lna == INADDR_ANY) {
945                         np = getnetbyaddr(net, AF_INET);
946                         if (np)
947                                 cp = np->n_name;
948                 }
949                 if (cp == NULL) {
950                         hp = gethostbyaddr(inp, sizeof (*inp), AF_INET);
951                         if (hp) {
952                                 cp = hp->h_name;
953                                 trimdomain(cp, strlen(cp));
954                         }
955                 }
956         }
957         if (inp->s_addr == INADDR_ANY)
958                 strcpy(line, "*");
959         else if (cp) {
960                 strncpy(line, cp, sizeof(line) - 1);
961                 line[sizeof(line) - 1] = '\0';
962         } else {
963                 inp->s_addr = ntohl(inp->s_addr);
964 #define C(x)    ((u_int)((x) & 0xff))
965                 sprintf(line, "%u.%u.%u.%u", C(inp->s_addr >> 24),
966                     C(inp->s_addr >> 16), C(inp->s_addr >> 8), C(inp->s_addr));
967         }
968         return (line);
969 }