xref: /NextBSD/sbin/atm/atmconfig/diag.c (revision eb1a5f8de9f7ea602c373a710f531abbf81141c4)
1 /*
2  * Copyright (c) 2001-2003
3  *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4  * 	All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  * Author: Hartmut Brandt <harti@freebsd.org>
28  */
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31 
32 #include <sys/types.h>
33 #include <sys/sysctl.h>
34 #include <sys/ioctl.h>
35 #include <sys/socket.h>
36 #include <sys/queue.h>
37 #include <net/if.h>
38 #include <net/if_mib.h>
39 #include <net/if_types.h>
40 #include <net/if_atm.h>
41 #include <net/if_media.h>
42 #include <netnatm/natm.h>
43 #include <dev/utopia/utopia.h>
44 #include <dev/utopia/suni.h>
45 #include <dev/utopia/idtphy.h>
46 
47 #include "atmconfig.h"
48 #include "private.h"
49 #include "diag.h"
50 
51 static void diag_list(int, char *[]);
52 static void diag_config(int, char *[]);
53 static void diag_vcc(int, char *[]);
54 static void diag_phy_show(int, char *[]);
55 static void diag_phy_set(int, char *[]);
56 static void diag_phy_print(int, char *[]);
57 static void diag_phy_stats(int, char *[]);
58 static void diag_stats(int, char *[]);
59 
60 static const struct cmdtab diag_phy_tab[] = {
61 	{ "show",	NULL, 		diag_phy_show },
62 	{ "set",	NULL, 		diag_phy_set },
63 	{ "stats",	NULL,		diag_phy_stats },
64 	{ "print",	NULL,		diag_phy_print },
65 	{ NULL,		NULL,		NULL },
66 };
67 
68 const struct cmdtab diag_tab[] = {
69 	{ "list",	NULL,		diag_list },
70 	{ "config",	NULL,		diag_config },
71 	{ "phy",	diag_phy_tab,	NULL },
72 	{ "stats",	NULL,		diag_stats },
73 	{ "vcc",	NULL,		diag_vcc },
74 	{ NULL, 	NULL, 		NULL }
75 };
76 
77 static const struct utopia_print suni_lite[] = { SUNI_PRINT_LITE };
78 static const struct utopia_print suni_ultra[] = { SUNI_PRINT_ULTRA };
79 static const struct utopia_print suni_622[] = { SUNI_PRINT_622 };
80 static const struct utopia_print idt77105[] = { IDTPHY_PRINT_77105 };
81 static const struct utopia_print idt77155[] = { IDTPHY_PRINT_77155 };
82 
83 static const struct {
84 	const struct utopia_print *tab;
85 	u_int len;
86 	u_int type;
87 } phy_print[] = {
88 	{ suni_lite, sizeof(suni_lite) / sizeof(suni_lite[0]),
89 	  UTP_TYPE_SUNI_LITE },
90 	{ suni_ultra, sizeof(suni_ultra) / sizeof(suni_ultra[0]),
91 	  UTP_TYPE_SUNI_ULTRA },
92 	{ suni_622, sizeof(suni_622) / sizeof(suni_622[0]),
93 	  UTP_TYPE_SUNI_622 },
94 	{ idt77105, sizeof(idt77105) / sizeof(idt77105[0]),
95 	  UTP_TYPE_IDT77105 },
96 	{ idt77155, sizeof(idt77155) / sizeof(idt77155[0]),
97 	  UTP_TYPE_IDT77155 },
98 };
99 
100 static const u_int utopia_addreg[] = { UTP_REG_ADD };
101 
102 /*
103  * Driver statistics printing
104  */
105 static const char *const print_stats_pca200e[] = {
106 	"cmd_queue_full:",
107 	"get_stat_errors:",
108 	"clr_stat_errors:",
109 	"get_prom_errors:",
110 	"suni_reg_errors:",
111 	"tx_queue_full:",
112 	"tx_queue_almost_full:",
113 	"tx_pdu2big:",
114 	"tx_too_many_segs:",
115 	"tx_retry:",
116 	"fix_empty:",
117 	"fix_addr_copy:",
118 	"fix_addr_noext:",
119 	"fix_addr_ext:",
120 	"fix_len_noext:",
121 	"fix_len_copy:",
122 	"fix_len:",
123 	"rx_badvc:",
124 	"rx_closed:",
125 	NULL
126 };
127 static const char *const print_stats_he[] = {
128 	"tdprq_full:",
129 	"hbuf_error:",
130 	"crc_error:",
131 	"len_error:",
132 	"flow_closed:",
133 	"flow_drop:",
134 	"tpd_no_mem:",
135 	"rx_seg:",
136 	"empty_hbuf:",
137 	"short_aal5:",
138 	"badlen_aal5:",
139 	"bug_bad_isw:",
140 	"bug_no_irq_upd:",
141 	"itype_tbrq:",
142 	"itype_tpd:",
143 	"itype_rbps:",
144 	"itype_rbpl:",
145 	"itype_rbrq:",
146 	"itype_rbrqt:",
147 	"itype_unknown:",
148 	"itype_phys:",
149 	"itype_err:",
150 	"defrag:",
151 	"mcc:",
152 	"oec:",
153 	"dcc:",
154 	"cec:",
155 	"no_rcv_mbuf:",
156 	NULL
157 };
158 static const char *const print_stats_eni[] = {
159 	"ttrash:",
160 	"mfixaddr:",
161 	"mfixlen:",
162 	"mfixfail:",
163 	"txmbovr:",
164 	"dmaovr:",
165 	"txoutspace:",
166 	"txdtqout:",
167 	"launch:",
168 	"hwpull:",
169 	"swadd:",
170 	"rxqnotus:",
171 	"rxqus:",
172 	"rxdrqout:",
173 	"rxmbufout:",
174 	"txnomap:",
175 	"vtrash:",
176 	"otrash:",
177 	NULL
178 };
179 
180 static const char *const print_stats_idt77211[] = {
181 	"need_copy:",
182 	"copy_failed:",
183 	"out_of_tbds:",
184 	"no_txmaps:",
185 	"tx_load_err:",
186 	"tx_qfull:",
187 	NULL
188 };
189 static const char *const print_stats_idt77252[] = {
190 	"raw_cells:",
191 	"raw_no_vcc:",
192 	"raw_no_buf:",
193 	"tx_qfull:",
194 	"tx_out_of_tbds:",
195 	"tx_out_of_maps:",
196 	"tx_load_err:",
197 	NULL
198 };
199 static const char *const print_stats_virtual[] = {
200 	"dummy:",
201 	NULL
202 };
203 static const char *const *const print_stats[] = {
204 	[ATM_DEVICE_UNKNOWN] =		NULL,
205 	[ATM_DEVICE_PCA200E] =		print_stats_pca200e,
206 	[ATM_DEVICE_HE155] =		print_stats_he,
207 	[ATM_DEVICE_HE622] =		print_stats_he,
208 	[ATM_DEVICE_ENI155P] =		print_stats_eni,
209 	[ATM_DEVICE_ADP155P] =		print_stats_eni,
210 	[ATM_DEVICE_FORELE25] =		print_stats_idt77211,
211 	[ATM_DEVICE_FORELE155] =	print_stats_idt77211,
212 	[ATM_DEVICE_NICSTAR25] =	print_stats_idt77211,
213 	[ATM_DEVICE_NICSTAR155] =	print_stats_idt77211,
214 	[ATM_DEVICE_IDTABR25] =		print_stats_idt77252,
215 	[ATM_DEVICE_IDTABR155] =	print_stats_idt77252,
216 	[ATM_DEVICE_PROATM25] =		print_stats_idt77252,
217 	[ATM_DEVICE_PROATM155] =	print_stats_idt77252,
218 	[ATM_DEVICE_VIRTUAL] =		print_stats_virtual,
219 };
220 
221 struct diagif_list diagif_list = TAILQ_HEAD_INITIALIZER(diagif_list);
222 
223 /*
224  * Fetch a phy sysctl
225  */
226 static int
phy_fetch(const char * ifname,const char * var,void * val,size_t len,int err_fatal)227 phy_fetch(const char *ifname, const char *var, void *val, size_t len,
228     int err_fatal)
229 {
230 	char *str;
231 
232 	if (asprintf(&str, "hw.atm.%s.phy_%s", ifname, var) == -1)
233 		err(1, NULL);
234 	if (sysctlbyname(str, val, &len, NULL, 0) == -1) {
235 		if (err_fatal || errno != ENOENT)
236 			err(1, "%s", str);
237 		free(str);
238 		return (-1);
239 	}
240 	free(str);
241 	return (0);
242 }
243 
244 /*
245  * Fetch the list of all ATM network interfaces and their MIBs.
246  */
247 void
diagif_fetch(void)248 diagif_fetch(void)
249 {
250 	size_t len;
251 	int count;
252 	int name[6];
253 	struct ifmibdata mib;
254 	struct ifatm_mib atm;
255 	int idx;
256 	struct diagif *d;
257 
258 	while ((d = TAILQ_FIRST(&diagif_list)) != NULL) {
259 		if (d->vtab != NULL)
260 			free(d->vtab);
261 		TAILQ_REMOVE(&diagif_list, d, link);
262 		free(d);
263 	}
264 
265 	len = sizeof(count);
266 	if (sysctlbyname("net.link.generic.system.ifcount", &count, &len,
267 	    NULL, 0) == -1)
268 		err(1, "ifcount");
269 
270 	name[0] = CTL_NET;
271 	name[1] = PF_LINK;
272 	name[2] = NETLINK_GENERIC;
273 	name[3] = IFMIB_IFDATA;
274 
275 	for (idx = 1; idx <= count; idx++) {
276 		name[4] = idx;
277 		name[5] = IFDATA_GENERAL;
278 		len = sizeof(mib);
279 		if (sysctl(name, 6, &mib, &len, NULL, 0) == -1)
280 			err(1, "interface %d: general mib", idx);
281 		if (mib.ifmd_data.ifi_type == IFT_ATM) {
282 			name[5] = IFDATA_LINKSPECIFIC;
283 			len = sizeof(atm);
284 			if (sysctl(name, 6, &atm, &len, NULL, 0) == -1)
285 				err(1, "interface %d: ATM mib", idx);
286 
287 			d = malloc(sizeof(*d));
288 			if (d == NULL)
289 				err(1, NULL);
290 			bzero(d, sizeof(*d));
291 			d->mib = atm;
292 			d->index = idx;
293 			strcpy(d->ifname, mib.ifmd_name);
294 			TAILQ_INSERT_TAIL(&diagif_list, d, link);
295 
296 			if (phy_fetch(d->ifname, "type", &d->phy_type,
297 			    sizeof(d->phy_type), 0) == 0) {
298 				d->phy_present = 1;
299 				phy_fetch(d->ifname, "loopback",
300 				    &d->phy_loopback,
301 				    sizeof(d->phy_loopback), 1);
302 				phy_fetch(d->ifname, "name", &d->phy_name,
303 				    sizeof(d->phy_name), 1);
304 				phy_fetch(d->ifname, "state", &d->phy_state,
305 				    sizeof(d->phy_state), 1);
306 				phy_fetch(d->ifname, "carrier", &d->phy_carrier,
307 				    sizeof(d->phy_carrier), 1);
308 			}
309 		}
310 	}
311 }
312 
313 /*
314  * "<radix><bit>STRING\011<mask><pattern>STRING\012<mask><radix>STRING"
315  */
316 static char *
printb8(uint32_t val,const char * descr)317 printb8(uint32_t val, const char *descr)
318 {
319 	static char buffer[1000];
320 	char *ptr;
321 	int tmp = 0;
322 	u_char mask, pattern;
323 
324 	if (*descr++ == '\010')
325 		sprintf(buffer, "%#o", val);
326 	else
327 		sprintf(buffer, "%#x", val);
328 	ptr = buffer + strlen(buffer);
329 
330 	*ptr++ = '<';
331 	while (*descr) {
332 		if (*descr == '\11') {
333 			descr++;
334 			mask = *descr++;
335 			pattern = *descr++;
336 			if ((val & mask) == pattern) {
337 				if (tmp++)
338 					*ptr++ = ',';
339 				while (*descr >= ' ')
340 					*ptr++ = *descr++;
341 			} else {
342 				while (*descr >= ' ')
343 					descr++;
344 			}
345 		} else if (*descr == '\12') {
346 			descr++;
347 			mask = *descr++;
348 			pattern = *descr++;
349 			if (tmp++)
350 				*ptr++ = ',';
351 			while (*descr >= ' ')
352 				*ptr++ = *descr++;
353 			*ptr++ = '=';
354 			if (pattern == 8)
355 				sprintf(ptr, "%#o",
356 				    (val & mask) >> (ffs(mask)-1));
357 			else if (pattern == 10)
358 				sprintf(ptr, "%u",
359 				    (val & mask) >> (ffs(mask)-1));
360 			else
361 				sprintf(ptr, "%#x",
362 				    (val & mask) >> (ffs(mask)-1));
363 			ptr += strlen(ptr);
364 		} else {
365 			if (val & (1 << (*descr++ - 1))) {
366 				if (tmp++)
367 					*ptr++ = ',';
368 				while (*descr >= ' ')
369 					*ptr++ = *descr++;
370 			} else {
371 				while (*descr >= ' ')
372 					descr++;
373 			}
374 		}
375 	}
376 	*ptr++ = '>';
377 	*ptr++ = '\0';
378 
379 	return (buffer);
380 }
381 
382 /*
383  * "<radix><bit>STRING<bit>STRING"
384  */
385 static char *
printb(uint32_t val,const char * descr)386 printb(uint32_t val, const char *descr)
387 {
388 	static char buffer[1000];
389 	char *ptr;
390 	int tmp = 0;
391 
392 	if (*descr++ == '\010')
393 		sprintf(buffer, "%#o", val);
394 	else
395 		sprintf(buffer, "%#x", val);
396 	ptr = buffer + strlen(buffer);
397 
398 	*ptr++ = '<';
399 	while (*descr) {
400 		if (val & (1 << (*descr++ - 1))) {
401 			if (tmp++)
402 				*ptr++ = ',';
403 			while (*descr > ' ')
404 				*ptr++ = *descr++;
405 		} else {
406 			while (*descr > ' ')
407 				descr++;
408 		}
409 	}
410 	*ptr++ = '>';
411 	*ptr++ = '\0';
412 
413 	return (buffer);
414 }
415 
416 
417 static void
diag_loop(int argc,char * argv[],const char * text,void (* func)(const struct diagif *))418 diag_loop(int argc, char *argv[], const char *text,
419     void (*func)(const struct diagif *))
420 {
421 	int i;
422 	struct diagif *aif;
423 
424 	heading_init();
425 	if (argc > 0) {
426 		for (i = 0; i < argc; i++) {
427 			TAILQ_FOREACH(aif, &diagif_list, link) {
428 				if (strcmp(argv[i], aif->ifname) == 0) {
429 					heading("%s", text);
430 					(*func)(aif);
431 					break;
432 				}
433 			}
434 			if (aif == NULL)
435 				warnx("%s: no such ATM interface", argv[i]);
436 		}
437 	} else {
438 		TAILQ_FOREACH(aif, &diagif_list, link) {
439 			heading("%s", text);
440 			(*func)(aif);
441 		}
442 	}
443 }
444 
445 /*
446  * Print the config line for the given interface
447  */
448 static void
config_line1(const struct diagif * aif)449 config_line1(const struct diagif *aif)
450 {
451 	printf("%-6u%-9s%-8u%-5u%-6u%-5u%-6u%02x:%02x:%02x:%02x:%02x:%02x\n",
452 	    aif->index, aif->ifname, aif->mib.pcr, (1 << aif->mib.vpi_bits) - 1,
453 	    (1 << aif->mib.vci_bits) - 1, aif->mib.max_vpcs, aif->mib.max_vccs,
454 	    aif->mib.esi[0], aif->mib.esi[1], aif->mib.esi[2],
455 	    aif->mib.esi[3], aif->mib.esi[4], aif->mib.esi[5]);
456 }
457 
458 static void
config_line2(const struct diagif * aif)459 config_line2(const struct diagif *aif)
460 {
461 	u_int d, i;
462 
463 	static const struct {
464 		const char *dev;
465 		const char *vendor;
466 	} devs[] = {
467 		ATM_DEVICE_NAMES
468 	};
469 	static const struct {
470 		u_int	media;
471 		const char *const name;
472 	} medias[] = IFM_SUBTYPE_ATM_DESCRIPTIONS;
473 
474 	for (i = 0; medias[i].name; i++)
475 		if (aif->mib.media == medias[i].media)
476 			break;
477 
478 	if ((d = aif->mib.device) >= sizeof(devs) / sizeof(devs[0]))
479 		d = 0;
480 
481 	printf("%-6u%-9s%-12.11s%-13.12s%-8u%-6x%-6x %s\n", aif->index,
482 	    aif->ifname, devs[d].vendor, devs[d].dev, aif->mib.serial,
483 	    aif->mib.hw_version, aif->mib.sw_version,
484 	    medias[i].name ? medias[i].name : "unknown");
485 }
486 
487 static void
diag_config(int argc,char * argv[])488 diag_config(int argc, char *argv[])
489 {
490 	int opt;
491 
492 	static int hardware;
493 	static int atm;
494 
495 	static const struct option opts[] = {
496 	    { "hardware", OPT_SIMPLE, &hardware },
497 	    { "atm", OPT_SIMPLE, &atm },
498 	    { NULL, 0, NULL }
499 	};
500 
501 	static const char config_text1[] =
502 	    "Interface              Max        Max\n"
503 	    "Index Name     PCR     VPI  VCI   VPCs VCCs  ESI\n";
504 	static const char config_text2[] =
505 	    "Interface                                       Version\n"
506 	    "Index Name     Vendor      Card         "
507 	    "Serial  HW    SW     Media\n";
508 
509 	while ((opt = parse_options(&argc, &argv, opts)) != -1)
510 		switch (opt) {
511 		}
512 
513 	diagif_fetch();
514 	if (TAILQ_EMPTY(&diagif_list))
515 		errx(1, "no ATM interfaces found");
516 
517 	if (!atm && !hardware)
518 		atm = 1;
519 
520 	if (atm)
521 		diag_loop(argc, argv, config_text1, config_line1);
522 	if (hardware)
523 		diag_loop(argc, argv, config_text2, config_line2);
524 
525 }
526 
527 static void
diag_list(int argc,char * argv[])528 diag_list(int argc, char *argv[])
529 {
530 	int opt;
531 	struct diagif *aif;
532 
533 	static const struct option opts[] = {
534 	    { NULL, 0, NULL }
535 	};
536 
537 	while ((opt = parse_options(&argc, &argv, opts)) != -1)
538 		switch (opt) {
539 		}
540 
541 	if (argc > 0)
542 		errx(1, "no arguments required for 'diag list'");
543 
544 	diagif_fetch();
545 	if (TAILQ_EMPTY(&diagif_list))
546 		errx(1, "no ATM interfaces found");
547 
548 	TAILQ_FOREACH(aif, &diagif_list, link)
549 		printf("%s ", aif->ifname);
550 	printf("\n");
551 }
552 
553 /*
554  * Print the config line for the given interface
555  */
556 static void
phy_show_line(const struct diagif * aif)557 phy_show_line(const struct diagif *aif)
558 {
559 	printf("%-6u%-9s", aif->index, aif->ifname);
560 	if (aif->phy_present)
561 		printf("%-5u%-25s0x%-9x", aif->phy_type,
562 		    aif->phy_name, aif->phy_loopback);
563 	printf("\n");
564 }
565 
566 static void
diag_phy_show(int argc,char * argv[])567 diag_phy_show(int argc, char *argv[])
568 {
569 	int opt;
570 
571 	static const struct option opts[] = {
572 	    { NULL, 0, NULL }
573 	};
574 
575 	static const char phy_show_text[] =
576 	    "Interface      Phy\n"
577 	    "Index Name     Type Name                     Loopback State\n";
578 
579 	while ((opt = parse_options(&argc, &argv, opts)) != -1)
580 		switch (opt) {
581 		}
582 
583 	diagif_fetch();
584 	if (TAILQ_EMPTY(&diagif_list))
585 		errx(1, "no ATM interfaces found");
586 
587 	diag_loop(argc, argv, phy_show_text, phy_show_line);
588 }
589 
590 /*
591  * Make sure the interface exists and has a phy
592  */
593 static struct diagif *
diagif_get_phy(const char * arg)594 diagif_get_phy(const char *arg)
595 {
596 	struct diagif *aif;
597 
598 	diagif_fetch();
599 	TAILQ_FOREACH(aif, &diagif_list, link)
600 		if (strcmp(aif->ifname, arg) == 0)
601 			break;
602 	if (aif == NULL)
603 		errx(1, "no such interface: %s", arg);
604 	if (!aif->phy_present)
605 		errx(1, "interface %s has no phy", arg);
606 
607 	return (aif);
608 }
609 
610 static void
diag_phy_set(int argc,char * argv[])611 diag_phy_set(int argc, char *argv[])
612 {
613 	int opt;
614 	uint8_t reg[3];
615 	u_long res;
616 	char *end;
617 	char *str;
618 
619 	static const struct option opts[] = {
620 	    { NULL, 0, NULL }
621 	};
622 
623 	while ((opt = parse_options(&argc, &argv, opts)) != -1)
624 		switch (opt) {
625 		}
626 
627 	if (argc != 4)
628 		errx(1, "missing arguments for 'diag phy set'");
629 
630 	errno = 0;
631 	res = strtoul(argv[1], &end, 0);
632 	if (errno != 0)
633 		err(1, "register number");
634 	if (*end != '\0')
635 		errx(1, "malformed register number '%s'", argv[1]);
636 	if (res > 0xff)
637 		errx(1, "register number too large");
638 	reg[0] = res;
639 
640 	errno = 0;
641 	res = strtoul(argv[2], &end, 0);
642 	if (errno != 0)
643 		err(1, "mask");
644 	if (*end != '\0')
645 		errx(1, "malformed mask '%s'", argv[1]);
646 	if (res > 0xff)
647 		errx(1, "mask too large");
648 	reg[1] = res;
649 
650 	errno = 0;
651 	res = strtoul(argv[3], &end, 0);
652 	if (errno != 0)
653 		err(1, "value");
654 	if (*end != '\0')
655 		errx(1, "malformed value '%s'", argv[1]);
656 	if (res > 0xff)
657 		errx(1, "value too large");
658 	reg[2] = res;
659 
660 	(void)diagif_get_phy(argv[0]);
661 
662 	if (asprintf(&str, "hw.atm.%s.phy_regs", argv[0]) == -1)
663 		err(1, NULL);
664 
665 	if (sysctlbyname(str, NULL, NULL, reg, 3 * sizeof(uint8_t)))
666 		err(1, "%s", str);
667 
668 	free(str);
669 }
670 
671 static void
diag_phy_print(int argc,char * argv[])672 diag_phy_print(int argc, char *argv[])
673 {
674 	int opt;
675 	char *str;
676 	size_t len, len1;
677 	uint8_t *regs;
678 	u_int type, i;
679 	const struct utopia_print *p;
680 
681 	static int numeric;
682 
683 	static const struct option opts[] = {
684 	    { "numeric", OPT_SIMPLE, &numeric },
685 	    { NULL, 0, NULL }
686 	};
687 
688 	while ((opt = parse_options(&argc, &argv, opts)) != -1)
689 		switch (opt) {
690 		}
691 
692 	if (argc != 1)
693 		errx(1, "need device name for 'diag phy print'");
694 
695 	(void)diagif_get_phy(argv[0]);
696 
697 	if (asprintf(&str, "hw.atm.%s.phy_regs", argv[0]) == -1)
698 		err(1, NULL);
699 	len = 0;
700 	if (sysctlbyname(str, NULL, &len, NULL, 0))
701 		err(1, "'%s' not found", str);
702 
703 	regs = malloc(len);
704 	if (regs == NULL)
705 		err(1, NULL);
706 
707 	if (sysctlbyname(str, regs, &len, NULL, 0))
708 		err(1, "'%s' not found", str);
709 	free(str);
710 
711 	if (numeric) {
712 		for (i = 0; i < len; i++) {
713 			if (i % 16 == 0)
714 				printf("%02x: ", i);
715 			if (i % 16 == 8)
716 				printf(" ");
717 			printf(" %02x", regs[i]);
718 			if (i % 16 == 15)
719 				printf("\n");
720 		}
721 		if (i % 16 != 0)
722 			printf("\n");
723 	} else {
724 		if (asprintf(&str, "hw.atm.%s.phy_type", argv[0]) == -1)
725 			err(1, NULL);
726 		len1 = sizeof(type);
727 		if (sysctlbyname(str, &type, &len1, NULL, 0))
728 			err(1, "'%s' not found", str);
729 		free(str);
730 
731 		for (i = 0; i < sizeof(phy_print) / sizeof(phy_print[0]); i++)
732 			if (type == phy_print[i].type)
733 				break;
734 		if (i == sizeof(phy_print) / sizeof(phy_print[0]))
735 			errx(1, "unknown PHY chip type %u\n", type);
736 
737 		for (p = phy_print[i].tab;
738 		    p < phy_print[i].tab + phy_print[i].len;
739 		    p++) {
740 			if (p->reg + utopia_addreg[p->type] > len)
741 				/* don't have this register */
742 				continue;
743 
744 			printf("%s:%*s", p->name, 40 - (int)strlen(p->name),"");
745 
746 			switch (p->type) {
747 
748 			  case UTP_REGT_BITS:
749 				printf("%s\n", printb8(regs[p->reg], p->fmt));
750 				break;
751 
752 			  case UTP_REGT_INT8:
753 				printf("%#x\n", regs[p->reg]);
754 				break;
755 
756 			  case UTP_REGT_INT10BITS:
757 				printf("%#x %s\n", regs[p->reg] |
758 				    ((regs[p->reg + 1] & 0x3) << 8),
759 				    printb8(regs[p->reg + 1], p->fmt));
760 				break;
761 
762 			  case UTP_REGT_INT12:
763 				printf("%#x\n", regs[p->reg] |
764 				    ((regs[p->reg + 1] & 0xf) << 8));
765 				break;
766 
767 			  case UTP_REGT_INT16:
768 				printf("%#x\n", regs[p->reg] |
769 				    (regs[p->reg + 1] << 8));
770 				break;
771 
772 			  case UTP_REGT_INT19:
773 				printf("%#x\n", regs[p->reg] |
774 				    (regs[p->reg + 1] << 8) |
775 				    ((regs[p->reg + 2] & 0x7) << 16));
776 				break;
777 
778 			  case UTP_REGT_INT20:
779 				printf("%#x\n", regs[p->reg] |
780 				    (regs[p->reg + 1] << 8) |
781 				    ((regs[p->reg + 2] & 0xf) << 16));
782 				break;
783 
784 			  case UTP_REGT_INT21:
785 				printf("%#x\n", regs[p->reg] |
786 				    (regs[p->reg + 1] << 8) |
787 				    ((regs[p->reg + 2] & 0x1f) << 16));
788 				break;
789 
790 			  default:
791 				abort();
792 			}
793 		}
794 	}
795 	free(regs);
796 }
797 
798 static void
diag_phy_stats(int argc,char * argv[])799 diag_phy_stats(int argc, char *argv[])
800 {
801 	int opt;
802 	size_t len;
803 	char *str;
804 	struct utopia_stats1 stats1;
805 	u_int foo;
806 
807 	static int clear;
808 
809 	static const struct option opts[] = {
810 	    { "clear", OPT_SIMPLE, &clear },
811 	    { NULL, 0, NULL }
812 	};
813 
814 	while ((opt = parse_options(&argc, &argv, opts)) != -1)
815 		switch (opt) {
816 		}
817 
818 	if (argc != 1)
819 		errx(1, "need device name for 'diag phy stats'");
820 
821 	(void)diagif_get_phy(argv[0]);
822 
823 	if (asprintf(&str, "hw.atm.%s.phy_stats", argv[0]) == -1)
824 		err(1, NULL);
825 
826 	len = sizeof(stats1);
827 	if (sysctlbyname(str, &stats1, &len,
828 	    clear ? &foo : NULL, clear ? sizeof(foo) : 0))
829 		err(1, "'%s' not found", str);
830 	if (len < sizeof(stats1.version))
831 		errx(1, "phy statistics too short %zu", len);
832 
833 	switch (stats1.version) {
834 
835 	  case 1:
836 		if (len != sizeof(stats1))
837 			errx(1, "bad phy stats length %zu (expecting %zu)",
838 			    len, sizeof(stats1));
839 		break;
840 
841 	  default:
842 		errx(1, "unknown phy stats version %u", stats1.version);
843 	}
844 
845 	free(str);
846 
847 	printf("rx_sbip:	%llu\n", (unsigned long long)stats1.rx_sbip);
848 	printf("rx_lbip:	%llu\n", (unsigned long long)stats1.rx_lbip);
849 	printf("rx_lfebe:	%llu\n", (unsigned long long)stats1.rx_lfebe);
850 	printf("rx_pbip:	%llu\n", (unsigned long long)stats1.rx_pbip);
851 	printf("rx_pfebe:	%llu\n", (unsigned long long)stats1.rx_pfebe);
852 	printf("rx_cells:	%llu\n", (unsigned long long)stats1.rx_cells);
853 	printf("rx_corr:	%llu\n", (unsigned long long)stats1.rx_corr);
854 	printf("rx_uncorr:	%llu\n", (unsigned long long)stats1.rx_uncorr);
855 	printf("rx_symerr:	%llu\n", (unsigned long long)stats1.rx_symerr);
856 	printf("tx_cells:	%llu\n", (unsigned long long)stats1.tx_cells);
857 }
858 
859 /*
860  * Fetch the table of open vccs
861  */
862 void
diagif_fetch_vcc(struct diagif * aif,int fd)863 diagif_fetch_vcc(struct diagif *aif, int fd)
864 {
865 	struct ifreq ifr;
866 
867 	if (aif->vtab != NULL)
868 		return;
869 
870 	strncpy(ifr.ifr_name, aif->ifname, IFNAMSIZ);
871 	ifr.ifr_name[IFNAMSIZ - 1] = '\0';
872 
873 	aif->vtab = malloc(sizeof(*aif->vtab) + sizeof(aif->vtab->vccs[0]) *
874 	    aif->mib.max_vccs);
875 	if (aif->vtab == NULL)
876 		err(1, NULL);
877 	ifr.ifr_data = (caddr_t)aif->vtab;
878 
879 	if (ioctl(fd, SIOCATMGVCCS, &ifr) == -1)
880 		err(1, "SIOCATMGVCCS");
881 }
882 
883 /*
884  * Print the VCC table for this interface.
885  */
886 static void
print_channel(const struct diagif * aif)887 print_channel(const struct diagif *aif)
888 {
889 	const struct atmio_vcc *v;
890 
891 	static const char *const aal_tab[] = {
892 		[ATMIO_AAL_0] = "0",
893 		[ATMIO_AAL_34] = "3/4",
894 		[ATMIO_AAL_5] = "5",
895 		[ATMIO_AAL_RAW] = "raw",
896 	};
897 	static const char *const traffic_tab[] = {
898 		[ATMIO_TRAFFIC_UBR] = "ubr",
899 		[ATMIO_TRAFFIC_CBR] = "cbr",
900 		[ATMIO_TRAFFIC_ABR] = "abr",
901 		[ATMIO_TRAFFIC_VBR] = "vbr",
902 	};
903 
904 	for (v = aif->vtab->vccs; v < &aif->vtab->vccs[aif->vtab->count]; v++) {
905 		printf("%-6u%-9s%-4u%-6u", aif->index, aif->ifname,
906 		    v->vpi, v->vci);
907 
908 		if (v->aal >= sizeof(aal_tab)/sizeof(aal_tab[0]) ||
909 		    aal_tab[v->aal] == NULL)
910 			printf("bad ");
911 		else
912 			printf("%-4s", aal_tab[v->aal]);
913 
914 		if (v->traffic >= sizeof(traffic_tab)/sizeof(traffic_tab[0]) ||
915 		    traffic_tab[v->traffic] == NULL)
916 			printf("bad     ");
917 		else
918 			printf("%-8s", traffic_tab[v->traffic]);
919 
920 		printf("%-6u%-6u%s\n", v->rmtu, v->tmtu,
921 		    printb(v->flags, ATMIO_FLAGS));
922 	}
923 }
924 
925 /*
926  * Print the VCC table for this interface, traffic parameters.
927  */
928 static void
print_traffic(const struct diagif * aif)929 print_traffic(const struct diagif *aif)
930 {
931 	const struct atmio_vcc *v;
932 
933 	for (v = aif->vtab->vccs; v < &aif->vtab->vccs[aif->vtab->count]; v++) {
934 		printf("%-6u%-9s%-4u%-6u", aif->index, aif->ifname,
935 		    v->vpi, v->vci);
936 
937 		switch (v->traffic) {
938 
939 		  case ATMIO_TRAFFIC_CBR:
940 			printf("%u", v->tparam.pcr);
941 			break;
942 
943 		  case ATMIO_TRAFFIC_UBR:
944 			printf("%-8u                %u", v->tparam.pcr,
945 			    v->tparam.mcr);
946 			break;
947 
948 		  case ATMIO_TRAFFIC_VBR:
949 			printf("%-8u%-8u%-8u", v->tparam.pcr, v->tparam.scr,
950 			    v->tparam.mbs);
951 			break;
952 
953 		  case ATMIO_TRAFFIC_ABR:
954 			printf("%-8u                %-8u",
955 			    v->tparam.pcr, v->tparam.mcr);
956 			break;
957 		}
958 		printf("\n");
959 	}
960 }
961 
962 /*
963  * Print the VCC table for this interface, ABR traffic parameters.
964  */
965 static void
print_abr(const struct diagif * aif)966 print_abr(const struct diagif *aif)
967 {
968 	const struct atmio_vcc *v;
969 
970 	for (v = aif->vtab->vccs; v < &aif->vtab->vccs[aif->vtab->count]; v++) {
971 		printf("%-6u%-9s%-4u%-6u", aif->index, aif->ifname,
972 		    v->vpi, v->vci);
973 
974 		if (v->traffic == ATMIO_TRAFFIC_ABR) {
975 			printf("%-8u%-8u%-4u%-4u%-5u%-5u%-5u%u",
976 			    v->tparam.icr, v->tparam.tbe, v->tparam.nrm,
977 			    v->tparam.trm, v->tparam.adtf, v->tparam.rif,
978 			    v->tparam.rdf, v->tparam.cdf);
979 		}
980 		printf("\n");
981 	}
982 }
983 
984 static void
diag_vcc_loop(void (* func)(const struct diagif *),const char * text,int argc,char * argv[],int fd)985 diag_vcc_loop(void (*func)(const struct diagif *), const char *text,
986     int argc, char *argv[], int fd)
987 {
988 	struct diagif *aif;
989 
990 	heading_init();
991 	if (argc == 0) {
992 		TAILQ_FOREACH(aif, &diagif_list, link) {
993 			diagif_fetch_vcc(aif, fd);
994 			if (aif->vtab->count != 0) {
995 				heading("%s", text);
996 				(*func)(aif);
997 			}
998 		}
999 
1000 	} else {
1001 		for (optind = 0; optind < argc; optind++) {
1002 			TAILQ_FOREACH(aif, &diagif_list, link)
1003 				if (strcmp(aif->ifname, argv[optind]) == 0) {
1004 					diagif_fetch_vcc(aif, fd);
1005 					if (aif->vtab->count != 0) {
1006 						heading("%s", text);
1007 						(*func)(aif);
1008 					}
1009 					break;
1010 				}
1011 			if (aif == NULL)
1012 				warnx("no such interface '%s'", argv[optind]);
1013 		}
1014 	}
1015 }
1016 
1017 static void
diag_vcc(int argc,char * argv[])1018 diag_vcc(int argc, char *argv[])
1019 {
1020 	int opt, fd;
1021 
1022 	static int channel, traffic, abr;
1023 	static const struct option opts[] = {
1024 	    { "abr", OPT_SIMPLE, &abr },
1025 	    { "channel", OPT_SIMPLE, &channel },
1026 	    { "traffic", OPT_SIMPLE, &traffic },
1027 	    { NULL, 0, NULL }
1028 	};
1029 	static const char head_channel[] =
1030 	    "Interface\n"
1031 	    "Index Name     VPI VCI   AAL Traffic RxMTU TxMTU Flags\n";
1032 	static const char head_traffic[] =
1033 	    "Interface                Traffic parameters\n"
1034 	    "Index Name     VPI VCI   PCR     SCR     MBS     MCR\n";
1035 	static const char head_abr[] =
1036 	    "Interface                ABR traffic parameters\n"
1037 	    "Index Name     VPI VCI   ICR     TBE     NRM TRM ADTF RIF  RDF  "
1038 	    "CDF\n";
1039 
1040 	while ((opt = parse_options(&argc, &argv, opts)) != -1)
1041 		switch (opt) {
1042 		}
1043 
1044 	fd = socket(PF_NATM, SOCK_STREAM, PROTO_NATMAAL5);
1045 	if (fd < 0)
1046 		err(1, "socket");
1047 
1048 	diagif_fetch();
1049 	if (TAILQ_EMPTY(&diagif_list))
1050 		errx(1, "no ATM interfaces found");
1051 
1052 	if (!channel && !traffic && !abr)
1053 		channel = 1;
1054 
1055 	if (channel)
1056 		diag_vcc_loop(print_channel, head_channel, argc, argv, fd);
1057 	if (traffic)
1058 		diag_vcc_loop(print_traffic, head_traffic, argc, argv, fd);
1059 	if (abr)
1060 		diag_vcc_loop(print_abr, head_abr, argc, argv, fd);
1061 }
1062 
1063 /*
1064  * Print driver-internal statistics
1065  */
1066 static void
diag_stats(int argc,char * argv[])1067 diag_stats(int argc, char *argv[])
1068 {
1069 	int opt;
1070 	char *str;
1071 	size_t len;
1072 	uint32_t *stats;
1073 	struct diagif *aif;
1074 	u_int i;
1075 
1076 	static const struct option opts[] = {
1077 	    { NULL, 0, NULL }
1078 	};
1079 
1080 	while ((opt = parse_options(&argc, &argv, opts)) != -1)
1081 		switch (opt) {
1082 		}
1083 
1084 	if (argc != 1)
1085 		errx(1, "need one arg for 'diag stats'");
1086 
1087 	diagif_fetch();
1088 	TAILQ_FOREACH(aif, &diagif_list, link)
1089 		if (strcmp(aif->ifname, argv[0]) == 0)
1090 			break;
1091 
1092 	if (aif == NULL)
1093 		errx(1, "interface '%s' not found", argv[0]);
1094 
1095 	if (asprintf(&str, "hw.atm.%s.istats", argv[0]) == -1)
1096 		err(1, NULL);
1097 	len = 0;
1098 	if (sysctlbyname(str, NULL, &len, NULL, 0))
1099 		err(1, "'%s' not found", str);
1100 
1101 	stats = malloc(len);
1102 	if (stats == NULL)
1103 		err(1, NULL);
1104 
1105 	if (sysctlbyname(str, stats, &len, NULL, 0))
1106 		err(1, "'%s' not found", str);
1107 	free(str);
1108 
1109 	if (aif->mib.device >= sizeof(print_stats) / sizeof(print_stats[0]) ||
1110 	    print_stats[aif->mib.device] == NULL)
1111 		errx(1, "unknown stats format (%u)", aif->mib.device);
1112 
1113 	for (i = 0; print_stats[aif->mib.device][i] != NULL; i++) {
1114 		if (i * sizeof(uint32_t) >= len)
1115 			errx(1, "debug info too short (version mismatch?)");
1116 		printf("%-22s%u\n", print_stats[aif->mib.device][i], stats[i]);
1117 	}
1118 	free(stats);
1119 
1120 	if (i != len / sizeof(uint32_t))
1121 		errx(1, "debug info too long (version mismatch?)");
1122 }
1123