Merge from vendor branch TCPDUMP:
[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.13 2004/05/03 15:18:25 hmp 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 #define CPU_STATS_FUNC(proto,type)                            \
344 static void                                                   \
345 proto ##_stats_agg(type *ary, type *ttl, int cpucnt)          \
346 {                                                             \
347     int i, off, siz;                                          \
348     siz = sizeof(type);                                       \
349                                                               \
350     if (!ary && !ttl)                                         \
351         return;                                               \
352                                                               \
353     bzero(ttl, siz);                                          \
354     if (cpucnt == 1) {                                        \
355         *ttl = ary[0];                                        \
356     } else {                                                  \
357         for (i = 0; i < cpucnt; ++i) {                        \
358             for (off = 0; off < siz; off += sizeof(u_long)) { \
359                 *(u_long *)((char *)(*(&ttl)) + off) +=       \
360                 *(u_long *)((char *)&ary[i] + off);           \
361             }                                                 \
362         }                                                     \
363     }                                                         \
364 }
365 CPU_STATS_FUNC(tcp, struct tcp_stats);
366 CPU_STATS_FUNC(ip, struct ip_stats);
367
368 /*
369  * Dump TCP statistics structure.
370  */
371 void
372 tcp_stats(u_long off __unused, char *name, int af __unused)
373 {
374         struct tcp_stats tcpstat, *stattmp;
375         struct tcp_stats zerostat[SMP_MAXCPU];
376         size_t len = sizeof(struct tcp_stats) * SMP_MAXCPU;
377         int cpucnt;
378         
379         if (zflag)
380                 memset(zerostat, 0, len);
381
382         if ((stattmp = malloc(len)) == NULL) {
383                 return;
384         } else {
385                 if (sysctlbyname("net.inet.tcp.stats", stattmp, &len,
386                         zflag ? zerostat : NULL, zflag ? len : 0) < 0) {
387                         warn("sysctl: net.inet.tcp.stats");
388                         free(stattmp);
389                         return;
390                 } else {
391                         if ((stattmp = realloc(stattmp, len)) == NULL) {
392                                 warn("tcp_stats");
393                                 return;
394                         }
395                 }
396         }
397         cpucnt = len / sizeof(struct tcp_stats);
398         tcp_stats_agg(stattmp, &tcpstat, cpucnt);
399
400 #ifdef INET6
401         if (tcp_done != 0)
402                 return;
403         else
404                 tcp_done = 1;
405 #endif
406
407         printf ("%s:\n", name);
408
409 #define p(f, m) if (tcpstat.f || sflag <= 1) \
410     printf(m, tcpstat.f, plural(tcpstat.f))
411 #define p1a(f, m) if (tcpstat.f || sflag <= 1) \
412     printf(m, tcpstat.f)
413 #define p2(f1, f2, m) if (tcpstat.f1 || tcpstat.f2 || sflag <= 1) \
414     printf(m, tcpstat.f1, plural(tcpstat.f1), tcpstat.f2, plural(tcpstat.f2))
415 #define p2a(f1, f2, m) if (tcpstat.f1 || tcpstat.f2 || sflag <= 1) \
416     printf(m, tcpstat.f1, plural(tcpstat.f1), tcpstat.f2)
417 #define p3(f, m) if (tcpstat.f || sflag <= 1) \
418     printf(m, tcpstat.f, plurales(tcpstat.f))
419
420         p(tcps_sndtotal, "\t%lu packet%s sent\n");
421         p2(tcps_sndpack,tcps_sndbyte,
422                 "\t\t%lu data packet%s (%lu byte%s)\n");
423         p2(tcps_sndrexmitpack, tcps_sndrexmitbyte,
424                 "\t\t%lu data packet%s (%lu byte%s) retransmitted\n");
425         p2a(tcps_sndfastrexmit, tcps_sndearlyrexmit,
426                 "\t\t%lu Fast Retransmit%s (%lu early)\n");
427         p(tcps_sndlimited, "\t\t%lu packet%s sent by Limited Transmit\n");
428         p(tcps_sndrtobad, "\t\t%lu spurious RTO retransmit%s\n");
429         p2a(tcps_sndfastrexmitbad, tcps_sndearlyrexmitbad,
430                 "\t\t%lu spurious Fast Retransmit%s (%lu early)\n");
431         p(tcps_eifeldetected, "\t\t%lu Eifel-detected spurious retransmit%s\n");
432         p(tcps_rttdetected, "\t\t%lu RTT-detected spurious retransmit%s\n");
433         p(tcps_mturesent, "\t\t%lu resend%s initiated by MTU discovery\n");
434         p2a(tcps_sndacks, tcps_delack,
435                 "\t\t%lu ack-only packet%s (%lu delayed)\n");
436         p(tcps_sndurg, "\t\t%lu URG only packet%s\n");
437         p(tcps_sndprobe, "\t\t%lu window probe packet%s\n");
438         p(tcps_sndwinup, "\t\t%lu window update packet%s\n");
439         p(tcps_sndctrl, "\t\t%lu control packet%s\n");
440         p(tcps_rcvtotal, "\t%lu packet%s received\n");
441         p2(tcps_rcvackpack, tcps_rcvackbyte, "\t\t%lu ack%s (for %lu byte%s)\n");
442         p(tcps_rcvdupack, "\t\t%lu duplicate ack%s\n");
443         p(tcps_rcvacktoomuch, "\t\t%lu ack%s for unsent data\n");
444         p2(tcps_rcvpack, tcps_rcvbyte,
445                 "\t\t%lu packet%s (%lu byte%s) received in-sequence\n");
446         p2(tcps_rcvduppack, tcps_rcvdupbyte,
447                 "\t\t%lu completely duplicate packet%s (%lu byte%s)\n");
448         p(tcps_pawsdrop, "\t\t%lu old duplicate packet%s\n");
449         p2(tcps_rcvpartduppack, tcps_rcvpartdupbyte,
450                 "\t\t%lu packet%s with some dup. data (%lu byte%s duped)\n");
451         p2(tcps_rcvoopack, tcps_rcvoobyte,
452                 "\t\t%lu out-of-order packet%s (%lu byte%s)\n");
453         p2(tcps_rcvpackafterwin, tcps_rcvbyteafterwin,
454                 "\t\t%lu packet%s (%lu byte%s) of data after window\n");
455         p(tcps_rcvwinprobe, "\t\t%lu window probe%s\n");
456         p(tcps_rcvwinupd, "\t\t%lu window update packet%s\n");
457         p(tcps_rcvafterclose, "\t\t%lu packet%s received after close\n");
458         p(tcps_rcvbadsum, "\t\t%lu discarded for bad checksum%s\n");
459         p(tcps_rcvbadoff, "\t\t%lu discarded for bad header offset field%s\n");
460         p1a(tcps_rcvshort, "\t\t%lu discarded because packet too short\n");
461         p(tcps_connattempt, "\t%lu connection request%s\n");
462         p(tcps_accepts, "\t%lu connection accept%s\n");
463         p(tcps_badsyn, "\t%lu bad connection attempt%s\n");
464         p(tcps_listendrop, "\t%lu listen queue overflow%s\n");
465         p(tcps_connects, "\t%lu connection%s established (including accepts)\n");
466         p2(tcps_closed, tcps_drops,
467                 "\t%lu connection%s closed (including %lu drop%s)\n");
468         p(tcps_cachedrtt, "\t\t%lu connection%s updated cached RTT on close\n");
469         p(tcps_cachedrttvar, 
470           "\t\t%lu connection%s updated cached RTT variance on close\n");
471         p(tcps_cachedssthresh,
472           "\t\t%lu connection%s updated cached ssthresh on close\n");
473         p(tcps_conndrops, "\t%lu embryonic connection%s dropped\n");
474         p2(tcps_rttupdated, tcps_segstimed,
475                 "\t%lu segment%s updated rtt (of %lu attempt%s)\n");
476         p(tcps_rexmttimeo, "\t%lu retransmit timeout%s\n");
477         p(tcps_timeoutdrop, "\t\t%lu connection%s dropped by rexmit timeout\n");
478         p(tcps_persisttimeo, "\t%lu persist timeout%s\n");
479         p(tcps_persistdrop, "\t\t%lu connection%s dropped by persist timeout\n");
480         p(tcps_keeptimeo, "\t%lu keepalive timeout%s\n");
481         p(tcps_keepprobe, "\t\t%lu keepalive probe%s sent\n");
482         p(tcps_keepdrops, "\t\t%lu connection%s dropped by keepalive\n");
483         p(tcps_predack, "\t%lu correct ACK header prediction%s\n");
484         p(tcps_preddat, "\t%lu correct data packet header prediction%s\n");
485
486         p(tcps_sc_added, "\t%lu syncache entries added\n"); 
487         p(tcps_sc_retransmitted, "\t\t%lu retransmitted\n"); 
488         p(tcps_sc_dupsyn, "\t\t%lu dupsyn\n"); 
489         p(tcps_sc_dropped, "\t\t%lu dropped\n"); 
490         p(tcps_sc_completed, "\t\t%lu completed\n"); 
491         p(tcps_sc_bucketoverflow, "\t\t%lu bucket overflow\n"); 
492         p(tcps_sc_cacheoverflow, "\t\t%lu cache overflow\n"); 
493         p(tcps_sc_reset, "\t\t%lu reset\n"); 
494         p(tcps_sc_stale, "\t\t%lu stale\n"); 
495         p(tcps_sc_aborted, "\t\t%lu aborted\n"); 
496         p(tcps_sc_badack, "\t\t%lu badack\n"); 
497         p(tcps_sc_unreach, "\t\t%lu unreach\n"); 
498         p(tcps_sc_zonefail, "\t\t%lu zone failures\n"); 
499         p(tcps_sc_sendcookie, "\t%lu cookies sent\n"); 
500         p(tcps_sc_recvcookie, "\t%lu cookies received\n"); 
501         free(stattmp);
502 #undef p
503 #undef p1a
504 #undef p2
505 #undef p2a
506 #undef p3
507 }
508
509 /*
510  * Dump UDP statistics structure.
511  */
512 void
513 udp_stats(u_long off __unused, char *name, int af __unused)
514 {
515         struct udpstat udpstat, zerostat;
516         size_t len = sizeof udpstat;
517         u_long delivered;
518
519         if (zflag)
520                 memset(&zerostat, 0, len);
521         if (sysctlbyname("net.inet.udp.stats", &udpstat, &len,
522             zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
523                 warn("sysctl: net.inet.udp.stats");
524                 return;
525         }
526
527 #ifdef INET6
528         if (udp_done != 0)
529                 return;
530         else
531                 udp_done = 1;
532 #endif
533
534         printf("%s:\n", name);
535 #define p(f, m) if (udpstat.f || sflag <= 1) \
536     printf(m, udpstat.f, plural(udpstat.f))
537 #define p1a(f, m) if (udpstat.f || sflag <= 1) \
538     printf(m, udpstat.f)
539         p(udps_ipackets, "\t%lu datagram%s received\n");
540         p1a(udps_hdrops, "\t%lu with incomplete header\n");
541         p1a(udps_badlen, "\t%lu with bad data length field\n");
542         p1a(udps_badsum, "\t%lu with bad checksum\n");
543         p1a(udps_nosum, "\t%lu with no checksum\n");
544         p1a(udps_noport, "\t%lu dropped due to no socket\n");
545         p(udps_noportbcast,
546             "\t%lu broadcast/multicast datagram%s dropped due to no socket\n");
547         p1a(udps_fullsock, "\t%lu dropped due to full socket buffers\n");
548         p1a(udpps_pcbhashmiss, "\t%lu not for hashed pcb\n");
549         delivered = udpstat.udps_ipackets -
550                     udpstat.udps_hdrops -
551                     udpstat.udps_badlen -
552                     udpstat.udps_badsum -
553                     udpstat.udps_noport -
554                     udpstat.udps_noportbcast -
555                     udpstat.udps_fullsock;
556         if (delivered || sflag <= 1)
557                 printf("\t%lu delivered\n", delivered);
558         p(udps_opackets, "\t%lu datagram%s output\n");
559 #undef p
560 #undef p1a
561 }
562
563 /*
564  * Dump IP statistics structure.
565  */
566 void
567 ip_stats(u_long off __unused, char *name, int af __unused)
568 {
569         struct ip_stats ipstat, *stattmp;
570         struct ip_stats zerostat[SMP_MAXCPU];
571         size_t len = sizeof(struct ip_stats) * SMP_MAXCPU;
572         int cpucnt;
573
574         if (zflag)
575                 memset(zerostat, 0, len);
576         if ((stattmp = malloc(len)) == NULL) {
577                 return;
578         } else {
579                 if (sysctlbyname("net.inet.ip.stats", stattmp, &len,
580                         zflag ? zerostat : NULL, zflag ? len : 0) < 0) {
581                                 warn("sysctl: net.inet.ip.stats");
582                                 free(stattmp);
583                                 return;
584                 } else {
585                         if ((stattmp = realloc(stattmp, len)) == NULL) {
586                                 warn("ip_stats");
587                                 return;
588                         }
589                 }
590         }
591         cpucnt = len / sizeof(struct ip_stats);
592         ip_stats_agg(stattmp, &ipstat, cpucnt);
593
594         printf("%s:\n", name);
595
596 #define p(f, m) if (ipstat.f || sflag <= 1) \
597     printf(m, ipstat.f, plural(ipstat.f))
598 #define p1a(f, m) if (ipstat.f || sflag <= 1) \
599     printf(m, ipstat.f)
600
601         p(ips_total, "\t%lu total packet%s received\n");
602         p(ips_badsum, "\t%lu bad header checksum%s\n");
603         p1a(ips_toosmall, "\t%lu with size smaller than minimum\n");
604         p1a(ips_tooshort, "\t%lu with data size < data length\n");
605         p1a(ips_toolong, "\t%lu with ip length > max ip packet size\n");
606         p1a(ips_badhlen, "\t%lu with header length < data size\n");
607         p1a(ips_badlen, "\t%lu with data length < header length\n");
608         p1a(ips_badoptions, "\t%lu with bad options\n");
609         p1a(ips_badvers, "\t%lu with incorrect version number\n");
610         p(ips_fragments, "\t%lu fragment%s received\n");
611         p(ips_fragdropped, "\t%lu fragment%s dropped (dup or out of space)\n");
612         p(ips_fragtimeout, "\t%lu fragment%s dropped after timeout\n");
613         p(ips_reassembled, "\t%lu packet%s reassembled ok\n");
614         p(ips_delivered, "\t%lu packet%s for this host\n");
615         p(ips_noproto, "\t%lu packet%s for unknown/unsupported protocol\n");
616         p(ips_forward, "\t%lu packet%s forwarded");
617         p(ips_fastforward, " (%lu packet%s fast forwarded)");
618         if (ipstat.ips_forward || sflag <= 1) 
619                 putchar('\n');
620         p(ips_cantforward, "\t%lu packet%s not forwardable\n");
621         p(ips_notmember,
622           "\t%lu packet%s received for unknown multicast group\n");
623         p(ips_redirectsent, "\t%lu redirect%s sent\n");
624         p(ips_localout, "\t%lu packet%s sent from this host\n");
625         p(ips_rawout, "\t%lu packet%s sent with fabricated ip header\n");
626         p(ips_odropped,
627           "\t%lu output packet%s dropped due to no bufs, etc.\n");
628         p(ips_noroute, "\t%lu output packet%s discarded due to no route\n");
629         p(ips_fragmented, "\t%lu output datagram%s fragmented\n");
630         p(ips_ofragments, "\t%lu fragment%s created\n");
631         p(ips_cantfrag, "\t%lu datagram%s that can't be fragmented\n");
632         p(ips_nogif, "\t%lu tunneling packet%s that can't find gif\n");
633         p(ips_badaddr, "\t%lu datagram%s with bad address in header\n");
634         free(stattmp);
635 #undef p
636 #undef p1a
637 }
638
639 static  char *icmpnames[] = {
640         "echo reply",
641         "#1",
642         "#2",
643         "destination unreachable",
644         "source quench",
645         "routing redirect",
646         "#6",
647         "#7",
648         "echo",
649         "router advertisement",
650         "router solicitation",
651         "time exceeded",
652         "parameter problem",
653         "time stamp",
654         "time stamp reply",
655         "information request",
656         "information request reply",
657         "address mask request",
658         "address mask reply",
659 };
660
661 /*
662  * Dump ICMP statistics.
663  */
664 void
665 icmp_stats(u_long off __unused, char *name, int af __unused)
666 {
667         struct icmpstat icmpstat, zerostat;
668         int i, first;
669         int mib[4];             /* CTL_NET + PF_INET + IPPROTO_ICMP + req */
670         size_t len;
671
672         mib[0] = CTL_NET;
673         mib[1] = PF_INET;
674         mib[2] = IPPROTO_ICMP;
675         mib[3] = ICMPCTL_STATS;
676
677         len = sizeof icmpstat;
678         if (zflag)
679                 memset(&zerostat, 0, len);
680         if (sysctl(mib, 4, &icmpstat, &len,
681             zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
682                 warn("sysctl: net.inet.icmp.stats");
683                 return;
684         }
685
686         printf("%s:\n", name);
687
688 #define p(f, m) if (icmpstat.f || sflag <= 1) \
689     printf(m, icmpstat.f, plural(icmpstat.f))
690 #define p1a(f, m) if (icmpstat.f || sflag <= 1) \
691     printf(m, icmpstat.f)
692 #define p2(f, m) if (icmpstat.f || sflag <= 1) \
693     printf(m, icmpstat.f, plurales(icmpstat.f))
694
695         p(icps_error, "\t%lu call%s to icmp_error\n");
696         p(icps_oldicmp,
697             "\t%lu error%s not generated 'cuz old message was icmp\n");
698         for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
699                 if (icmpstat.icps_outhist[i] != 0) {
700                         if (first) {
701                                 printf("\tOutput histogram:\n");
702                                 first = 0;
703                         }
704                         printf("\t\t%s: %lu\n", icmpnames[i],
705                                 icmpstat.icps_outhist[i]);
706                 }
707         p(icps_badcode, "\t%lu message%s with bad code fields\n");
708         p(icps_tooshort, "\t%lu message%s < minimum length\n");
709         p(icps_checksum, "\t%lu bad checksum%s\n");
710         p(icps_badlen, "\t%lu message%s with bad length\n");
711         p1a(icps_bmcastecho, "\t%lu multicast echo requests ignored\n");
712         p1a(icps_bmcasttstamp, "\t%lu multicast timestamp requests ignored\n");
713         for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
714                 if (icmpstat.icps_inhist[i] != 0) {
715                         if (first) {
716                                 printf("\tInput histogram:\n");
717                                 first = 0;
718                         }
719                         printf("\t\t%s: %lu\n", icmpnames[i],
720                                 icmpstat.icps_inhist[i]);
721                 }
722         p(icps_reflect, "\t%lu message response%s generated\n");
723         p2(icps_badaddr, "\t%lu invalid return address%s\n");
724         p(icps_noroute, "\t%lu no return route%s\n");
725 #undef p
726 #undef p1a
727 #undef p2
728         mib[3] = ICMPCTL_MASKREPL;
729         len = sizeof i;
730         if (sysctl(mib, 4, &i, &len, (void *)0, 0) < 0)
731                 return;
732         printf("\tICMP address mask responses are %sabled\n", 
733                i ? "en" : "dis");
734 }
735
736 /*
737  * Dump IGMP statistics structure.
738  */
739 void
740 igmp_stats(u_long off __unused, char *name, int af __unused)
741 {
742         struct igmpstat igmpstat, zerostat;
743         size_t len = sizeof igmpstat;
744
745         if (zflag)
746                 memset(&zerostat, 0, len);
747         if (sysctlbyname("net.inet.igmp.stats", &igmpstat, &len,
748             zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
749                 warn("sysctl: net.inet.igmp.stats");
750                 return;
751         }
752
753         printf("%s:\n", name);
754
755 #define p(f, m) if (igmpstat.f || sflag <= 1) \
756     printf(m, igmpstat.f, plural(igmpstat.f))
757 #define py(f, m) if (igmpstat.f || sflag <= 1) \
758     printf(m, igmpstat.f, igmpstat.f != 1 ? "ies" : "y")
759         p(igps_rcv_total, "\t%u message%s received\n");
760         p(igps_rcv_tooshort, "\t%u message%s received with too few bytes\n");
761         p(igps_rcv_badsum, "\t%u message%s received with bad checksum\n");
762         py(igps_rcv_queries, "\t%u membership quer%s received\n");
763         py(igps_rcv_badqueries, "\t%u membership quer%s received with invalid field(s)\n");
764         p(igps_rcv_reports, "\t%u membership report%s received\n");
765         p(igps_rcv_badreports, "\t%u membership report%s received with invalid field(s)\n");
766         p(igps_rcv_ourreports, "\t%u membership report%s received for groups to which we belong\n");
767         p(igps_snd_reports, "\t%u membership report%s sent\n");
768 #undef p
769 #undef py
770 }
771
772 /*
773  * Dump PIM statistics structure.
774  */
775 void
776 pim_stats(u_long off __unused, char *name, int af1 __unused)
777 {
778         struct pimstat pimstat, zerostat;
779         size_t len = sizeof pimstat;
780
781         if (zflag)
782                 memset(&zerostat, 0, len);
783         if (sysctlbyname("net.inet.pim.stats", &pimstat, &len,
784             zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
785                 if (errno != ENOENT)
786                         warn("sysctl: net.inet.pim.stats");
787                 return;
788         }
789
790         printf("%s:\n", name);
791
792 #define p(f, m) if (pimstat.f || sflag <= 1) \
793     printf(m, pimstat.f, plural(pimstat.f))
794 #define py(f, m) if (pimstat.f || sflag <= 1) \
795     printf(m, pimstat.f, pimstat.f != 1 ? "ies" : "y")
796         p(pims_rcv_total_msgs, "\t%llu message%s received\n");
797         p(pims_rcv_total_bytes, "\t%llu byte%s received\n");
798         p(pims_rcv_tooshort, "\t%llu message%s received with too few bytes\n");
799         p(pims_rcv_badsum, "\t%llu message%s received with bad checksum\n");
800         p(pims_rcv_badversion, "\t%llu message%s received with bad version\n");
801         p(pims_rcv_registers_msgs, "\t%llu data register message%s received\n");
802         p(pims_rcv_registers_bytes, "\t%llu data register byte%s received\n");
803         p(pims_rcv_registers_wrongiif, "\t%llu data register message%s received on wrong iif\n");
804         p(pims_rcv_badregisters, "\t%llu bad register%s received\n");
805         p(pims_snd_registers_msgs, "\t%llu data register message%s sent\n");
806         p(pims_snd_registers_bytes, "\t%llu data register byte%s sent\n");
807 #undef p
808 #undef py
809 }
810
811 /*
812  * Pretty print an Internet address (net address + port).
813  */
814 void
815 inetprint(struct in_addr *in, int port, char *proto, int numeric_port)
816 {
817         struct servent *sp = 0;
818         char line[80], *cp;
819         int width;
820
821         if (Wflag)
822             sprintf(line, "%s.", inetname(in));
823         else
824             sprintf(line, "%.*s.", (Aflag && !numeric_port) ? 12 : 16, inetname(in));
825         cp = index(line, '\0');
826         if (!numeric_port && port)
827                 sp = getservbyport((int)port, proto);
828         if (sp || port == 0)
829                 sprintf(cp, "%.15s ", sp ? sp->s_name : "*");
830         else
831                 sprintf(cp, "%d ", ntohs((u_short)port));
832         width = (Aflag && !Wflag) ? 18 : 22;
833         if (Wflag)
834             printf("%-*s ", width, line);
835         else
836             printf("%-*.*s ", width, width, line);
837 }
838
839 /*
840  * Construct an Internet address representation.
841  * If numeric_addr has been supplied, give
842  * numeric value, otherwise try for symbolic name.
843  */
844 char *
845 inetname(struct in_addr *inp)
846 {
847         register char *cp;
848         static char line[MAXHOSTNAMELEN];
849         struct hostent *hp;
850         struct netent *np;
851
852         cp = 0;
853         if (!numeric_addr && inp->s_addr != INADDR_ANY) {
854                 int net = inet_netof(*inp);
855                 int lna = inet_lnaof(*inp);
856
857                 if (lna == INADDR_ANY) {
858                         np = getnetbyaddr(net, AF_INET);
859                         if (np)
860                                 cp = np->n_name;
861                 }
862                 if (cp == 0) {
863                         hp = gethostbyaddr((char *)inp, sizeof (*inp), AF_INET);
864                         if (hp) {
865                                 cp = hp->h_name;
866                                 trimdomain(cp, strlen(cp));
867                         }
868                 }
869         }
870         if (inp->s_addr == INADDR_ANY)
871                 strcpy(line, "*");
872         else if (cp) {
873                 strncpy(line, cp, sizeof(line) - 1);
874                 line[sizeof(line) - 1] = '\0';
875         } else {
876                 inp->s_addr = ntohl(inp->s_addr);
877 #define C(x)    ((u_int)((x) & 0xff))
878                 sprintf(line, "%u.%u.%u.%u", C(inp->s_addr >> 24),
879                     C(inp->s_addr >> 16), C(inp->s_addr >> 8), C(inp->s_addr));
880         }
881         return (line);
882 }