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