xref: /freebsd/usr.bin/systat/icmp6.c (revision e1e636193db45630c7881246d25902e57c43d24e)
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 1980, 1992, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 
33 
34 /* From:
35 	"Id: mbufs.c,v 1.5 1997/02/24 20:59:03 wollman Exp"
36 */
37 
38 #ifdef INET6
39 #include <sys/param.h>
40 #include <sys/types.h>
41 #include <sys/socket.h>
42 #include <sys/sysctl.h>
43 
44 #include <netinet/in.h>
45 #include <netinet/icmp6.h>
46 
47 #include <inttypes.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <paths.h>
51 #include "systat.h"
52 #include "extern.h"
53 #include "mode.h"
54 
55 static struct icmp6stat icmp6stat, initstat, oldstat;
56 
57 /*-
58 --0         1         2         3         4         5         6         7
59 --0123456789012345678901234567890123456789012345678901234567890123456789012345
60 00          ICMPv6 Input                       ICMPv6 Output
61 01999999999 total messages           999999999 total messages
62 02999999999 with bad code            999999999 errors generated
63 03999999999 with bad length          999999999 suppressed - original too short
64 04999999999 with bad checksum        999999999 suppressed - original was ICMP
65 05999999999 with insufficient data   999999999 responses sent
66 06
67 07          Input Histogram                    Output Histogram
68 08999999999 echo response            999999999 echo response
69 09999999999 echo request             999999999 echo request
70 10999999999 destination unreachable  999999999 destination unreachable
71 11999999999 redirect                 999999999 redirect
72 12999999999 time-to-live exceeded    999999999 time-to-line exceeded
73 13999999999 parameter problem        999999999 parameter problem
74 14999999999 neighbor solicitation    999999999 neighbor solicitation
75 15999999999 neighbor advertisement   999999999 neighbor advertisement
76 16999999999 router advertisement     999999999 router solicitation
77 17
78 18
79 --0123456789012345678901234567890123456789012345678901234567890123456789012345
80 --0         1         2         3         4         5         6         7
81 */
82 
83 WINDOW *
84 openicmp6(void)
85 {
86 	return (subwin(stdscr, LINES-3-1, 0, MAINWIN_ROW, 0));
87 }
88 
89 void
90 closeicmp6(WINDOW *w)
91 {
92 	if (w == NULL)
93 		return;
94 	wclear(w);
95 	wrefresh(w);
96 	delwin(w);
97 }
98 
99 void
100 labelicmp6(void)
101 {
102 	wmove(wnd, 0, 0); wclrtoeol(wnd);
103 #define L(row, str) mvwprintw(wnd, row, 10, str)
104 #define R(row, str) mvwprintw(wnd, row, 45, str);
105 	L(0, "ICMPv6 Input");		R(0, "ICMPv6 Output");
106 	L(1, "total messages");		R(1, "total messages");
107 	L(2, "with bad code");		R(2, "errors generated");
108 	L(3, "with bad length");	R(3, "suppressed - original too short");
109 	L(4, "with bad checksum");	R(4, "suppressed - original was ICMP");
110 	L(5, "with insufficient data");	R(5, "responses sent");
111 
112 	L(7, "Input Histogram");	R(7, "Output Histogram");
113 #define B(row, str) L(row, str); R(row, str)
114 	B(8, "echo response");
115 	B(9, "echo request");
116 	B(10, "destination unreachable");
117 	B(11, "redirect");
118 	B(12, "time-to-live exceeded");
119 	B(13, "parameter problem");
120 	B(14, "neighbor solicitation");
121 	B(15, "neighbor advertisement");
122 	L(16, "router advertisement");	R(16, "router solicitation");
123 #undef L
124 #undef R
125 #undef B
126 }
127 
128 static void
129 domode(struct icmp6stat *ret)
130 {
131 	const struct icmp6stat *sub;
132 	int i, divisor = 1;
133 
134 	switch(currentmode) {
135 	case display_RATE:
136 		sub = &oldstat;
137 		divisor = (delay > 1000000) ? delay / 1000000 : 1;
138 		break;
139 	case display_DELTA:
140 		sub = &oldstat;
141 		break;
142 	case display_SINCE:
143 		sub = &initstat;
144 		break;
145 	default:
146 		*ret = icmp6stat;
147 		return;
148 	}
149 #define DO(stat) ret->stat = (icmp6stat.stat - sub->stat) / divisor
150 	DO(icp6s_error);
151 	DO(icp6s_tooshort);
152 	DO(icp6s_canterror);
153 	for (i = 0; i <= ICMP6_MAXTYPE; i++) {
154 		DO(icp6s_outhist[i]);
155 	}
156 	DO(icp6s_badcode);
157 	DO(icp6s_tooshort);
158 	DO(icp6s_checksum);
159 	DO(icp6s_badlen);
160 	DO(icp6s_reflect);
161 	for (i = 0; i <= ICMP6_MAXTYPE; i++) {
162 		DO(icp6s_inhist[i]);
163 	}
164 #undef DO
165 }
166 
167 void
168 showicmp6(void)
169 {
170 	struct icmp6stat stats;
171 	uint64_t totalin, totalout;
172 	int i;
173 
174 	memset(&stats, 0, sizeof stats);
175 	domode(&stats);
176 	for (i = totalin = totalout = 0; i <= ICMP6_MAXTYPE; i++) {
177 		totalin += stats.icp6s_inhist[i];
178 		totalout += stats.icp6s_outhist[i];
179 	}
180 	totalin += stats.icp6s_badcode + stats.icp6s_badlen +
181 		stats.icp6s_checksum + stats.icp6s_tooshort;
182 	mvwprintw(wnd, 1, 0, "%9"PRIu64, totalin);
183 	mvwprintw(wnd, 1, 35, "%9"PRIu64, totalout);
184 
185 #define DO(stat, row, col) \
186 	mvwprintw(wnd, row, col, "%9"PRIu64, stats.stat)
187 
188 	DO(icp6s_badcode, 2, 0);
189 	DO(icp6s_badlen, 3, 0);
190 	DO(icp6s_checksum, 4, 0);
191 	DO(icp6s_tooshort, 5, 0);
192 	DO(icp6s_error, 2, 35);
193 	DO(icp6s_tooshort, 3, 35);
194 	DO(icp6s_canterror, 4, 35);
195 	DO(icp6s_reflect, 5, 35);
196 #define DO2(type, row) DO(icp6s_inhist[type], row, 0); DO(icp6s_outhist[type], \
197 							 row, 35)
198 	DO2(ICMP6_ECHO_REPLY, 8);
199 	DO2(ICMP6_ECHO_REQUEST, 9);
200 	DO2(ICMP6_DST_UNREACH, 10);
201 	DO2(ND_REDIRECT, 11);
202 	DO2(ICMP6_TIME_EXCEEDED, 12);
203 	DO2(ICMP6_PARAM_PROB, 13);
204 	DO2(ND_NEIGHBOR_SOLICIT, 14);
205 	DO2(ND_NEIGHBOR_ADVERT, 15);
206 	DO(icp6s_inhist[ND_ROUTER_SOLICIT], 16, 0);
207 	DO(icp6s_outhist[ND_ROUTER_ADVERT], 16, 35);
208 #undef DO
209 #undef DO2
210 }
211 
212 int
213 initicmp6(void)
214 {
215 	size_t len;
216 	int name[4];
217 
218 	name[0] = CTL_NET;
219 	name[1] = PF_INET6;
220 	name[2] = IPPROTO_ICMPV6;
221 	name[3] = ICMPV6CTL_STATS;
222 
223 	len = 0;
224 	if (sysctl(name, 4, 0, &len, 0, 0) < 0) {
225 		error("sysctl getting icmp6stat size failed");
226 		return 0;
227 	}
228 	if (len > sizeof icmp6stat) {
229 		error("icmp6stat structure has grown--recompile systat!");
230 		return 0;
231 	}
232 	if (sysctl(name, 4, &initstat, &len, 0, 0) < 0) {
233 		error("sysctl getting icmp6stat size failed");
234 		return 0;
235 	}
236 	oldstat = initstat;
237 	return 1;
238 }
239 
240 void
241 reseticmp6(void)
242 {
243 	size_t len;
244 	int name[4];
245 
246 	name[0] = CTL_NET;
247 	name[1] = PF_INET6;
248 	name[2] = IPPROTO_ICMPV6;
249 	name[3] = ICMPV6CTL_STATS;
250 
251 	len = sizeof initstat;
252 	if (sysctl(name, 4, &initstat, &len, 0, 0) < 0) {
253 		error("sysctl getting icmp6stat size failed");
254 	}
255 	oldstat = initstat;
256 }
257 
258 void
259 fetchicmp6(void)
260 {
261 	int name[4];
262 	size_t len;
263 
264 	oldstat = icmp6stat;
265 	name[0] = CTL_NET;
266 	name[1] = PF_INET6;
267 	name[2] = IPPROTO_ICMPV6;
268 	name[3] = ICMPV6CTL_STATS;
269 	len = sizeof icmp6stat;
270 
271 	if (sysctl(name, 4, &icmp6stat, &len, 0, 0) < 0)
272 		return;
273 }
274 
275 #endif
276