1*0785ab37Smsaitoh /* $NetBSD: atalk.c,v 1.21 2022/09/02 06:25:43 msaitoh Exp $ */
2c3a7122eSchristos
3c3a7122eSchristos /*
4c3a7122eSchristos * Copyright (c) 1983, 1988, 1993
5c3a7122eSchristos * The Regents of the University of California. All rights reserved.
6c3a7122eSchristos *
7c3a7122eSchristos * Redistribution and use in source and binary forms, with or without
8c3a7122eSchristos * modification, are permitted provided that the following conditions
9c3a7122eSchristos * are met:
10c3a7122eSchristos * 1. Redistributions of source code must retain the above copyright
11c3a7122eSchristos * notice, this list of conditions and the following disclaimer.
12c3a7122eSchristos * 2. Redistributions in binary form must reproduce the above copyright
13c3a7122eSchristos * notice, this list of conditions and the following disclaimer in the
14c3a7122eSchristos * documentation and/or other materials provided with the distribution.
1589aaa1bbSagc * 3. Neither the name of the University nor the names of its contributors
16c3a7122eSchristos * may be used to endorse or promote products derived from this software
17c3a7122eSchristos * without specific prior written permission.
18c3a7122eSchristos *
19c3a7122eSchristos * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20c3a7122eSchristos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21c3a7122eSchristos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22c3a7122eSchristos * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23c3a7122eSchristos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24c3a7122eSchristos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25c3a7122eSchristos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26c3a7122eSchristos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27c3a7122eSchristos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28c3a7122eSchristos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29c3a7122eSchristos * SUCH DAMAGE.
30c3a7122eSchristos */
31c3a7122eSchristos
32e55eeec2Slukem #include <sys/cdefs.h>
33c3a7122eSchristos #ifndef lint
34c3a7122eSchristos #if 0
35c3a7122eSchristos static char sccsid[] = "from @(#)atalk.c 1.1 (Whistle) 6/6/96";
36c3a7122eSchristos #else
37*0785ab37Smsaitoh __RCSID("$NetBSD: atalk.c,v 1.21 2022/09/02 06:25:43 msaitoh Exp $");
38c3a7122eSchristos #endif
39c3a7122eSchristos #endif /* not lint */
40c3a7122eSchristos
41c3a7122eSchristos #include <sys/param.h>
42c3a7122eSchristos #include <sys/queue.h>
43c3a7122eSchristos #include <sys/socket.h>
44c3a7122eSchristos #include <sys/socketvar.h>
45c3a7122eSchristos #include <sys/mbuf.h>
46c3a7122eSchristos #include <sys/protosw.h>
47d2d99542Sthorpej #include <sys/sysctl.h>
48c3a7122eSchristos
49c3a7122eSchristos #include <net/route.h>
50c3a7122eSchristos #include <net/if.h>
51c3a7122eSchristos
52c3a7122eSchristos #include <netinet/tcp_fsm.h>
53c3a7122eSchristos
54c3a7122eSchristos #include <netatalk/at.h>
55c3a7122eSchristos #include <netatalk/ddp_var.h>
56c3a7122eSchristos
5740edcfedSthorpej #include <err.h>
58c3a7122eSchristos #include <nlist.h>
599ce7ce6bSrpaulo #include <kvm.h>
60c3a7122eSchristos #include <errno.h>
61c3a7122eSchristos #include <stdio.h>
62c3a7122eSchristos #include <string.h>
63c3a7122eSchristos #include "netstat.h"
64fc2fae23Skamil #include "prog_ops.h"
65c3a7122eSchristos
66c3a7122eSchristos static int first = 1;
67c3a7122eSchristos
68c3a7122eSchristos /*
69c3a7122eSchristos * Print a summary of connections related to a Network Systems
70c3a7122eSchristos * protocol. For XXX, also give state of connection.
71c3a7122eSchristos * Listening processes (aflag) are suppressed unless the
72c3a7122eSchristos * -a (all) flag is specified.
73c3a7122eSchristos */
74c3a7122eSchristos
75d5a0caadSlukem static const char *
at_pr_net(const struct sockaddr_at * sat,int numeric)76d5a0caadSlukem at_pr_net(const struct sockaddr_at *sat, int numeric)
77c3a7122eSchristos {
78c3a7122eSchristos static char mybuf[50];
79c3a7122eSchristos
80c3a7122eSchristos if (!numeric) {
81c3a7122eSchristos switch (sat->sat_addr.s_net) {
82c3a7122eSchristos case 0xffff:
83c3a7122eSchristos return "????";
84c3a7122eSchristos case ATADDR_ANYNET:
85d7198e62Smsaitoh return "*";
86c3a7122eSchristos }
87c3a7122eSchristos }
88d7198e62Smsaitoh (void)snprintf(mybuf, sizeof(mybuf), "%hu",
89d7198e62Smsaitoh ntohs(sat->sat_addr.s_net));
90d7198e62Smsaitoh return mybuf;
91c3a7122eSchristos }
92c3a7122eSchristos
93d5a0caadSlukem static const char *
at_pr_host(const struct sockaddr_at * sat,int numeric)94d5a0caadSlukem at_pr_host(const struct sockaddr_at *sat, int numeric)
95c3a7122eSchristos {
96c3a7122eSchristos static char mybuf[50];
97c3a7122eSchristos
98c3a7122eSchristos if (!numeric) {
99c3a7122eSchristos switch (sat->sat_addr.s_node) {
100c3a7122eSchristos case ATADDR_BCAST:
101c3a7122eSchristos return "bcast";
102c3a7122eSchristos case ATADDR_ANYNODE:
103d7198e62Smsaitoh return "*";
104c3a7122eSchristos }
105c3a7122eSchristos }
106c3a7122eSchristos (void)snprintf(mybuf, sizeof(mybuf), "%d",
107c3a7122eSchristos (unsigned int)sat->sat_addr.s_node);
108d7198e62Smsaitoh return mybuf;
109c3a7122eSchristos }
110c3a7122eSchristos
111d5a0caadSlukem static const char *
at_pr_port(const struct sockaddr_at * sat)112d5a0caadSlukem at_pr_port(const struct sockaddr_at *sat)
113c3a7122eSchristos {
114c3a7122eSchristos static char mybuf[50];
115c3a7122eSchristos
116c3a7122eSchristos switch (sat->sat_port) {
117c3a7122eSchristos case ATADDR_ANYPORT:
118d7198e62Smsaitoh return "*";
119c3a7122eSchristos case 0xff:
120c3a7122eSchristos return "????";
121c3a7122eSchristos default:
122c3a7122eSchristos (void)snprintf(mybuf, sizeof(mybuf), "%d",
123c3a7122eSchristos (unsigned int)sat->sat_port);
124d7198e62Smsaitoh return mybuf;
125c3a7122eSchristos }
126c3a7122eSchristos }
127c3a7122eSchristos
128d5a0caadSlukem static const char *
at_pr_range(const struct sockaddr_at * sat)129d5a0caadSlukem at_pr_range(const struct sockaddr_at *sat)
130c3a7122eSchristos {
131c3a7122eSchristos static char mybuf[50];
132c3a7122eSchristos
133c3a7122eSchristos if (sat->sat_range.r_netrange.nr_firstnet
134c3a7122eSchristos != sat->sat_range.r_netrange.nr_lastnet) {
135c3a7122eSchristos (void)snprintf(mybuf, sizeof(mybuf), "%d-%d",
136c3a7122eSchristos ntohs(sat->sat_range.r_netrange.nr_firstnet),
137c3a7122eSchristos ntohs(sat->sat_range.r_netrange.nr_lastnet));
138c3a7122eSchristos } else {
139c3a7122eSchristos (void)snprintf(mybuf, sizeof(mybuf), "%d",
140c3a7122eSchristos ntohs(sat->sat_range.r_netrange.nr_firstnet));
141c3a7122eSchristos }
142d7198e62Smsaitoh return mybuf;
143c3a7122eSchristos }
144c3a7122eSchristos
145c3a7122eSchristos
146c3a7122eSchristos /* what == 0 for addr only == 3
147c3a7122eSchristos * 1 for net
148c3a7122eSchristos * 2 for host
149c3a7122eSchristos * 4 for port
150c3a7122eSchristos * 8 for numeric only
151c3a7122eSchristos */
152d5a0caadSlukem const char *
atalk_print(const struct sockaddr * sa,int what)153d2d99542Sthorpej atalk_print(const struct sockaddr *sa, int what)
154c3a7122eSchristos {
155d5a0caadSlukem const struct sockaddr_at *sat = (const struct sockaddr_at *) sa;
156c3a7122eSchristos static char mybuf[50];
157c3a7122eSchristos int numeric = (what & 0x08);
158c3a7122eSchristos
159c3a7122eSchristos mybuf[0] = 0;
160c3a7122eSchristos switch (what & 0x13) {
161c3a7122eSchristos case 0:
162c3a7122eSchristos mybuf[0] = 0;
163c3a7122eSchristos break;
164c3a7122eSchristos case 1:
165c3a7122eSchristos (void)snprintf(mybuf, sizeof(mybuf), "%s",
166c3a7122eSchristos at_pr_net(sat, numeric));
167c3a7122eSchristos break;
168c3a7122eSchristos case 2:
169c3a7122eSchristos (void)snprintf(mybuf, sizeof(mybuf), "%s",
170c3a7122eSchristos at_pr_host(sat, numeric));
171c3a7122eSchristos break;
172c3a7122eSchristos case 3:
173c3a7122eSchristos (void)snprintf(mybuf, sizeof(mybuf), "%s.%s",
174c3a7122eSchristos at_pr_net(sat, numeric),
175c3a7122eSchristos at_pr_host(sat, numeric));
176c3a7122eSchristos break;
177c3a7122eSchristos case 0x10:
178c3a7122eSchristos (void)snprintf(mybuf, sizeof(mybuf), "%s", at_pr_range(sat));
179c3a7122eSchristos }
180c3a7122eSchristos if (what & 4) {
181c3a7122eSchristos (void)snprintf(mybuf + strlen(mybuf),
182c3a7122eSchristos sizeof(mybuf) - strlen(mybuf), ".%s", at_pr_port(sat));
183c3a7122eSchristos }
184d7198e62Smsaitoh return mybuf;
185c3a7122eSchristos }
186c3a7122eSchristos
187d5a0caadSlukem const char *
atalk_print2(const struct sockaddr * sa,const struct sockaddr * mask,int what)188d2d99542Sthorpej atalk_print2(const struct sockaddr *sa, const struct sockaddr *mask, int what)
189c3a7122eSchristos {
19032f6ca81Srpaulo int n, l;
191c3a7122eSchristos static char buf[100];
192d5a0caadSlukem const struct sockaddr_at *sat1, *sat2;
193c3a7122eSchristos struct sockaddr_at thesockaddr;
194c3a7122eSchristos struct sockaddr *sa2;
195c3a7122eSchristos
196d5a0caadSlukem sat1 = (const struct sockaddr_at *) sa;
197d5a0caadSlukem sat2 = (const struct sockaddr_at *) mask;
198c3a7122eSchristos sa2 = (struct sockaddr *) & thesockaddr;
199c3a7122eSchristos
200c3a7122eSchristos thesockaddr.sat_addr.s_net = sat1->sat_addr.s_net &
201c3a7122eSchristos sat2->sat_addr.s_net;
202c3a7122eSchristos n = snprintf(buf, sizeof(buf), "%s", atalk_print(sa2, 1 | (what & 8)));
203d5a0caadSlukem if (n >= (int)sizeof(buf))
204bc9b3f2aSitojun n = sizeof(buf) - 1;
205bc9b3f2aSitojun else if (n == -1)
206bc9b3f2aSitojun n = 0; /* What else can be done ? */
207c3a7122eSchristos if (sat2->sat_addr.s_net != 0xFFFF) {
208c3a7122eSchristos thesockaddr.sat_addr.s_net = sat1->sat_addr.s_net |
209c3a7122eSchristos ~sat2->sat_addr.s_net;
210bc9b3f2aSitojun l = snprintf(buf + n, sizeof(buf) - n,
211c3a7122eSchristos "-%s", atalk_print(sa2, 1 | (what & 8)));
212d5a0caadSlukem if (l >= (int)(sizeof(buf) - n))
213bc9b3f2aSitojun l = sizeof(buf) - n - 1;
214bc9b3f2aSitojun if (l > 0)
215bc9b3f2aSitojun n += l;
216c3a7122eSchristos }
217bc9b3f2aSitojun if (what & 2) {
218bc9b3f2aSitojun l = snprintf(buf + n, sizeof(buf) - n, ".%s",
219c3a7122eSchristos atalk_print(sa, what & (~1)));
220d5a0caadSlukem if (l >= (int)(sizeof(buf) - n))
221bc9b3f2aSitojun l = sizeof(buf) - n - 1;
222bc9b3f2aSitojun if (l > 0)
223bc9b3f2aSitojun n += l;
224bc9b3f2aSitojun }
225d7198e62Smsaitoh return buf;
226c3a7122eSchristos }
227c3a7122eSchristos
228c3a7122eSchristos void
atalkprotopr(u_long off,const char * name)229d5a0caadSlukem atalkprotopr(u_long off, const char *name)
230c3a7122eSchristos {
2314f6512cdSjoerg struct ddpcb ddpcb;
2324f6512cdSjoerg struct socket sockb;
23315a5bba9Schristos struct ddpcb *next;
234c3a7122eSchristos struct ddpcb *initial;
235135600f9Sis int width = 22;
236c3a7122eSchristos if (off == 0)
237c3a7122eSchristos return;
238c3a7122eSchristos if (kread(off, (char *)&initial, sizeof(struct ddpcb *)) < 0)
239c3a7122eSchristos return;
24015a5bba9Schristos for (next = initial; next != NULL;) {
241aef70018Schristos u_long ppcb = (u_long)next;
242c3a7122eSchristos
243c3a7122eSchristos if (kread((u_long)next, (char *)&ddpcb, sizeof(ddpcb)) < 0)
244c3a7122eSchristos return;
245c3a7122eSchristos next = ddpcb.ddp_next;
246c3a7122eSchristos #if 0
247*0785ab37Smsaitoh if (!aflag && atalk_nullhost(ddpcb.ddp_lsat))
248c3a7122eSchristos continue;
249c3a7122eSchristos #endif
250c3a7122eSchristos if (kread((u_long)ddpcb.ddp_socket,
251c3a7122eSchristos (char *)&sockb, sizeof(sockb)) < 0)
252c3a7122eSchristos return;
253c3a7122eSchristos if (first) {
254c3a7122eSchristos printf("Active ATALK connections");
255c3a7122eSchristos if (aflag)
256c3a7122eSchristos printf(" (including servers)");
257c3a7122eSchristos putchar('\n');
258135600f9Sis if (Aflag) {
259135600f9Sis width = 18;
260c3a7122eSchristos printf("%-8.8s ", "PCB");
261135600f9Sis }
262135600f9Sis printf("%-5.5s %-6.6s %-6.6s %*.*s %*.*s %s\n",
263c3a7122eSchristos "Proto", "Recv-Q", "Send-Q",
264135600f9Sis -width, width, "Local Address",
265135600f9Sis -width, width, "Foreign Address", "(state)");
266c3a7122eSchristos first = 0;
267c3a7122eSchristos }
268c3a7122eSchristos if (Aflag)
269aef70018Schristos printf("%8lx ", ppcb);
270c3a7122eSchristos printf("%-5.5s %6ld %6ld ", name, sockb.so_rcv.sb_cc,
271c3a7122eSchristos sockb.so_snd.sb_cc);
272135600f9Sis printf(" %*.*s", -width, width,
273135600f9Sis atalk_print((struct sockaddr *)&ddpcb.ddp_lsat, 7));
274135600f9Sis printf(" %*.*s", -width, width,
275135600f9Sis atalk_print((struct sockaddr *)&ddpcb.ddp_fsat, 7));
276c3a7122eSchristos putchar('\n');
277c3a7122eSchristos }
278c3a7122eSchristos }
279c3a7122eSchristos #define ANY(x,y,z) \
280d7198e62Smsaitoh ((sflag==1 || (x)) ? \
281d7198e62Smsaitoh printf("\t%llu %s%s%s\n",(unsigned long long)x,y,plural(x),z) : 0)
282c3a7122eSchristos
283c3a7122eSchristos /*
284c3a7122eSchristos * Dump DDP statistics structure.
285c3a7122eSchristos */
286c3a7122eSchristos void
ddp_stats(u_long off,const char * name)287d5a0caadSlukem ddp_stats(u_long off, const char *name)
288c3a7122eSchristos {
289d2d99542Sthorpej uint64_t ddpstat[DDP_NSTATS];
290c3a7122eSchristos
291d2d99542Sthorpej if (use_sysctl) {
292d2d99542Sthorpej size_t size = sizeof(ddpstat);
293d2d99542Sthorpej
294fc2fae23Skamil if (prog_sysctlbyname("net.atalk.ddp.stats", ddpstat, &size,
2951d675d5aSozaki-r NULL, 0) == -1 && errno != ENOMEM)
296d2d99542Sthorpej return;
297d2d99542Sthorpej } else {
29840edcfedSthorpej warnx("%s stats not available via KVM.", name);
299c3a7122eSchristos return;
300d2d99542Sthorpej }
301d2d99542Sthorpej
302c3a7122eSchristos printf("%s:\n", name);
303d2d99542Sthorpej
304d2d99542Sthorpej ANY(ddpstat[DDP_STAT_SHORT], "packet", " with short headers ");
305d2d99542Sthorpej ANY(ddpstat[DDP_STAT_LONG], "packet", " with long headers ");
306d2d99542Sthorpej ANY(ddpstat[DDP_STAT_NOSUM], "packet", " with no checksum ");
307d2d99542Sthorpej ANY(ddpstat[DDP_STAT_TOOSHORT], "packet", " too short ");
308d2d99542Sthorpej ANY(ddpstat[DDP_STAT_BADSUM], "packet", " with bad checksum ");
309d2d99542Sthorpej ANY(ddpstat[DDP_STAT_TOOSMALL], "packet", " with not enough data ");
310d2d99542Sthorpej ANY(ddpstat[DDP_STAT_FORWARD], "packet", " forwarded ");
311d2d99542Sthorpej ANY(ddpstat[DDP_STAT_ENCAP], "packet", " encapsulated ");
312d7198e62Smsaitoh ANY(ddpstat[DDP_STAT_CANTFORWARD], "packet",
313d7198e62Smsaitoh " rcvd for unreachable dest ");
314d7198e62Smsaitoh ANY(ddpstat[DDP_STAT_NOSOCKSPACE], "packet",
315d7198e62Smsaitoh " dropped due to no socket space ");
316c3a7122eSchristos }
317c3a7122eSchristos #undef ANY
318