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