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