Remove the userland visible part of the socket generation counting.
[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.16 2004/12/20 11:03:16 joerg 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, const char *, int);
82 #ifdef INET6
83 extern void     inet6print (struct in6_addr *, int, const 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
94 static int ppr_first = 1;
95 static void outputpcb(int proto, const char *name, struct inpcb *inp, struct xsocket *so, struct tcpcb *tp);
96
97 void
98 protopr(u_long proto, char *name, int af)
99 {
100         int istcp;
101         int i;
102         void *buf;
103         const char *mibvar;
104         size_t len;
105
106         istcp = 0;
107         switch (proto) {
108         case IPPROTO_TCP:
109 #ifdef INET6
110                 if (tcp_done != 0)
111                         return;
112                 else
113                         tcp_done = 1;
114 #endif
115                 istcp = 1;
116                 mibvar = "net.inet.tcp.pcblist";
117                 break;
118         case IPPROTO_UDP:
119 #ifdef INET6
120                 if (udp_done != 0)
121                         return;
122                 else
123                         udp_done = 1;
124 #endif
125                 mibvar = "net.inet.udp.pcblist";
126                 break;
127         case IPPROTO_DIVERT:
128                 mibvar = "net.inet.divert.pcblist";
129                 break;
130         default:
131                 mibvar = "net.inet.raw.pcblist";
132                 break;
133         }
134         len = 0;
135         if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) {
136                 if (errno != ENOENT)
137                         warn("sysctl: %s", mibvar);
138                 return;
139         }
140         if (len == 0)
141                 return;
142         if ((buf = malloc(len)) == 0) {
143                 warn("malloc %lu bytes", (u_long)len);
144                 return;
145         }
146         if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) {
147                 warn("sysctl: %s", mibvar);
148                 free(buf);
149                 return;
150         }
151
152         if (istcp) {
153                 struct xtcpcb *tcp = buf;
154                 len /= sizeof(*tcp);
155                 for (i = 0; i < len; i++) {
156                         if (tcp[i].xt_len != sizeof(*tcp))
157                                 break;
158                         outputpcb(proto, name, &tcp[i].xt_inp,
159                                   &tcp[i].xt_socket, &tcp[i].xt_tp);
160                 }
161         } else {
162                 struct xinpcb *in = buf;
163                 len /= sizeof(*in);
164                 for (i = 0; i < len; i++) {
165                         if (in[i].xi_len != sizeof(*in))
166                                 break;
167                         outputpcb(proto, name, &in[i].xi_inp,
168                                   &in[i].xi_socket, NULL);
169                 }
170         }
171         free(buf);
172 }
173
174 static void
175 outputpcb(int proto, const char *name, struct inpcb *inp, struct xsocket *so, struct tcpcb *tp)
176 {
177         const char *vchar;
178
179         /* Ignore sockets for protocols other than the desired one. */
180         if (so->xso_protocol != (int)proto)
181                 return;
182
183         if ((af == AF_INET && (inp->inp_vflag & INP_IPV4) == 0)
184 #ifdef INET6
185             || (af == AF_INET6 && (inp->inp_vflag & INP_IPV6) == 0)
186 #endif /* INET6 */
187             || (af == AF_UNSPEC && ((inp->inp_vflag & INP_IPV4) == 0
188 #ifdef INET6
189                 && (inp->inp_vflag & INP_IPV6) == 0
190 #endif /* INET6 */
191                 ))
192             ) {
193                 return;
194         }
195         if (!aflag && ( 
196                 (af == AF_INET && inet_lnaof(inp->inp_laddr) == INADDR_ANY)
197 #ifdef INET6
198             || (af == AF_INET6 && IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr))
199 #endif /* INET6 */
200             || (af == AF_UNSPEC && (((inp->inp_vflag & INP_IPV4) != 0 &&
201                 inet_lnaof(inp->inp_laddr) == INADDR_ANY)
202 #ifdef INET6
203             || ((inp->inp_vflag & INP_IPV6) != 0 &&
204                 IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr))
205 #endif
206                   ))
207              )) {
208                 return;
209         }
210
211         if (ppr_first) {
212                 if (!Lflag) {
213                         printf("Active Internet connections");
214                         if (aflag)
215                                 printf(" (including servers)");
216                 } else {
217                         printf("Current listen queue sizes "
218                                 "(qlen/incqlen/maxqlen)");
219                 }
220                 putchar('\n');
221                 if (Aflag)
222                         printf("%-8.8s ", "Socket");
223                 if (Lflag) {
224                         printf("%-5.5s %-14.14s %-22.22s\n",
225                                 "Proto", "Listen", "Local Address");
226                 } else {
227                         printf((Aflag && !Wflag) ?
228                             "%-5.5s %-6.6s %-6.6s %-17.17s %-17.17s %s\n" :
229                             "%-5.5s %-6.6s %-6.6s %-21.21s %-21.21s %s\n",
230                             "Proto", "Recv-Q", "Send-Q",
231                             "Local Address", "Foreign Address",
232                             "(state)");
233                 }
234                 ppr_first = 0;
235         }
236         if (Lflag && so->so_qlimit == 0)
237                 return;
238         if (Aflag) {
239                 if (tp)
240                         printf("%8lx ", (u_long)inp->inp_ppcb);
241                 else
242                         printf("%8lx ", (u_long)so->so_pcb);
243         }
244 #ifdef INET6
245         if ((inp->inp_vflag & INP_IPV6) != 0)
246                 vchar = ((inp->inp_vflag & INP_IPV4) != 0) ? "46" : "6 ";
247         else
248 #endif
249                 vchar = ((inp->inp_vflag & INP_IPV4) != 0) ? "4 " : "  ";
250
251         printf("%-3.3s%-2.2s ", name, vchar);
252         if (Lflag) {
253                 char buf[15];
254
255                 snprintf(buf, sizeof(buf), "%d/%d/%d", so->so_qlen,
256                          so->so_incqlen, so->so_qlimit);
257                 printf("%-13.13s ", buf);
258         } else if (Bflag) {
259                 printf("%6ld %6ld ",
260                        so->so_rcv.sb_hiwat,
261                        so->so_snd.sb_hiwat);
262         } else {
263                 printf("%6ld %6ld ",
264                        so->so_rcv.sb_cc,
265                        so->so_snd.sb_cc);
266         }
267         if (numeric_port) {
268                 if (inp->inp_vflag & INP_IPV4) {
269                         inetprint(&inp->inp_laddr, (int)inp->inp_lport,
270                                   name, 1);
271                         if (!Lflag)
272                                 inetprint(&inp->inp_faddr,
273                                           (int)inp->inp_fport, name, 1);
274                 }
275 #ifdef INET6
276                 else if (inp->inp_vflag & INP_IPV6) {
277                         inet6print(&inp->in6p_laddr,
278                                    (int)inp->inp_lport, name, 1);
279                         if (!Lflag)
280                                 inet6print(&inp->in6p_faddr,
281                                            (int)inp->inp_fport, name, 1);
282                 } /* else nothing printed now */
283 #endif /* INET6 */
284         } else if (inp->inp_flags & INP_ANONPORT) {
285                 if (inp->inp_vflag & INP_IPV4) {
286                         inetprint(&inp->inp_laddr, (int)inp->inp_lport,
287                                   name, 1);
288                         if (!Lflag)
289                                 inetprint(&inp->inp_faddr,
290                                           (int)inp->inp_fport, name, 0);
291                 }
292 #ifdef INET6
293                 else if (inp->inp_vflag & INP_IPV6) {
294                         inet6print(&inp->in6p_laddr,
295                                    (int)inp->inp_lport, name, 1);
296                         if (!Lflag)
297                                 inet6print(&inp->in6p_faddr,
298                                            (int)inp->inp_fport, name, 0);
299                 } /* else nothing printed now */
300 #endif /* INET6 */
301         } else {
302                 if (inp->inp_vflag & INP_IPV4) {
303                         inetprint(&inp->inp_laddr, (int)inp->inp_lport,
304                                   name, 0);
305                         if (!Lflag)
306                                 inetprint(&inp->inp_faddr,
307                                           (int)inp->inp_fport, name,
308                                           inp->inp_lport !=
309                                                 inp->inp_fport);
310                 }
311 #ifdef INET6
312                 else if (inp->inp_vflag & INP_IPV6) {
313                         inet6print(&inp->in6p_laddr,
314                                    (int)inp->inp_lport, name, 0);
315                         if (!Lflag)
316                                 inet6print(&inp->in6p_faddr,
317                                            (int)inp->inp_fport, name,
318                                            inp->inp_lport !=
319                                                 inp->inp_fport);
320                 } /* else nothing printed now */
321 #endif /* INET6 */
322         }
323         if (tp && !Lflag) {
324                 if (tp->t_state < 0 || tp->t_state >= TCP_NSTATES)
325                         printf("%d", tp->t_state);
326               else {
327                         printf("%s", tcpstates[tp->t_state]);
328 #if defined(TF_NEEDSYN) && defined(TF_NEEDFIN)
329                       /* Show T/TCP `hidden state' */
330                       if (tp->t_flags & (TF_NEEDSYN|TF_NEEDFIN))
331                               putchar('*');
332 #endif /* defined(TF_NEEDSYN) && defined(TF_NEEDFIN) */
333               }
334         }
335         putchar('\n');
336 }
337
338
339
340 #define CPU_STATS_FUNC(proto,type)                            \
341 static void                                                   \
342 proto ##_stats_agg(type *ary, type *ttl, int cpucnt)          \
343 {                                                             \
344     int i, off, siz;                                          \
345     siz = sizeof(type);                                       \
346                                                               \
347     if (!ary && !ttl)                                         \
348         return;                                               \
349                                                               \
350     bzero(ttl, siz);                                          \
351     if (cpucnt == 1) {                                        \
352         *ttl = ary[0];                                        \
353     } else {                                                  \
354         for (i = 0; i < cpucnt; ++i) {                        \
355             for (off = 0; off < siz; off += sizeof(u_long)) { \
356                 *(u_long *)((char *)(*(&ttl)) + off) +=       \
357                 *(u_long *)((char *)&ary[i] + off);           \
358             }                                                 \
359         }                                                     \
360     }                                                         \
361 }
362 CPU_STATS_FUNC(tcp, struct tcp_stats);
363 CPU_STATS_FUNC(ip, struct ip_stats);
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 ip_stats ipstat, *stattmp;
567         struct ip_stats zerostat[SMP_MAXCPU];
568         size_t len = sizeof(struct ip_stats) * SMP_MAXCPU;
569         int cpucnt;
570
571         if (zflag)
572                 memset(zerostat, 0, len);
573         if ((stattmp = malloc(len)) == NULL) {
574                 return;
575         } else {
576                 if (sysctlbyname("net.inet.ip.stats", stattmp, &len,
577                         zflag ? zerostat : NULL, zflag ? len : 0) < 0) {
578                                 warn("sysctl: net.inet.ip.stats");
579                                 free(stattmp);
580                                 return;
581                 } else {
582                         if ((stattmp = realloc(stattmp, len)) == NULL) {
583                                 warn("ip_stats");
584                                 return;
585                         }
586                 }
587         }
588         cpucnt = len / sizeof(struct ip_stats);
589         ip_stats_agg(stattmp, &ipstat, cpucnt);
590
591         printf("%s:\n", name);
592
593 #define p(f, m) if (ipstat.f || sflag <= 1) \
594     printf(m, ipstat.f, plural(ipstat.f))
595 #define p1a(f, m) if (ipstat.f || sflag <= 1) \
596     printf(m, ipstat.f)
597
598         p(ips_total, "\t%lu total packet%s received\n");
599         p(ips_badsum, "\t%lu bad header checksum%s\n");
600         p1a(ips_toosmall, "\t%lu with size smaller than minimum\n");
601         p1a(ips_tooshort, "\t%lu with data size < data length\n");
602         p1a(ips_toolong, "\t%lu with ip length > max ip packet size\n");
603         p1a(ips_badhlen, "\t%lu with header length < data size\n");
604         p1a(ips_badlen, "\t%lu with data length < header length\n");
605         p1a(ips_badoptions, "\t%lu with bad options\n");
606         p1a(ips_badvers, "\t%lu with incorrect version number\n");
607         p(ips_fragments, "\t%lu fragment%s received\n");
608         p(ips_fragdropped, "\t%lu fragment%s dropped (dup or out of space)\n");
609         p(ips_fragtimeout, "\t%lu fragment%s dropped after timeout\n");
610         p(ips_reassembled, "\t%lu packet%s reassembled ok\n");
611         p(ips_delivered, "\t%lu packet%s for this host\n");
612         p(ips_noproto, "\t%lu packet%s for unknown/unsupported protocol\n");
613         p(ips_forward, "\t%lu packet%s forwarded");
614         p(ips_fastforward, " (%lu packet%s fast forwarded)");
615         if (ipstat.ips_forward || sflag <= 1) 
616                 putchar('\n');
617         p(ips_cantforward, "\t%lu packet%s not forwardable\n");
618         p(ips_notmember,
619           "\t%lu packet%s received for unknown multicast group\n");
620         p(ips_redirectsent, "\t%lu redirect%s sent\n");
621         p(ips_localout, "\t%lu packet%s sent from this host\n");
622         p(ips_rawout, "\t%lu packet%s sent with fabricated ip header\n");
623         p(ips_odropped,
624           "\t%lu output packet%s dropped due to no bufs, etc.\n");
625         p(ips_noroute, "\t%lu output packet%s discarded due to no route\n");
626         p(ips_fragmented, "\t%lu output datagram%s fragmented\n");
627         p(ips_ofragments, "\t%lu fragment%s created\n");
628         p(ips_cantfrag, "\t%lu datagram%s that can't be fragmented\n");
629         p(ips_nogif, "\t%lu tunneling packet%s that can't find gif\n");
630         p(ips_badaddr, "\t%lu datagram%s with bad address in header\n");
631         free(stattmp);
632 #undef p
633 #undef p1a
634 }
635
636 static  char *icmpnames[] = {
637         "echo reply",
638         "#1",
639         "#2",
640         "destination unreachable",
641         "source quench",
642         "routing redirect",
643         "#6",
644         "#7",
645         "echo",
646         "router advertisement",
647         "router solicitation",
648         "time exceeded",
649         "parameter problem",
650         "time stamp",
651         "time stamp reply",
652         "information request",
653         "information request reply",
654         "address mask request",
655         "address mask reply",
656 };
657
658 /*
659  * Dump ICMP statistics.
660  */
661 void
662 icmp_stats(u_long off __unused, char *name, int af __unused)
663 {
664         struct icmpstat icmpstat, zerostat;
665         int i, first;
666         int mib[4];             /* CTL_NET + PF_INET + IPPROTO_ICMP + req */
667         size_t len;
668
669         mib[0] = CTL_NET;
670         mib[1] = PF_INET;
671         mib[2] = IPPROTO_ICMP;
672         mib[3] = ICMPCTL_STATS;
673
674         len = sizeof icmpstat;
675         if (zflag)
676                 memset(&zerostat, 0, len);
677         if (sysctl(mib, 4, &icmpstat, &len,
678             zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
679                 warn("sysctl: net.inet.icmp.stats");
680                 return;
681         }
682
683         printf("%s:\n", name);
684
685 #define p(f, m) if (icmpstat.f || sflag <= 1) \
686     printf(m, icmpstat.f, plural(icmpstat.f))
687 #define p1a(f, m) if (icmpstat.f || sflag <= 1) \
688     printf(m, icmpstat.f)
689 #define p2(f, m) if (icmpstat.f || sflag <= 1) \
690     printf(m, icmpstat.f, plurales(icmpstat.f))
691
692         p(icps_error, "\t%lu call%s to icmp_error\n");
693         p(icps_oldicmp,
694             "\t%lu error%s not generated 'cuz old message was icmp\n");
695         for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
696                 if (icmpstat.icps_outhist[i] != 0) {
697                         if (first) {
698                                 printf("\tOutput histogram:\n");
699                                 first = 0;
700                         }
701                         printf("\t\t%s: %lu\n", icmpnames[i],
702                                 icmpstat.icps_outhist[i]);
703                 }
704         p(icps_badcode, "\t%lu message%s with bad code fields\n");
705         p(icps_tooshort, "\t%lu message%s < minimum length\n");
706         p(icps_checksum, "\t%lu bad checksum%s\n");
707         p(icps_badlen, "\t%lu message%s with bad length\n");
708         p1a(icps_bmcastecho, "\t%lu multicast echo requests ignored\n");
709         p1a(icps_bmcasttstamp, "\t%lu multicast timestamp requests ignored\n");
710         for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
711                 if (icmpstat.icps_inhist[i] != 0) {
712                         if (first) {
713                                 printf("\tInput histogram:\n");
714                                 first = 0;
715                         }
716                         printf("\t\t%s: %lu\n", icmpnames[i],
717                                 icmpstat.icps_inhist[i]);
718                 }
719         p(icps_reflect, "\t%lu message response%s generated\n");
720         p2(icps_badaddr, "\t%lu invalid return address%s\n");
721         p(icps_noroute, "\t%lu no return route%s\n");
722 #undef p
723 #undef p1a
724 #undef p2
725         mib[3] = ICMPCTL_MASKREPL;
726         len = sizeof i;
727         if (sysctl(mib, 4, &i, &len, (void *)0, 0) < 0)
728                 return;
729         printf("\tICMP address mask responses are %sabled\n", 
730                i ? "en" : "dis");
731 }
732
733 /*
734  * Dump IGMP statistics structure.
735  */
736 void
737 igmp_stats(u_long off __unused, char *name, int af __unused)
738 {
739         struct igmpstat igmpstat, zerostat;
740         size_t len = sizeof igmpstat;
741
742         if (zflag)
743                 memset(&zerostat, 0, len);
744         if (sysctlbyname("net.inet.igmp.stats", &igmpstat, &len,
745             zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
746                 warn("sysctl: net.inet.igmp.stats");
747                 return;
748         }
749
750         printf("%s:\n", name);
751
752 #define p(f, m) if (igmpstat.f || sflag <= 1) \
753     printf(m, igmpstat.f, plural(igmpstat.f))
754 #define py(f, m) if (igmpstat.f || sflag <= 1) \
755     printf(m, igmpstat.f, igmpstat.f != 1 ? "ies" : "y")
756         p(igps_rcv_total, "\t%u message%s received\n");
757         p(igps_rcv_tooshort, "\t%u message%s received with too few bytes\n");
758         p(igps_rcv_badsum, "\t%u message%s received with bad checksum\n");
759         py(igps_rcv_queries, "\t%u membership quer%s received\n");
760         py(igps_rcv_badqueries, "\t%u membership quer%s received with invalid field(s)\n");
761         p(igps_rcv_reports, "\t%u membership report%s received\n");
762         p(igps_rcv_badreports, "\t%u membership report%s received with invalid field(s)\n");
763         p(igps_rcv_ourreports, "\t%u membership report%s received for groups to which we belong\n");
764         p(igps_snd_reports, "\t%u membership report%s sent\n");
765 #undef p
766 #undef py
767 }
768
769 /*
770  * Dump PIM statistics structure.
771  */
772 void
773 pim_stats(u_long off __unused, char *name, int af1 __unused)
774 {
775         struct pimstat pimstat, zerostat;
776         size_t len = sizeof pimstat;
777
778         if (zflag)
779                 memset(&zerostat, 0, len);
780         if (sysctlbyname("net.inet.pim.stats", &pimstat, &len,
781             zflag ? &zerostat : NULL, zflag ? len : 0) < 0) {
782                 if (errno != ENOENT)
783                         warn("sysctl: net.inet.pim.stats");
784                 return;
785         }
786
787         printf("%s:\n", name);
788
789 #define p(f, m) if (pimstat.f || sflag <= 1) \
790     printf(m, pimstat.f, plural(pimstat.f))
791 #define py(f, m) if (pimstat.f || sflag <= 1) \
792     printf(m, pimstat.f, pimstat.f != 1 ? "ies" : "y")
793         p(pims_rcv_total_msgs, "\t%llu message%s received\n");
794         p(pims_rcv_total_bytes, "\t%llu byte%s received\n");
795         p(pims_rcv_tooshort, "\t%llu message%s received with too few bytes\n");
796         p(pims_rcv_badsum, "\t%llu message%s received with bad checksum\n");
797         p(pims_rcv_badversion, "\t%llu message%s received with bad version\n");
798         p(pims_rcv_registers_msgs, "\t%llu data register message%s received\n");
799         p(pims_rcv_registers_bytes, "\t%llu data register byte%s received\n");
800         p(pims_rcv_registers_wrongiif, "\t%llu data register message%s received on wrong iif\n");
801         p(pims_rcv_badregisters, "\t%llu bad register%s received\n");
802         p(pims_snd_registers_msgs, "\t%llu data register message%s sent\n");
803         p(pims_snd_registers_bytes, "\t%llu data register byte%s sent\n");
804 #undef p
805 #undef py
806 }
807
808 /*
809  * Pretty print an Internet address (net address + port).
810  */
811 void
812 inetprint(struct in_addr *in, int port, const char *proto, int numeric_port)
813 {
814         struct servent *sp = 0;
815         char line[80], *cp;
816         int width;
817
818         if (Wflag)
819             sprintf(line, "%s.", inetname(in));
820         else
821             sprintf(line, "%.*s.", (Aflag && !numeric_port) ? 12 : 16, inetname(in));
822         cp = strchr(line, '\0');
823         if (!numeric_port && port)
824                 sp = getservbyport((int)port, proto);
825         if (sp || port == 0)
826                 sprintf(cp, "%.15s ", sp ? sp->s_name : "*");
827         else
828                 sprintf(cp, "%d ", ntohs((u_short)port));
829         width = (Aflag && !Wflag) ? 17 : 21;
830         if (Wflag)
831             printf("%-*s ", width, line);
832         else
833             printf("%-*.*s ", width, width, line);
834 }
835
836 /*
837  * Construct an Internet address representation.
838  * If numeric_addr has been supplied, give
839  * numeric value, otherwise try for symbolic name.
840  */
841 char *
842 inetname(struct in_addr *inp)
843 {
844         register char *cp;
845         static char line[MAXHOSTNAMELEN];
846         struct hostent *hp;
847         struct netent *np;
848
849         cp = 0;
850         if (!numeric_addr && inp->s_addr != INADDR_ANY) {
851                 int net = inet_netof(*inp);
852                 int lna = inet_lnaof(*inp);
853
854                 if (lna == INADDR_ANY) {
855                         np = getnetbyaddr(net, AF_INET);
856                         if (np)
857                                 cp = np->n_name;
858                 }
859                 if (cp == 0) {
860                         hp = gethostbyaddr((char *)inp, sizeof (*inp), AF_INET);
861                         if (hp) {
862                                 cp = hp->h_name;
863                                 trimdomain(cp, strlen(cp));
864                         }
865                 }
866         }
867         if (inp->s_addr == INADDR_ANY)
868                 strcpy(line, "*");
869         else if (cp) {
870                 strncpy(line, cp, sizeof(line) - 1);
871                 line[sizeof(line) - 1] = '\0';
872         } else {
873                 inp->s_addr = ntohl(inp->s_addr);
874 #define C(x)    ((u_int)((x) & 0xff))
875                 sprintf(line, "%u.%u.%u.%u", C(inp->s_addr >> 24),
876                     C(inp->s_addr >> 16), C(inp->s_addr >> 8), C(inp->s_addr));
877         }
878         return (line);
879 }