nrelease - fix/improve livecd
[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), "%hd/%hd/%hd", 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         u_long state_count[TCP_NSTATES];
396         struct tcp_stats tcpstat, *stattmp;
397         struct tcp_stats zerostat[SMP_MAXCPU];
398         size_t len = sizeof(struct tcp_stats) * SMP_MAXCPU;
399         int cpucnt;
400         
401         if (zflag)
402                 memset(zerostat, 0, len);
403
404         if ((stattmp = malloc(len)) == NULL) {
405                 return;
406         } else {
407                 if (sysctlbyname("net.inet.tcp.stats", stattmp, &len,
408                         zflag ? zerostat : NULL, zflag ? len : 0) < 0) {
409                         warn("sysctl: net.inet.tcp.stats");
410                         free(stattmp);
411                         return;
412                 } else {
413                         if ((stattmp = realloc(stattmp, len)) == NULL) {
414                                 warn("tcp_stats");
415                                 return;
416                         }
417                 }
418         }
419         cpucnt = len / sizeof(struct tcp_stats);
420         tcp_stats_agg(stattmp, &tcpstat, cpucnt);
421
422 #ifdef INET6
423         if (tcp_done != 0)
424                 return;
425         else
426                 tcp_done = 1;
427 #endif
428
429         printf ("%s:\n", name);
430
431 #define p(f, m) if (tcpstat.f || sflag <= 1) \
432     printf(m, tcpstat.f, plural(tcpstat.f))
433 #define p1a(f, m) if (tcpstat.f || sflag <= 1) \
434     printf(m, tcpstat.f)
435 #define p2(f1, f2, m) if (tcpstat.f1 || tcpstat.f2 || sflag <= 1) \
436     printf(m, tcpstat.f1, plural(tcpstat.f1), tcpstat.f2, plural(tcpstat.f2))
437 #define p2a(f1, f2, m) if (tcpstat.f1 || tcpstat.f2 || sflag <= 1) \
438     printf(m, tcpstat.f1, plural(tcpstat.f1), tcpstat.f2)
439 #define p3(f, m) if (tcpstat.f || sflag <= 1) \
440     printf(m, tcpstat.f, plurales(tcpstat.f))
441
442         p(tcps_sndtotal, "\t%lu packet%s sent\n");
443         p2(tcps_sndpack,tcps_sndbyte,
444                 "\t\t%lu data packet%s (%lu byte%s)\n");
445         p2(tcps_sndrexmitpack, tcps_sndrexmitbyte,
446                 "\t\t%lu data packet%s (%lu byte%s) retransmitted\n");
447         p2(tcps_sndsackrtopack, tcps_sndsackrtobyte,
448                 "\t\t%lu data packet%s (%lu byte%s) retransmitted by SACK\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_sackrescue, tcps_sackrescue_try,
452                 "\t\t%lu SACK rescue packet%s sent (of %lu attempt%s)\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         p2(tcps_sndrtobad, tcps_eifelresponse,
457                 "\t\t%lu spurious RTO retransmit%s (%lu Eifel-response%s)\n");
458         p2a(tcps_sndfastrexmitbad, tcps_sndearlyrexmitbad,
459                 "\t\t%lu spurious Fast Retransmit%s (%lu early)\n");
460         p2a(tcps_eifeldetected, tcps_rttcantdetect,
461                 "\t\t%lu Eifel-detected spurious retransmit%s (%lu non-RTT)\n");
462         p(tcps_rttdetected, "\t\t%lu RTT-detected spurious retransmit%s\n");
463         p(tcps_mturesent, "\t\t%lu resend%s initiated by MTU discovery\n");
464         p(tcps_sndsackopt, "\t\t%lu SACK option%s sent\n");
465         p(tcps_snddsackopt, "\t\t%lu D-SACK option%s sent\n");
466         p2a(tcps_sndacks, tcps_delack,
467                 "\t\t%lu ack-only packet%s (%lu delayed)\n");
468         p(tcps_sndurg, "\t\t%lu URG only packet%s\n");
469         p(tcps_sndprobe, "\t\t%lu window probe packet%s\n");
470         p(tcps_sndwinup, "\t\t%lu window update packet%s\n");
471         p(tcps_sndctrl, "\t\t%lu control packet%s\n");
472         p(tcps_rcvtotal, "\t%lu packet%s received\n");
473         p2(tcps_rcvackpack, tcps_rcvackbyte, "\t\t%lu ack%s (for %lu byte%s)\n");
474         p(tcps_rcvdupack, "\t\t%lu duplicate ack%s\n");
475         p(tcps_rcvacktoomuch, "\t\t%lu ack%s for unsent data\n");
476         p2(tcps_rcvpack, tcps_rcvbyte,
477                 "\t\t%lu packet%s (%lu byte%s) received in-sequence\n");
478         p2(tcps_rcvduppack, tcps_rcvdupbyte,
479                 "\t\t%lu completely duplicate packet%s (%lu byte%s)\n");
480         p2(tcps_pawsdrop, tcps_pawsaccept,
481                 "\t\t%lu old duplicate packet%s (%lu packet%s accepted)\n");
482         p2(tcps_rcvpartduppack, tcps_rcvpartdupbyte,
483                 "\t\t%lu packet%s with some dup. data (%lu byte%s duped)\n");
484         p2(tcps_rcvoopack, tcps_rcvoobyte,
485                 "\t\t%lu out-of-order packet%s (%lu byte%s)\n");
486         p2(tcps_rcvpackafterwin, tcps_rcvbyteafterwin,
487                 "\t\t%lu packet%s (%lu byte%s) of data after window\n");
488         p(tcps_rcvwinprobe, "\t\t%lu window probe%s\n");
489         p(tcps_rcvwinupd, "\t\t%lu window update packet%s\n");
490         p(tcps_rcvafterclose, "\t\t%lu packet%s received after close\n");
491         p(tcps_rcvbadsum, "\t\t%lu discarded for bad checksum%s\n");
492         p(tcps_rcvbadoff, "\t\t%lu discarded for bad header offset field%s\n");
493         p1a(tcps_rcvshort, "\t\t%lu discarded because packet too short\n");
494         p(tcps_rcvbadsackopt, "\t\t%lu bad SACK option%s\n");
495         p1a(tcps_sackrenege, "\t\t%lu other side reneged\n");
496         p(tcps_connattempt, "\t%lu connection request%s\n");
497         p(tcps_accepts, "\t%lu connection accept%s\n");
498         p(tcps_badsyn, "\t%lu bad connection attempt%s\n");
499         p(tcps_listendrop, "\t%lu listen queue overflow%s\n");
500         p(tcps_connects, "\t%lu connection%s established (including accepts)\n");
501         p2(tcps_closed, tcps_drops,
502                 "\t%lu connection%s closed (including %lu drop%s)\n");
503         p(tcps_cachedrtt, "\t\t%lu connection%s updated cached RTT on close\n");
504         p(tcps_cachedrttvar, 
505           "\t\t%lu connection%s updated cached RTT variance on close\n");
506         p(tcps_cachedssthresh,
507           "\t\t%lu connection%s updated cached ssthresh on close\n");
508         p(tcps_conndrops, "\t%lu embryonic connection%s dropped\n");
509         p2(tcps_rttupdated, tcps_segstimed,
510                 "\t%lu segment%s updated rtt (of %lu attempt%s)\n");
511         p(tcps_rexmttimeo, "\t%lu retransmit timeout%s\n");
512         p(tcps_timeoutdrop, "\t\t%lu connection%s dropped by rexmit timeout\n");
513         p(tcps_persisttimeo, "\t%lu persist timeout%s\n");
514         p(tcps_persistdrop, "\t\t%lu connection%s dropped by persist timeout\n");
515         p(tcps_keeptimeo, "\t%lu keepalive timeout%s\n");
516         p(tcps_keepprobe, "\t\t%lu keepalive probe%s sent\n");
517         p(tcps_keepdrops, "\t\t%lu connection%s dropped by keepalive\n");
518         p(tcps_predack, "\t%lu correct ACK header prediction%s\n");
519         p(tcps_preddat, "\t%lu correct data packet header prediction%s\n");
520         p(tcps_sndidle, "\t%lu send idle%s\n");
521
522         p1a(tcps_sc_added, "\t%lu syncache entries added\n"); 
523         p1a(tcps_sc_retransmitted, "\t\t%lu retransmitted\n"); 
524         p1a(tcps_sc_dupsyn, "\t\t%lu dupsyn\n"); 
525         p1a(tcps_sc_dropped, "\t\t%lu dropped\n"); 
526         p1a(tcps_sc_completed, "\t\t%lu completed\n"); 
527         p1a(tcps_sc_bucketoverflow, "\t\t%lu bucket overflow\n"); 
528         p1a(tcps_sc_cacheoverflow, "\t\t%lu cache overflow\n"); 
529         p1a(tcps_sc_reset, "\t\t%lu reset\n"); 
530         p1a(tcps_sc_stale, "\t\t%lu stale\n"); 
531         p1a(tcps_sc_aborted, "\t\t%lu aborted\n"); 
532         p1a(tcps_sc_badack, "\t\t%lu badack\n"); 
533         p1a(tcps_sc_unreach, "\t\t%lu unreach\n"); 
534         p1a(tcps_sc_zonefail, "\t\t%lu zone failures\n"); 
535         p1a(tcps_sc_sendcookie, "\t\t%lu cookies sent\n"); 
536         p1a(tcps_sc_recvcookie, "\t\t%lu cookies received\n"); 
537
538         p(tcps_sacksbupdate, "\t%lu SACK scoreboard update%s\n");
539         p(tcps_sacksboverflow, "\t\t%lu overflow%s\n");
540         p(tcps_sacksbfailed, "\t\t%lu failure%s\n");
541         p(tcps_sacksbreused, "\t\t%lu record%s reused\n");
542         p(tcps_sacksbfast, "\t\t%lu record%s fast allocated\n");
543
544         free(stattmp);
545 #undef p
546 #undef p1a
547 #undef p2
548 #undef p2a
549 #undef p3
550
551         len = sizeof(state_count);
552         if (sysctlbyname("net.inet.tcp.state_count", state_count, &len, NULL, 0) == 0) {
553                 int s;
554
555                 for (s = TCPS_TERMINATING + 1; s < TCP_NSTATES; ++s) {
556                         printf("\t%lu connection%s in %s state\n", state_count[s],
557                             state_count[s] == 1 ? "" : "s", tcpstates[s]);
558                 }
559         }
560 }
561
562 /*
563  * Dump UDP statistics structure.
564  */
565 void
566 udp_stats(u_long off __unused, const char *name, int af1 __unused)
567 {
568         struct udpstat udpstat, *stattmp;
569         struct udpstat zerostat[SMP_MAXCPU];
570         size_t len = sizeof(struct udpstat) * SMP_MAXCPU;
571         int cpucnt;
572         u_long delivered;
573
574         if (zflag)
575                 memset(&zerostat, 0, len);
576
577         if ((stattmp = malloc(len)) == NULL) {
578                 return;
579         } else {
580                 if (sysctlbyname("net.inet.udp.stats", stattmp, &len,
581                         zflag ? zerostat : NULL, zflag ? len : 0) < 0) {
582                         warn("sysctl: net.inet.udp.stats");
583                         free(stattmp);
584                         return;
585                 } else {
586                         if ((stattmp = realloc(stattmp, len)) == NULL) {
587                                 warn("udp_stats");
588                                 return;
589                         }
590                 }
591         }
592         cpucnt = len / sizeof(struct udpstat);
593         udp_stats_agg(stattmp, &udpstat, cpucnt);
594
595 #ifdef INET6
596         if (udp_done != 0)
597                 return;
598         else
599                 udp_done = 1;
600 #endif
601
602         printf("%s:\n", name);
603 #define p(f, m) if (udpstat.f || sflag <= 1) \
604     printf(m, udpstat.f, plural(udpstat.f))
605 #define p1a(f, m) if (udpstat.f || sflag <= 1) \
606     printf(m, udpstat.f)
607         p(udps_ipackets, "\t%lu datagram%s received\n");
608         p1a(udps_hdrops, "\t%lu with incomplete header\n");
609         p1a(udps_badlen, "\t%lu with bad data length field\n");
610         p1a(udps_badsum, "\t%lu with bad checksum\n");
611         p1a(udps_nosum, "\t%lu with no checksum\n");
612         p1a(udps_noport, "\t%lu dropped due to no socket\n");
613         p(udps_noportbcast,
614             "\t%lu broadcast/multicast datagram%s dropped due to no socket\n");
615         p1a(udps_fullsock, "\t%lu dropped due to full socket buffers\n");
616         p1a(udpps_pcbhashmiss, "\t%lu not for hashed pcb\n");
617         delivered = udpstat.udps_ipackets -
618                     udpstat.udps_hdrops -
619                     udpstat.udps_badlen -
620                     udpstat.udps_badsum -
621                     udpstat.udps_noport -
622                     udpstat.udps_noportbcast -
623                     udpstat.udps_fullsock;
624         if (delivered || sflag <= 1)
625                 printf("\t%lu delivered\n", delivered);
626         p(udps_opackets, "\t%lu datagram%s output\n");
627 #undef p
628 #undef p1a
629 }
630
631 /* 
632  * Dump CARP statistics structure.
633  */
634 void
635 carp_stats(u_long off __unused, const char *name, int af1 __unused)
636 {
637        struct carpstats carpstat, zerostat;
638        size_t len = sizeof(struct carpstats);
639
640        if (zflag)
641                memset(&zerostat, 0, len);
642        if (sysctlbyname("net.inet.carp.stats", &carpstat, &len,
643            zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
644                warn("sysctl: net.inet.carp.stats");
645                return;
646        }
647
648        printf("%s:\n", name);
649
650 #define p(f, m) if (carpstat.f || sflag <= 1) \
651        printf(m, (uintmax_t)carpstat.f, plural((int)carpstat.f))
652 #define p2(f, m) if (carpstat.f || sflag <= 1) \
653        printf(m, (uintmax_t)carpstat.f)
654
655        p(carps_ipackets, "\t%ju packet%s received (IPv4)\n");
656        p(carps_ipackets6, "\t%ju packet%s received (IPv6)\n");
657        p(carps_badttl, "\t\t%ju packet%s discarded for wrong TTL\n");
658        p(carps_hdrops, "\t\t%ju packet%s shorter than header\n");
659        p(carps_badsum, "\t\t%ju discarded for bad checksum%s\n");
660        p(carps_badver, "\t\t%ju discarded packet%s with a bad version\n");
661        p2(carps_badlen, "\t\t%ju discarded because packet too short\n");
662        p2(carps_badauth, "\t\t%ju discarded for bad authentication\n");
663        p2(carps_badvhid, "\t\t%ju discarded for bad vhid\n");
664        p2(carps_badaddrs, "\t\t%ju discarded because of a bad address list\n");
665        p(carps_opackets, "\t%ju packet%s sent (IPv4)\n");
666        p(carps_opackets6, "\t%ju packet%s sent (IPv6)\n");
667        p2(carps_onomem, "\t\t%ju send failed due to mbuf memory error\n");
668 #if 0 /* not yet */
669        p(carps_ostates, "\t\t%s state update%s sent\n");
670 #endif
671 #undef p
672 #undef p2
673 }
674
675 /*
676  * Dump IP statistics structure.
677  */
678 void
679 ip_stats(u_long off __unused, const char *name, int af1 __unused)
680 {
681         struct ip_stats ipstat, *stattmp;
682         struct ip_stats zerostat[SMP_MAXCPU];
683         size_t len = sizeof(struct ip_stats) * SMP_MAXCPU;
684         int cpucnt;
685
686         if (zflag)
687                 memset(zerostat, 0, len);
688         if ((stattmp = malloc(len)) == NULL) {
689                 return;
690         } else {
691                 if (sysctlbyname("net.inet.ip.stats", stattmp, &len,
692                         zflag ? zerostat : NULL, zflag ? len : 0) < 0) {
693                                 warn("sysctl: net.inet.ip.stats");
694                                 free(stattmp);
695                                 return;
696                 } else {
697                         if ((stattmp = realloc(stattmp, len)) == NULL) {
698                                 warn("ip_stats");
699                                 return;
700                         }
701                 }
702         }
703         cpucnt = len / sizeof(struct ip_stats);
704         ip_stats_agg(stattmp, &ipstat, cpucnt);
705
706         printf("%s:\n", name);
707
708 #define p(f, m) if (ipstat.f || sflag <= 1) \
709     printf(m, ipstat.f, plural(ipstat.f))
710 #define p1a(f, m) if (ipstat.f || sflag <= 1) \
711     printf(m, ipstat.f)
712
713         p(ips_total, "\t%lu total packet%s received\n");
714         p(ips_badsum, "\t%lu bad header checksum%s\n");
715         p1a(ips_toosmall, "\t%lu with size smaller than minimum\n");
716         p1a(ips_tooshort, "\t%lu with data size < data length\n");
717         p1a(ips_toolong, "\t%lu with ip length > max ip packet size\n");
718         p1a(ips_badhlen, "\t%lu with header length < data size\n");
719         p1a(ips_badlen, "\t%lu with data length < header length\n");
720         p1a(ips_badoptions, "\t%lu with bad options\n");
721         p1a(ips_badvers, "\t%lu with incorrect version number\n");
722         p(ips_fragments, "\t%lu fragment%s received\n");
723         p(ips_fragdropped, "\t%lu fragment%s dropped (dup or out of space)\n");
724         p(ips_fragtimeout, "\t%lu fragment%s dropped after timeout\n");
725         p(ips_reassembled, "\t%lu packet%s reassembled ok\n");
726         p(ips_delivered, "\t%lu packet%s for this host\n");
727         p(ips_noproto, "\t%lu packet%s for unknown/unsupported protocol\n");
728         p(ips_forward, "\t%lu packet%s forwarded");
729         p(ips_fastforward, " (%lu packet%s fast forwarded)");
730         if (ipstat.ips_forward || sflag <= 1) 
731                 putchar('\n');
732         p(ips_cantforward, "\t%lu packet%s not forwardable\n");
733         p(ips_notmember,
734           "\t%lu packet%s received for unknown multicast group\n");
735         p(ips_redirectsent, "\t%lu redirect%s sent\n");
736         p(ips_localout, "\t%lu packet%s sent from this host\n");
737         p(ips_rawout, "\t%lu packet%s sent with fabricated ip header\n");
738         p(ips_odropped,
739           "\t%lu output packet%s dropped due to no bufs, etc.\n");
740         p(ips_noroute, "\t%lu output packet%s discarded due to no route\n");
741         p(ips_fragmented, "\t%lu output datagram%s fragmented\n");
742         p(ips_ofragments, "\t%lu fragment%s created\n");
743         p(ips_cantfrag, "\t%lu datagram%s that can't be fragmented\n");
744         p(ips_nogif, "\t%lu tunneling packet%s that can't find gif\n");
745         p(ips_badaddr, "\t%lu datagram%s with bad address in header\n");
746         free(stattmp);
747 #undef p
748 #undef p1a
749 }
750
751 static  const char *icmpnames[] = {
752         "echo reply",
753         "#1",
754         "#2",
755         "destination unreachable",
756         "source quench",
757         "routing redirect",
758         "#6",
759         "#7",
760         "echo",
761         "router advertisement",
762         "router solicitation",
763         "time exceeded",
764         "parameter problem",
765         "time stamp",
766         "time stamp reply",
767         "information request",
768         "information request reply",
769         "address mask request",
770         "address mask reply",
771 };
772
773 /*
774  * Dump ICMP statistics.
775  */
776 void
777 icmp_stats(u_long off __unused, const char *name, int af1 __unused)
778 {
779         struct icmpstat icmpstat, zerostat;
780         int i, first;
781         int mib[4];             /* CTL_NET + PF_INET + IPPROTO_ICMP + req */
782         size_t len;
783
784         mib[0] = CTL_NET;
785         mib[1] = PF_INET;
786         mib[2] = IPPROTO_ICMP;
787         mib[3] = ICMPCTL_STATS;
788
789         len = sizeof icmpstat;
790         if (zflag)
791                 memset(&zerostat, 0, len);
792         if (sysctl(mib, 4, &icmpstat, &len,
793             zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
794                 warn("sysctl: net.inet.icmp.stats");
795                 return;
796         }
797
798         printf("%s:\n", name);
799
800 #define p(f, m) if (icmpstat.f || sflag <= 1) \
801     printf(m, icmpstat.f, plural(icmpstat.f))
802 #define p1a(f, m) if (icmpstat.f || sflag <= 1) \
803     printf(m, icmpstat.f)
804 #define p2(f, m) if (icmpstat.f || sflag <= 1) \
805     printf(m, icmpstat.f, plurales(icmpstat.f))
806
807         p(icps_error, "\t%lu call%s to icmp_error\n");
808         p(icps_oldicmp,
809             "\t%lu error%s not generated 'cuz old message was icmp\n");
810         for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
811                 if (icmpstat.icps_outhist[i] != 0) {
812                         if (first) {
813                                 printf("\tOutput histogram:\n");
814                                 first = 0;
815                         }
816                         printf("\t\t%s: %lu\n", icmpnames[i],
817                                 icmpstat.icps_outhist[i]);
818                 }
819         p(icps_badcode, "\t%lu message%s with bad code fields\n");
820         p(icps_tooshort, "\t%lu message%s < minimum length\n");
821         p(icps_checksum, "\t%lu bad checksum%s\n");
822         p(icps_badlen, "\t%lu message%s with bad length\n");
823         p1a(icps_bmcastecho, "\t%lu multicast echo requests ignored\n");
824         p1a(icps_bmcasttstamp, "\t%lu multicast timestamp requests ignored\n");
825         for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
826                 if (icmpstat.icps_inhist[i] != 0) {
827                         if (first) {
828                                 printf("\tInput histogram:\n");
829                                 first = 0;
830                         }
831                         printf("\t\t%s: %lu\n", icmpnames[i],
832                                 icmpstat.icps_inhist[i]);
833                 }
834         p(icps_reflect, "\t%lu message response%s generated\n");
835         p2(icps_badaddr, "\t%lu invalid return address%s\n");
836         p(icps_noroute, "\t%lu no return route%s\n");
837 #undef p
838 #undef p1a
839 #undef p2
840         mib[3] = ICMPCTL_MASKREPL;
841         len = sizeof i;
842         if (sysctl(mib, 4, &i, &len, NULL, 0) < 0)
843                 return;
844         printf("\tICMP address mask responses are %sabled\n", 
845                i ? "en" : "dis");
846 }
847
848 /*
849  * Dump IGMP statistics structure.
850  */
851 void
852 igmp_stats(u_long off __unused, const char *name, int af1 __unused)
853 {
854         struct igmpstat igmpstat, zerostat;
855         size_t len = sizeof igmpstat;
856
857         if (zflag)
858                 memset(&zerostat, 0, len);
859         if (sysctlbyname("net.inet.igmp.stats", &igmpstat, &len,
860             zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
861                 warn("sysctl: net.inet.igmp.stats");
862                 return;
863         }
864
865         printf("%s:\n", name);
866
867 #define p(f, m) if (igmpstat.f || sflag <= 1) \
868     printf(m, igmpstat.f, plural(igmpstat.f))
869 #define py(f, m) if (igmpstat.f || sflag <= 1) \
870     printf(m, igmpstat.f, igmpstat.f != 1 ? "ies" : "y")
871         p(igps_rcv_total, "\t%u message%s received\n");
872         p(igps_rcv_tooshort, "\t%u message%s received with too few bytes\n");
873         p(igps_rcv_badsum, "\t%u message%s received with bad checksum\n");
874         py(igps_rcv_queries, "\t%u membership quer%s received\n");
875         py(igps_rcv_badqueries, "\t%u membership quer%s received with invalid field(s)\n");
876         p(igps_rcv_reports, "\t%u membership report%s received\n");
877         p(igps_rcv_badreports, "\t%u membership report%s received with invalid field(s)\n");
878         p(igps_rcv_ourreports, "\t%u membership report%s received for groups to which we belong\n");
879         p(igps_snd_reports, "\t%u membership report%s sent\n");
880 #undef p
881 #undef py
882 }
883
884 /*
885  * Dump PIM statistics structure.
886  */
887 void
888 pim_stats(u_long off __unused, const char *name, int af1 __unused)
889 {
890         struct pimstat pimstat, zerostat;
891         size_t len = sizeof pimstat;
892
893         if (zflag)
894                 memset(&zerostat, 0, len);
895         if (sysctlbyname("net.inet.pim.stats", &pimstat, &len,
896             zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
897                 if (errno != ENOENT)
898                         warn("sysctl: net.inet.pim.stats");
899                 return;
900         }
901
902         printf("%s:\n", name);
903
904 #define p(f, m) if (pimstat.f || sflag <= 1) \
905     printf(m, (uintmax_t)pimstat.f, plural(pimstat.f))
906 #define py(f, m) if (pimstat.f || sflag <= 1) \
907     printf(m, (uintmax_t)pimstat.f, pimstat.f != 1 ? "ies" : "y")
908         p(pims_rcv_total_msgs, "\t%ju message%s received\n");
909         p(pims_rcv_total_bytes, "\t%ju byte%s received\n");
910         p(pims_rcv_tooshort, "\t%ju message%s received with too few bytes\n");
911         p(pims_rcv_badsum, "\t%ju message%s received with bad checksum\n");
912         p(pims_rcv_badversion, "\t%ju message%s received with bad version\n");
913         p(pims_rcv_registers_msgs, "\t%ju data register message%s received\n");
914         p(pims_rcv_registers_bytes, "\t%ju data register byte%s received\n");
915         p(pims_rcv_registers_wrongiif, "\t%ju data register message%s received on wrong iif\n");
916         p(pims_rcv_badregisters, "\t%ju bad register%s received\n");
917         p(pims_snd_registers_msgs, "\t%ju data register message%s sent\n");
918         p(pims_snd_registers_bytes, "\t%ju data register byte%s sent\n");
919 #undef p
920 #undef py
921 }
922
923 /*
924  * Pretty print an Internet address (net address + port).
925  */
926 void
927 inetprint(struct in_addr *in, int port, const char *proto, int num_port)
928 {
929         struct servent *sp = NULL;
930         char line[80], *cp;
931         int width;
932
933         if (Wflag)
934             sprintf(line, "%s.", inetname(in));
935         else
936             sprintf(line, "%.*s.", (Aflag && !num_port) ? 12 : 16, inetname(in));
937         cp = strchr(line, '\0');
938         if (!num_port && port)
939                 sp = getservbyport((int)port, proto);
940         if (sp || port == 0)
941                 sprintf(cp, "%.15s ", sp ? sp->s_name : "*");
942         else
943                 sprintf(cp, "%d ", ntohs((u_short)port));
944         width = (Aflag && !Wflag) ? 17 : 21;
945         if (Wflag)
946             printf("%-*s ", width, line);
947         else
948             printf("%-*.*s ", width, width, line);
949 }
950
951 /*
952  * Construct an Internet address representation.
953  * If numeric_addr has been supplied, give
954  * numeric value, otherwise try for symbolic name.
955  */
956 char *
957 inetname(struct in_addr *inp)
958 {
959         char *cp;
960         static char line[MAXHOSTNAMELEN];
961         struct hostent *hp;
962         struct netent *np;
963
964         cp = NULL;
965         if (!numeric_addr && inp->s_addr != INADDR_ANY) {
966                 int net = inet_netof(*inp);
967                 int lna = inet_lnaof(*inp);
968
969                 if (lna == INADDR_ANY) {
970                         np = getnetbyaddr(net, AF_INET);
971                         if (np)
972                                 cp = np->n_name;
973                 }
974                 if (cp == NULL) {
975                         hp = gethostbyaddr(inp, sizeof (*inp), AF_INET);
976                         if (hp) {
977                                 cp = hp->h_name;
978                                 trimdomain(cp, strlen(cp));
979                         }
980                 }
981         }
982         if (inp->s_addr == INADDR_ANY)
983                 strcpy(line, "*");
984         else if (cp) {
985                 strncpy(line, cp, sizeof(line) - 1);
986                 line[sizeof(line) - 1] = '\0';
987         } else {
988                 inp->s_addr = ntohl(inp->s_addr);
989 #define C(x)    ((u_int)((x) & 0xff))
990                 sprintf(line, "%u.%u.%u.%u", C(inp->s_addr >> 24),
991                     C(inp->s_addr >> 16), C(inp->s_addr >> 8), C(inp->s_addr));
992         }
993         return (line);
994 }