atalk.c revision 1.16.8.1 1 /* $NetBSD: atalk.c,v 1.16.8.1 2022/09/12 14:29:19 martin Exp $ */
2
3 /*
4 * Copyright (c) 1983, 1988, 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 #include <sys/cdefs.h>
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "from @(#)atalk.c 1.1 (Whistle) 6/6/96";
36 #else
37 __RCSID("$NetBSD: atalk.c,v 1.16.8.1 2022/09/12 14:29:19 martin Exp $");
38 #endif
39 #endif /* not lint */
40
41 #include <sys/param.h>
42 #include <sys/queue.h>
43 #include <sys/socket.h>
44 #include <sys/socketvar.h>
45 #include <sys/mbuf.h>
46 #include <sys/protosw.h>
47 #include <sys/sysctl.h>
48
49 #include <net/route.h>
50 #include <net/if.h>
51
52 #include <netinet/tcp_fsm.h>
53
54 #include <netatalk/at.h>
55 #include <netatalk/ddp_var.h>
56
57 #include <err.h>
58 #include <nlist.h>
59 #include <kvm.h>
60 #include <errno.h>
61 #include <stdio.h>
62 #include <string.h>
63 #include "netstat.h"
64
65 static int first = 1;
66
67 /*
68 * Print a summary of connections related to a Network Systems
69 * protocol. For XXX, also give state of connection.
70 * Listening processes (aflag) are suppressed unless the
71 * -a (all) flag is specified.
72 */
73
74 static const char *
75 at_pr_net(const struct sockaddr_at *sat, int numeric)
76 {
77 static char mybuf[50];
78
79 if (!numeric) {
80 switch (sat->sat_addr.s_net) {
81 case 0xffff:
82 return "????";
83 case ATADDR_ANYNET:
84 return "*";
85 }
86 }
87 (void)snprintf(mybuf, sizeof(mybuf), "%hu",
88 ntohs(sat->sat_addr.s_net));
89 return mybuf;
90 }
91
92 static const char *
93 at_pr_host(const struct sockaddr_at *sat, int numeric)
94 {
95 static char mybuf[50];
96
97 if (!numeric) {
98 switch (sat->sat_addr.s_node) {
99 case ATADDR_BCAST:
100 return "bcast";
101 case ATADDR_ANYNODE:
102 return "*";
103 }
104 }
105 (void)snprintf(mybuf, sizeof(mybuf), "%d",
106 (unsigned int)sat->sat_addr.s_node);
107 return mybuf;
108 }
109
110 static const char *
111 at_pr_port(const struct sockaddr_at *sat)
112 {
113 static char mybuf[50];
114
115 switch (sat->sat_port) {
116 case ATADDR_ANYPORT:
117 return "*";
118 case 0xff:
119 return "????";
120 default:
121 (void)snprintf(mybuf, sizeof(mybuf), "%d",
122 (unsigned int)sat->sat_port);
123 return mybuf;
124 }
125 }
126
127 static const char *
128 at_pr_range(const struct sockaddr_at *sat)
129 {
130 static char mybuf[50];
131
132 if (sat->sat_range.r_netrange.nr_firstnet
133 != sat->sat_range.r_netrange.nr_lastnet) {
134 (void)snprintf(mybuf, sizeof(mybuf), "%d-%d",
135 ntohs(sat->sat_range.r_netrange.nr_firstnet),
136 ntohs(sat->sat_range.r_netrange.nr_lastnet));
137 } else {
138 (void)snprintf(mybuf, sizeof(mybuf), "%d",
139 ntohs(sat->sat_range.r_netrange.nr_firstnet));
140 }
141 return mybuf;
142 }
143
144
145 /* what == 0 for addr only == 3
146 * 1 for net
147 * 2 for host
148 * 4 for port
149 * 8 for numeric only
150 */
151 const char *
152 atalk_print(const struct sockaddr *sa, int what)
153 {
154 const struct sockaddr_at *sat = (const struct sockaddr_at *) sa;
155 static char mybuf[50];
156 int numeric = (what & 0x08);
157
158 mybuf[0] = 0;
159 switch (what & 0x13) {
160 case 0:
161 mybuf[0] = 0;
162 break;
163 case 1:
164 (void)snprintf(mybuf, sizeof(mybuf), "%s",
165 at_pr_net(sat, numeric));
166 break;
167 case 2:
168 (void)snprintf(mybuf, sizeof(mybuf), "%s",
169 at_pr_host(sat, numeric));
170 break;
171 case 3:
172 (void)snprintf(mybuf, sizeof(mybuf), "%s.%s",
173 at_pr_net(sat, numeric),
174 at_pr_host(sat, numeric));
175 break;
176 case 0x10:
177 (void)snprintf(mybuf, sizeof(mybuf), "%s", at_pr_range(sat));
178 }
179 if (what & 4) {
180 (void)snprintf(mybuf + strlen(mybuf),
181 sizeof(mybuf) - strlen(mybuf), ".%s", at_pr_port(sat));
182 }
183 return mybuf;
184 }
185
186 const char *
187 atalk_print2(const struct sockaddr *sa, const struct sockaddr *mask, int what)
188 {
189 int n, l;
190 static char buf[100];
191 const struct sockaddr_at *sat1, *sat2;
192 struct sockaddr_at thesockaddr;
193 struct sockaddr *sa2;
194
195 sat1 = (const struct sockaddr_at *) sa;
196 sat2 = (const struct sockaddr_at *) mask;
197 sa2 = (struct sockaddr *) & thesockaddr;
198
199 thesockaddr.sat_addr.s_net = sat1->sat_addr.s_net &
200 sat2->sat_addr.s_net;
201 n = snprintf(buf, sizeof(buf), "%s", atalk_print(sa2, 1 | (what & 8)));
202 if (n >= (int)sizeof(buf))
203 n = sizeof(buf) - 1;
204 else if (n == -1)
205 n = 0; /* What else can be done ? */
206 if (sat2->sat_addr.s_net != 0xFFFF) {
207 thesockaddr.sat_addr.s_net = sat1->sat_addr.s_net |
208 ~sat2->sat_addr.s_net;
209 l = snprintf(buf + n, sizeof(buf) - n,
210 "-%s", atalk_print(sa2, 1 | (what & 8)));
211 if (l >= (int)(sizeof(buf) - n))
212 l = sizeof(buf) - n - 1;
213 if (l > 0)
214 n += l;
215 }
216 if (what & 2) {
217 l = snprintf(buf + n, sizeof(buf) - n, ".%s",
218 atalk_print(sa, what & (~1)));
219 if (l >= (int)(sizeof(buf) - n))
220 l = sizeof(buf) - n - 1;
221 if (l > 0)
222 n += l;
223 }
224 return buf;
225 }
226
227 void
228 atalkprotopr(u_long off, const char *name)
229 {
230 struct ddpcb ddpcb;
231 struct socket sockb;
232 struct ddpcb *next;
233 struct ddpcb *initial;
234 int width = 22;
235 if (off == 0)
236 return;
237 if (kread(off, (char *)&initial, sizeof(struct ddpcb *)) < 0)
238 return;
239 for (next = initial; next != NULL;) {
240 u_long ppcb = (u_long)next;
241
242 if (kread((u_long)next, (char *)&ddpcb, sizeof(ddpcb)) < 0)
243 return;
244 next = ddpcb.ddp_next;
245 #if 0
246 if (!aflag && atalk_nullhost(ddpcb.ddp_lsat))
247 continue;
248 #endif
249 if (kread((u_long)ddpcb.ddp_socket,
250 (char *)&sockb, sizeof(sockb)) < 0)
251 return;
252 if (first) {
253 printf("Active ATALK connections");
254 if (aflag)
255 printf(" (including servers)");
256 putchar('\n');
257 if (Aflag) {
258 width = 18;
259 printf("%-8.8s ", "PCB");
260 }
261 printf("%-5.5s %-6.6s %-6.6s %*.*s %*.*s %s\n",
262 "Proto", "Recv-Q", "Send-Q",
263 -width, width, "Local Address",
264 -width, width, "Foreign Address", "(state)");
265 first = 0;
266 }
267 if (Aflag)
268 printf("%8lx ", ppcb);
269 printf("%-5.5s %6ld %6ld ", name, sockb.so_rcv.sb_cc,
270 sockb.so_snd.sb_cc);
271 printf(" %*.*s", -width, width,
272 atalk_print((struct sockaddr *)&ddpcb.ddp_lsat, 7));
273 printf(" %*.*s", -width, width,
274 atalk_print((struct sockaddr *)&ddpcb.ddp_fsat, 7));
275 putchar('\n');
276 }
277 }
278 #define ANY(x,y,z) \
279 ((sflag==1 || (x)) ? \
280 printf("\t%llu %s%s%s\n",(unsigned long long)x,y,plural(x),z) : 0)
281
282 /*
283 * Dump DDP statistics structure.
284 */
285 void
286 ddp_stats(u_long off, const char *name)
287 {
288 uint64_t ddpstat[DDP_NSTATS];
289
290 if (use_sysctl) {
291 size_t size = sizeof(ddpstat);
292
293 if (sysctlbyname("net.atalk.ddp.stats", ddpstat, &size,
294 NULL, 0) == -1)
295 return;
296 } else {
297 warnx("%s stats not available via KVM.", name);
298 return;
299 }
300
301 printf("%s:\n", name);
302
303 ANY(ddpstat[DDP_STAT_SHORT], "packet", " with short headers ");
304 ANY(ddpstat[DDP_STAT_LONG], "packet", " with long headers ");
305 ANY(ddpstat[DDP_STAT_NOSUM], "packet", " with no checksum ");
306 ANY(ddpstat[DDP_STAT_TOOSHORT], "packet", " too short ");
307 ANY(ddpstat[DDP_STAT_BADSUM], "packet", " with bad checksum ");
308 ANY(ddpstat[DDP_STAT_TOOSMALL], "packet", " with not enough data ");
309 ANY(ddpstat[DDP_STAT_FORWARD], "packet", " forwarded ");
310 ANY(ddpstat[DDP_STAT_ENCAP], "packet", " encapsulated ");
311 ANY(ddpstat[DDP_STAT_CANTFORWARD], "packet",
312 " rcvd for unreachable dest ");
313 ANY(ddpstat[DDP_STAT_NOSOCKSPACE], "packet",
314 " dropped due to no socket space ");
315 }
316 #undef ANY
317