8795f5d240cbc55bdddfa2ee63875c0b13bf60a2
[dragonfly.git] / sbin / atm / atm / atm_show.c
1 /*
2  *
3  * ===================================
4  * HARP  |  Host ATM Research Platform
5  * ===================================
6  *
7  *
8  * This Host ATM Research Platform ("HARP") file (the "Software") is
9  * made available by Network Computing Services, Inc. ("NetworkCS")
10  * "AS IS".  NetworkCS does not provide maintenance, improvements or
11  * support of any kind.
12  *
13  * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
14  * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
15  * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
16  * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
17  * In no event shall NetworkCS be responsible for any damages, including
18  * but not limited to consequential damages, arising from or relating to
19  * any use of the Software or related support.
20  *
21  * Copyright 1994-1998 Network Computing Services, Inc.
22  *
23  * Copies of this Software may be made, however, the above copyright
24  * notice must be reproduced on all copies.
25  *
26  *      @(#) $FreeBSD: src/sbin/atm/atm/atm_show.c,v 1.3.2.1 2000/07/01 06:02:14 ps Exp $
27  *      @(#) $DragonFly: src/sbin/atm/atm/atm_show.c,v 1.2 2003/06/17 04:27:32 dillon Exp $
28  */
29
30 /*
31  * User configuration and display program
32  * --------------------------------------
33  *
34  * Routines for "show" subcommand
35  *
36  */
37
38 #include <sys/param.h>  
39 #include <sys/socket.h> 
40 #include <net/if.h>
41 #include <netinet/in.h>
42 #include <netatm/port.h>
43 #include <netatm/atm.h>
44 #include <netatm/atm_if.h> 
45 #include <netatm/atm_sap.h>
46 #include <netatm/atm_sys.h>
47 #include <netatm/atm_vc.h>
48 #include <netatm/atm_ioctl.h>
49
50 #include <errno.h>
51 #include <libatm.h>
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55
56 #include "atm.h"
57
58 /*
59  * Local functions
60  */
61 static int      vcc_compare __P((const void *, const void *));
62 static int      ip_vcc_compare __P((const void *, const void *));
63 static int      arp_compare __P((const void *, const void *));
64
65
66 /*
67  * Process show ARP command
68  * 
69  * Command format: 
70  *      atm show ARP [<ip-addr>]
71  *
72  * Arguments:
73  *      argc    number of remaining arguments to command
74  *      argv    pointer to remaining argument strings
75  *      cmdp    pointer to command description 
76  *
77  * Returns:
78  *      none
79  *
80  */
81 void
82 show_arp(argc, argv, cmdp)
83         int             argc;
84         char            **argv;
85         struct cmd      *cmdp;
86 {
87         int                     buf_len, arp_info_len;
88         struct atminfreq        air;
89         struct air_arp_rsp      *arp_info, *arp_info_base;
90         struct sockaddr_in      *sin;
91         union {
92                 struct sockaddr_in      sin;
93                 struct sockaddr         sa;
94         } host_addr;
95
96         /*
97          * Get IP address of specified host name
98          */
99         UM_ZERO(&host_addr, sizeof(host_addr));
100         host_addr.sa.sa_family = AF_INET;
101         if (argc) {
102                 sin = get_ip_addr(argv[0]);
103                 if (!sin) {
104                         fprintf(stderr, "%s: host \'%s\' not found\n",
105                                         prog, argv[0]);
106                         exit(1);
107                 }
108                 host_addr.sin.sin_addr.s_addr = sin->sin_addr.s_addr;
109         } else {
110                 host_addr.sin.sin_addr.s_addr = INADDR_ANY;
111         }
112
113         /*
114          * Get ARP information from the kernel
115          */
116         UM_ZERO(&air, sizeof(air));
117         buf_len = sizeof(struct air_arp_rsp) * 10;
118         air.air_opcode = AIOCS_INF_ARP;
119         air.air_arp_addr = host_addr.sa;
120         arp_info_len = do_info_ioctl(&air, buf_len);
121         if (arp_info_len < 0) {
122                 fprintf(stderr, "%s: ", prog);
123                 switch (errno) {
124                 case ENOPROTOOPT:
125                 case EOPNOTSUPP:
126                         perror("Internal error");
127                         break;
128                 case ENXIO:
129                         fprintf(stderr, "not an ATM device\n");
130                         break;
131                 default:
132                         perror("ioctl (AIOCINFO)");
133                         break;
134                 }
135                 exit(1);
136         }
137         arp_info_base = arp_info =
138                         (struct air_arp_rsp *) air.air_buf_addr;
139
140         /*
141          * Sort the ARP table
142          */
143         qsort((void *) arp_info,
144                         arp_info_len / sizeof(struct air_arp_rsp),
145                         sizeof(struct air_arp_rsp),
146                         arp_compare);
147
148         /*
149          * Print the relevant information
150          */
151         while (arp_info_len > 0) {
152                 print_arp_info(arp_info);
153                 arp_info++;
154                 arp_info_len -= sizeof(struct air_arp_rsp);
155         }
156
157         /*
158          * Release the information from the kernel
159          */
160         UM_FREE(arp_info_base);
161 }
162
163
164 /*
165  * Process show ATM ARP server command
166  * 
167  * Command format: 
168  *      atm show arpserver [<interface-name>]
169  *
170  * Arguments:
171  *      argc    number of remaining arguments to command
172  *      argv    pointer to remaining argument strings
173  *      cmdp    pointer to command description 
174  *
175  * Returns:
176  *      none
177  *
178  */
179 void
180 show_arpserv(argc, argv, cmdp)
181         int             argc;
182         char            **argv;
183         struct cmd      *cmdp;
184 {
185         int     asrv_info_len, buf_len = sizeof(struct air_asrv_rsp) * 3;
186         struct atminfreq        air;
187         struct air_asrv_rsp     *asrv_info, *asrv_info_base;
188
189         /*
190          * Validate interface name
191          */
192         UM_ZERO(air.air_int_intf, sizeof(air.air_int_intf));
193         if (argc) {
194                 if (strlen(argv[0]) > IFNAMSIZ - 1) {
195                         fprintf(stderr, "%s: Illegal interface name\n",
196                                         prog);
197                         exit(1);
198                 }
199                 strcpy(air.air_int_intf, argv[0]);
200                 argc--; argv++;
201         }
202
203         /*
204          * Get interface information from the kernel
205          */
206         air.air_opcode = AIOCS_INF_ASV;
207         buf_len = do_info_ioctl(&air, buf_len);
208         if (buf_len < 0) {
209                 fprintf(stderr, "%s: ", prog);
210                 switch (errno) {
211                 case ENOPROTOOPT:
212                 case EOPNOTSUPP:
213                         perror("Internal error");
214                         break;
215                 case ENXIO:
216                         fprintf(stderr, "%s is not an ATM device\n",
217                                         argv[0]);
218                         break;
219                 default:
220                         perror("ioctl (AIOCINFO)");
221                         break;
222                 }
223                 exit(1);
224         }
225
226         /*
227          * Print the interface information
228          */
229         asrv_info_base = asrv_info =
230                         (struct air_asrv_rsp *) air.air_buf_addr;
231         for (; buf_len >= sizeof(struct air_asrv_rsp);
232                         asrv_info = (struct air_asrv_rsp *)
233                                 ((u_long)asrv_info + asrv_info_len),
234                         buf_len -= asrv_info_len) {
235                 print_asrv_info(asrv_info);
236                 asrv_info_len = sizeof(struct air_asrv_rsp) +
237                                 asrv_info->asp_nprefix *
238                                 sizeof(struct in_addr) * 2;
239         }
240         UM_FREE(asrv_info_base);
241 }
242
243
244 /*
245  * Process show ATM adapter configuration command
246  * 
247  * Command format: 
248  *      atm show config [<interface-name>]
249  *
250  * Arguments:
251  *      argc    number of remaining arguments to command
252  *      argv    pointer to remaining argument strings
253  *      cmdp    pointer to command description 
254  *
255  * Returns:
256  *      none
257  *
258  */
259 void
260 show_config(argc, argv, cmdp)
261         int             argc;
262         char            **argv;
263         struct cmd      *cmdp;
264 {
265         int     buf_len = sizeof(struct air_asrv_rsp) * 3;
266         struct atminfreq        air;
267         struct air_cfg_rsp      *cfg_info, *cfg_info_base;
268
269         /*
270          * Validate interface name
271          */
272         UM_ZERO(air.air_cfg_intf, sizeof(air.air_cfg_intf));
273         if (argc) {
274                 if (strlen(argv[0]) > IFNAMSIZ - 1) {
275                         fprintf(stderr, "%s: Illegal interface name\n",
276                                         prog);
277                         exit(1);
278                 }
279                 strcpy(air.air_cfg_intf, argv[0]);
280                 argc--; argv++;
281         }
282
283         /*
284          * Get configuration information from the kernel
285          */
286         air.air_opcode = AIOCS_INF_CFG;
287         buf_len = do_info_ioctl(&air, buf_len);
288         if (buf_len < 0) {
289                 fprintf(stderr, "%s: ", prog);
290                 switch (errno) {
291                 case ENOPROTOOPT:
292                 case EOPNOTSUPP:
293                         perror("Internal error");
294                         break;
295                 case ENXIO:
296                         fprintf(stderr, "%s is not an ATM device\n",
297                                         argv[0]);
298                         break;
299                 default:
300                         perror("ioctl (AIOCINFO)");
301                         break;
302                 }
303                 exit(1);
304         }
305
306         /*
307          * Print the interface information
308          */
309         cfg_info_base = cfg_info =
310                         (struct air_cfg_rsp *) air.air_buf_addr;
311         for (; buf_len >= sizeof(struct air_cfg_rsp); cfg_info++,
312                         buf_len -= sizeof(struct air_cfg_rsp)) {
313                 print_cfg_info(cfg_info);
314         }
315         UM_FREE(cfg_info_base);
316 }
317
318
319 /*
320  * Process show interface command
321  * 
322  * Command format: 
323  *      atm show interface [<interface-name>]
324  *
325  * Arguments:
326  *      argc    number of remaining arguments to command
327  *      argv    pointer to remaining argument strings
328  *      cmdp    pointer to command description 
329  *
330  * Returns:
331  *      none
332  *
333  */
334 void
335 show_intf(argc, argv, cmdp)
336         int             argc;
337         char            **argv;
338         struct cmd      *cmdp;
339 {
340         int     buf_len = sizeof(struct air_int_rsp) * 3;
341         struct atminfreq        air;
342         struct air_int_rsp      *int_info, *int_info_base;
343
344         /*
345          * Validate interface name
346          */
347         UM_ZERO(&air, sizeof(air));
348         if (argc) {
349                 if (strlen(argv[0]) > IFNAMSIZ - 1) {
350                         fprintf(stderr, "%s: Illegal interface name\n",
351                                         prog);
352                         exit(1);
353                 }
354                 strcpy(air.air_int_intf, argv[0]);
355                 argc--; argv++;
356         }
357
358         /*
359          * Get interface information from the kernel
360          */
361         air.air_opcode = AIOCS_INF_INT;
362         buf_len = do_info_ioctl(&air, buf_len);
363         if (buf_len < 0) {
364                 fprintf(stderr, "%s: ", prog);
365                 switch (errno) {
366                 case ENOPROTOOPT:
367                 case EOPNOTSUPP:
368                         perror("Internal error");
369                         break;
370                 case ENXIO:
371                         fprintf(stderr, "%s is not an ATM device\n",
372                                         argv[0]);
373                         break;
374                 default:
375                         perror("ioctl (AIOCINFO)");
376                         break;
377                 }
378                 exit(1);
379         }
380
381         /*
382          * Print the interface information
383          */
384         int_info_base = int_info =
385                         (struct air_int_rsp *) air.air_buf_addr;
386         for (; buf_len >= sizeof(struct air_int_rsp); int_info++,
387                         buf_len -= sizeof(struct air_int_rsp)) {
388                 print_intf_info(int_info);
389         }
390         UM_FREE(int_info_base);
391 }
392
393
394 /*
395  * Process show IP VCCs command
396  * 
397  * Command format: 
398  *      atm show ipvcc [<ip-addr>]
399  *
400  * Arguments:
401  *      argc    number of remaining arguments to command
402  *      argv    pointer to remaining argument strings
403  *      cmdp    pointer to command description 
404  *
405  * Returns:
406  *      none
407  *
408  */
409 void
410 show_ip_vcc(argc, argv, cmdp)
411         int             argc;
412         char            **argv;
413         struct cmd      *cmdp;
414 {
415         int                     buf_len, ip_info_len, rc;
416         char                    *if_name = (char *)0;
417         struct atminfreq        air;
418         struct air_ip_vcc_rsp   *ip_info, *ip_info_base;
419         struct sockaddr_in      *sin;
420         union {
421                 struct sockaddr_in      sin;
422                 struct sockaddr         sa;
423         } host_addr;
424
425         /*
426          * First parameter can be a netif name, an IP host name, or
427          * an IP address.  Figure out which it is.
428          */
429         UM_ZERO(&host_addr, sizeof(host_addr));
430         host_addr.sa.sa_family = AF_INET;
431         if (argc) {
432                 rc = verify_nif_name(argv[0]);
433                 if (rc < 0) {
434                         /*
435                          * Error occured
436                          */
437                         fprintf(stderr, "%s: ", prog);
438                         switch (errno) {
439                         case ENOPROTOOPT:
440                         case EOPNOTSUPP:
441                                 perror("Internal error");
442                                 break;
443                         case ENXIO:
444                                 fprintf(stderr, "%s is not an ATM device\n",
445                                                 argv[0]);
446                                 break;
447                         default:
448                                 perror("ioctl (AIOCINFO)");
449                                 break;
450                         }
451                         exit(1);
452                 } else if (rc > 0) {
453                         /*
454                          * Parameter is a valid netif name
455                          */
456                         if_name = argv[0];
457                 } else {
458                         /*
459                          * Get IP address of specified host name
460                          */
461                         sin = get_ip_addr(argv[0]);
462                         host_addr.sin.sin_addr.s_addr =
463                                         sin->sin_addr.s_addr;
464                 }
465         } else {
466                 host_addr.sin.sin_addr.s_addr = INADDR_ANY;
467         }
468
469         /*
470          * Get IP map information from the kernel
471          */
472         buf_len = sizeof(struct air_ip_vcc_rsp) * 10;
473         air.air_opcode = AIOCS_INF_IPM;
474         air.air_ip_addr = host_addr.sa;
475         ip_info_len = do_info_ioctl(&air, buf_len);
476         if (ip_info_len < 0) {
477                 fprintf(stderr, "%s: ", prog);
478                 switch (errno) {
479                 case ENOPROTOOPT:
480                 case EOPNOTSUPP:
481                         perror("Internal error");
482                         break;
483                 case ENXIO:
484                         fprintf(stderr, "not an ATM device\n");
485                         break;
486                 default:
487                         perror("ioctl (AIOCINFO)");
488                         break;
489                 }
490                 exit(1);
491         }
492         ip_info_base = ip_info =
493                         (struct air_ip_vcc_rsp *) air.air_buf_addr;
494
495         /*
496          * Sort the information
497          */
498         qsort((void *) ip_info,
499                         ip_info_len / sizeof(struct air_ip_vcc_rsp),
500                         sizeof(struct air_ip_vcc_rsp),
501                         ip_vcc_compare);
502
503         /*
504          * Print the relevant information
505          */
506         while (ip_info_len>0) {
507                 if (!if_name || !strcmp(if_name, ip_info->aip_intf)) {
508                         print_ip_vcc_info(ip_info);
509                 }
510                 ip_info++;
511                 ip_info_len -= sizeof(struct air_ip_vcc_rsp);
512         }
513
514         /*
515          * Release the information from the kernel
516          */
517         UM_FREE(ip_info_base);
518
519 }
520
521
522 /*
523  * Process show network interface command
524  * 
525  * Command format: 
526  *      atm show netif [<netif>]
527  *
528  * Arguments:
529  *      argc    number of remaining arguments to command
530  *      argv    pointer to remaining argument strings
531  *      cmdp    pointer to command description 
532  *
533  * Returns:
534  *      none
535  *
536  */
537 void
538 show_netif(argc, argv, cmdp)
539         int             argc;
540         char            **argv;
541         struct cmd      *cmdp;
542 {
543         int     buf_len = sizeof(struct air_netif_rsp) * 3;
544         struct atminfreq        air;
545         struct air_netif_rsp    *int_info, *int_info_base;
546
547         /*
548          * Validate network interface name
549          */
550         UM_ZERO(air.air_int_intf, sizeof(air.air_int_intf));
551         if (argc) {
552                 if (strlen(argv[0]) > IFNAMSIZ - 1) {
553                         fprintf(stderr, "%s: Illegal interface name\n", prog);
554                         exit(1);
555                 }
556                 strcpy(air.air_int_intf, argv[0]);
557                 argc--; argv++;
558         }
559
560         /*
561          * Get network interface information from the kernel
562          */
563         air.air_opcode = AIOCS_INF_NIF;
564         buf_len = do_info_ioctl(&air, buf_len);
565         if (buf_len < 0) {
566                 fprintf(stderr, "%s: ", prog);
567                 switch (errno) {
568                 case ENOPROTOOPT:
569                 case EOPNOTSUPP:
570                         perror("Internal error");
571                         break;
572                 case ENXIO:
573                         fprintf(stderr, "%s is not an ATM device\n",
574                                         argv[0]);
575                         break;
576                 default:
577                         perror("ioctl (AIOCINFO)");
578                         break;
579                 }
580                 exit(1);
581         }
582
583         /*
584          * Print the network interface information
585          */
586         int_info_base = int_info =
587                         (struct air_netif_rsp *) air.air_buf_addr;
588         for (; buf_len >= sizeof(struct air_netif_rsp); int_info++,
589                         buf_len -= sizeof(struct air_netif_rsp)) {
590                 print_netif_info(int_info);
591         }
592         UM_FREE(int_info_base);
593 }
594
595
596 /*
597  * Process interface statistics command
598  * 
599  * Command format: 
600  *      atm show stats interface [<interface-name>]
601  *
602  * Arguments:
603  *      argc    number of remaining arguments to command
604  *      argv    pointer to remaining argument strings
605  *      cmdp    pointer to command description 
606  *
607  * Returns:
608  *      none
609  *
610  */
611 void
612 show_intf_stats(argc, argv, cmdp)
613         int             argc;
614         char            **argv;
615         struct cmd      *cmdp;
616 {
617         int                     buf_len;
618         char                    intf[IFNAMSIZ];
619         struct atminfreq        air;
620         struct air_phy_stat_rsp *pstat_info, *pstat_info_base;
621         struct air_cfg_rsp      *cfg_info;
622
623         /*
624          * Validate interface name
625          */
626         UM_ZERO(intf, sizeof(intf));
627         if (argc) {
628                 if (strlen(argv[0]) > IFNAMSIZ - 1) {
629                         fprintf(stderr, "%s: Illegal interface name\n",
630                                         prog);
631                         exit(1);
632                 }
633                 strcpy(intf, argv[0]);
634                 argc--; argv++;
635         }
636
637         /*
638          * If there are parameters remaining, the request is for
639          * vendor-specific adaptor statistics
640          */
641         if (argc) {
642                 /*
643                  * Get adapter configuration information
644                  */
645                 buf_len = sizeof(struct air_cfg_rsp);
646                 air.air_opcode = AIOCS_INF_CFG;
647                 strcpy(air.air_cfg_intf, intf);
648                 buf_len = do_info_ioctl(&air, buf_len);
649                 if (buf_len < 0) {
650                         fprintf(stderr, "%s: ", prog);
651                         switch (errno) {
652                         case ENOPROTOOPT:
653                         case EOPNOTSUPP:
654                                 perror("Internal error");
655                                 break;
656                         case ENXIO:
657                                 fprintf(stderr, "%s is not an ATM device\n",
658                                                 intf);
659                                 break;
660                         default:
661                                 perror("ioctl (AIOCINFO)");
662                                 break;
663                         }
664                         exit(1);
665                 }
666                 cfg_info = (struct air_cfg_rsp *)air.air_buf_addr;
667
668                 /*
669                  * Call the appropriate vendor-specific routine
670                  */
671                 switch(cfg_info->acp_vendor) {
672                 case VENDOR_FORE:
673                         show_fore200_stats(intf, argc, argv);
674                         break;
675                 case VENDOR_ENI:
676                         show_eni_stats(intf, argc, argv);
677                         break;
678                 default:
679                         fprintf(stderr, "%s: Unknown adapter vendor\n",
680                                         prog);
681                         break;
682                 }
683
684                 UM_FREE(cfg_info);
685         } else {
686                 /*
687                  * Get generic interface statistics
688                  */
689                 buf_len = sizeof(struct air_phy_stat_rsp) * 3;
690                 air.air_opcode = AIOCS_INF_PIS;
691                 strcpy(air.air_physt_intf, intf);
692                 buf_len = do_info_ioctl(&air, buf_len);
693                 if (buf_len < 0) {
694                         fprintf(stderr, "%s: ", prog);
695                         switch (errno) {
696                         case ENOPROTOOPT:
697                         case EOPNOTSUPP:
698                                 perror("Internal error");
699                                 break;
700                         case ENXIO:
701                                 fprintf(stderr, "%s is not an ATM device\n",
702                                                 intf);
703                                 break;
704                         default:
705                                 perror("ioctl (AIOCINFO)");
706                                 break;
707                         }
708                         exit(1);
709                 }
710
711                 /*
712                  * Display the interface statistics
713                  */
714                 pstat_info_base = pstat_info =
715                                 (struct air_phy_stat_rsp *)air.air_buf_addr;
716                 for (; buf_len >= sizeof(struct air_phy_stat_rsp);
717                                 pstat_info++,
718                                 buf_len-=sizeof(struct air_phy_stat_rsp)) {
719                         print_intf_stats(pstat_info);
720                 }
721                 UM_FREE((caddr_t)pstat_info_base);
722         }
723 }
724
725
726 /*
727  * Process VCC statistics command
728  * 
729  * Command format: 
730  *      atm show stats VCC [<interface-name> [<vpi> [<vci>]]] 
731  *
732  * Arguments:
733  *      argc    number of remaining arguments to command
734  *      argv    pointer to remaining argument strings
735  *      cmdp    pointer to command description 
736  *
737  * Returns:
738  *      none
739  *
740  */
741 void
742 show_vcc_stats(argc, argv, cmdp)
743         int             argc;
744         char            **argv;
745         struct cmd      *cmdp;
746 {
747         int     vcc_info_len;
748         int     vpi = -1, vci = -1;
749         char    *cp, *intf = NULL;
750         struct air_vcc_rsp      *vcc_info, *vcc_info_base;
751
752         /*
753          * Validate interface name
754          */
755         if (argc) {
756                 if (strlen(argv[0]) > IFNAMSIZ - 1) {
757                         fprintf(stderr, "%s: Illegal interface name\n",
758                                         prog);
759                         exit(1);
760                 }
761                 intf = argv[0];
762                 argc--; argv++;
763         }
764
765         /*
766          * Validate VPI value
767          */
768         if (argc) {
769                 vpi = strtol(argv[0], &cp, 0);
770                 if ((*cp != '\0') || (vpi < 0) || (vpi >= 1 << 8)) {
771                         fprintf(stderr, "%s: Invalid VPI value\n", prog);
772                         exit(1);
773                 }
774                 argc--; argv++;
775         }
776
777         /*
778          * Validate VCI value
779          */
780         if (argc) {
781                 vci = strtol(argv[0], &cp, 0);
782                 if ((*cp != '\0') || (vci <= 0) || (vci >= 1 << 16)) {
783                         fprintf(stderr, "%s: Invalid VCI value\n",
784                                         prog);
785                         exit(1);
786                 }
787                 argc--; argv++;
788         }
789
790         /*
791          * Get VCC information
792          */
793         vcc_info_len = get_vcc_info(intf, &vcc_info);
794         if (vcc_info_len == 0)
795                 exit(1);
796         else if (vcc_info_len < 0) {
797                 fprintf(stderr, "%s: ", prog);
798                 switch (errno) {
799                 case ENOPROTOOPT:
800                 case EOPNOTSUPP:
801                         perror("Internal error");
802                         break;
803                 case ENXIO:
804                         fprintf(stderr, "Not an ATM device\n");
805                         break;
806                 default:
807                         perror("ioctl (AIOCINFO)");
808                         break;
809                 }
810                 exit(1);
811         }
812
813         /*
814          * Sort the VCC information
815          */
816         qsort((void *) vcc_info,
817                         vcc_info_len / sizeof(struct air_vcc_rsp),
818                         sizeof(struct air_vcc_rsp),
819                         vcc_compare);
820
821         /*
822          * Display the VCC statistics
823          */
824         vcc_info_base = vcc_info;
825         for (; vcc_info_len >= sizeof(struct air_vcc_rsp);
826                         vcc_info_len-=sizeof(struct air_vcc_rsp),
827                         vcc_info++) {
828                 if (vpi != -1 && vcc_info->avp_vpi != vpi)
829                         continue;
830                 if (vci != -1 && vcc_info->avp_vci != vci)
831                         continue;
832                 print_vcc_stats(vcc_info);
833         }
834         UM_FREE(vcc_info_base);
835 }
836
837
838 /*
839  * Process VCC information command
840  * 
841  * Command format: 
842  *      atm show VCC [<interface-name> [<vpi> [<vci>] | PVC | SVC]] 
843  *
844  * Arguments:
845  *      argc    number of remaining arguments to command
846  *      argv    pointer to remaining argument strings
847  *      cmdp    pointer to command description 
848  *
849  * Returns:
850  *      none
851  *
852  */
853 void
854 show_vcc(argc, argv, cmdp)
855         int             argc;
856         char            **argv;
857         struct cmd      *cmdp;
858 {
859         int     vcc_info_len;
860         int     vpi = -1, vci = -1, show_pvc = 0, show_svc = 0;
861         char    *cp, *intf = NULL;
862         struct air_vcc_rsp      *vcc_info, *vcc_info_base;
863
864         /*
865          * Validate interface name
866          */
867         if (argc) {
868                 if (strlen(argv[0]) > IFNAMSIZ - 1) {
869                         fprintf(stderr, "%s: Illegal interface name\n",
870                                         prog);
871                         exit(1);
872                 }
873                 intf = argv[0];
874                 argc--; argv++;
875         }
876
877         /*
878          * Validate VPI value
879          */
880         if (argc) {
881                 if (strcasecmp(argv[0], "pvc"))
882                         show_pvc = 1;
883                 else if (strcasecmp(argv[0], "svc"))
884                         show_svc = 1;
885                 else {
886                         vpi = strtol(argv[0], &cp, 0);
887                         if ((*cp != '\0') || (vpi < 0) ||
888                                         (vpi >= 1 << 8)) {
889                                 fprintf(stderr, "%s: Invalid VPI value\n", prog);
890                                 exit(1);
891                         }
892                 }
893                 argc--; argv++;
894         }
895
896         /*
897          * Validate VCI value
898          */
899         if (argc) {
900                 vci = strtol(argv[0], &cp, 0);
901                 if ((*cp != '\0') || (vci <= 0) || (vci >= 1 << 16)) {
902                         fprintf(stderr, "%s: Invalid VCI value\n",
903                                         prog);
904                         exit(1);
905                 }
906                 argc--; argv++;
907         }
908
909         /*
910          * Get VCC information
911          */
912         vcc_info_len = get_vcc_info(intf, &vcc_info);
913         if (vcc_info_len == 0)
914                 exit(1);
915         else if (vcc_info_len < 0) {
916                 fprintf(stderr, "%s: ", prog);
917                 switch (errno) {
918                 case ENOPROTOOPT:
919                 case EOPNOTSUPP:
920                         perror("Internal error");
921                         break;
922                 case ENXIO:
923                         fprintf(stderr, "Not an ATM device\n");
924                         break;
925                 default:
926                         perror("ioctl (AIOCINFO)");
927                         break;
928                 }
929                 exit(1);
930         }
931
932         /*
933          * Sort the VCC information
934          */
935         qsort((void *) vcc_info,
936                         vcc_info_len/sizeof(struct air_vcc_rsp),
937                         sizeof(struct air_vcc_rsp),
938                         vcc_compare);
939
940         /*
941          * Display the VCC information
942          */
943         vcc_info_base = vcc_info;
944         for (; vcc_info_len >= sizeof(struct air_vcc_rsp);
945                         vcc_info_len-=sizeof(struct air_vcc_rsp),
946                         vcc_info++) {
947                 if (vpi != -1 && vcc_info->avp_vpi != vpi)
948                         continue;
949                 if (vci != -1 && vcc_info->avp_vci != vci)
950                         continue;
951                 if (show_pvc && vcc_info->avp_type & VCC_PVC)
952                         continue;
953                 if (show_svc && vcc_info->avp_type & VCC_SVC)
954                         continue;
955                 print_vcc_info(vcc_info);
956         }
957         UM_FREE(vcc_info_base);
958 }
959
960
961 /*
962  * Process version command
963  * 
964  * Command format: 
965  *      atm show version
966  *
967  * Arguments:
968  *      argc    number of remaining arguments to command
969  *      argv    pointer to remaining argument strings
970  *      cmdp    pointer to command description 
971  *
972  * Returns:
973  *      none
974  *
975  */
976 void
977 show_version(argc, argv, cmdp)
978         int             argc;
979         char            **argv;
980         struct cmd      *cmdp;
981 {
982         int     buf_len = sizeof(struct air_version_rsp);
983         struct atminfreq        air;
984         struct air_version_rsp  *ver_info, *ver_info_base;
985
986         /*
987          * Get network interface information from the kernel
988          */
989         air.air_opcode = AIOCS_INF_VER;
990         buf_len = do_info_ioctl(&air, buf_len);
991         if (buf_len < 0) {
992                 fprintf(stderr, "%s: ", prog);
993                 switch (errno) {
994                 case ENOPROTOOPT:
995                 case EOPNOTSUPP:
996                         perror("Internal error");
997                         break;
998                 case ENXIO:
999                         fprintf(stderr, "Not an ATM device\n");
1000                         break;
1001                 default:
1002                         perror("ioctl (AIOCINFO)");
1003                         break;
1004                 }
1005                 exit(1);
1006         }
1007
1008         /*
1009          * Print the network interface information
1010          */
1011         ver_info_base = ver_info =
1012                         (struct air_version_rsp *) air.air_buf_addr;
1013         for (; buf_len >= sizeof(struct air_version_rsp); ver_info++,
1014                         buf_len -= sizeof(struct air_version_rsp)) {
1015                 print_version_info(ver_info);
1016         }
1017         UM_FREE(ver_info_base);
1018 }
1019
1020
1021 /*
1022  * Comparison function for qsort
1023  * 
1024  * Arguments:
1025  *      p1      pointer to the first VCC response
1026  *      p2      pointer to the second VCC response
1027  *
1028  * Returns:
1029  *      int     a number less than, greater than, or equal to zero,
1030  *              depending on whether *p1 is less than, greater than, or
1031  *              equal to *p2
1032  *
1033  */
1034 static int
1035 vcc_compare(p1, p2)
1036         const void *p1, *p2;
1037 {
1038         int rc;
1039         struct air_vcc_rsp      *c1, *c2;
1040
1041         c1 = (struct air_vcc_rsp *) p1;
1042         c2 = (struct air_vcc_rsp *) p2;
1043
1044         /*
1045          * Compare the interface names
1046          */
1047         rc = strcmp(c1->avp_intf, c2->avp_intf);
1048         if (rc)
1049                 return(rc);
1050
1051         /*
1052          * Compare the VPI values
1053          */
1054         rc = c1->avp_vpi - c2->avp_vpi;
1055         if (rc)
1056                 return(rc);
1057
1058         /*
1059          * Compare the VCI values
1060          */
1061         rc = c1->avp_vci - c2->avp_vci;
1062         if (rc)
1063                 return(rc);
1064
1065         /*
1066          * Compare the types
1067          */
1068         rc = c1->avp_type - c2->avp_type;
1069         return(rc);
1070 }
1071
1072
1073 /*
1074  * Comparison function for qsort
1075  * 
1076  * Arguments:
1077  *      p1      pointer to the first VCC response
1078  *      p2      pointer to the second VCC response
1079  *
1080  * Returns:
1081  *      int     a number less than, greater than, or equal to zero,
1082  *              depending on whether *p1 is less than, greater than, or
1083  *              equal to *p2
1084  *
1085  */
1086 static int
1087 ip_vcc_compare(p1, p2)
1088         const void *p1, *p2;
1089 {
1090         int rc;
1091         struct air_ip_vcc_rsp   *c1, *c2;
1092
1093         c1 = (struct air_ip_vcc_rsp *) p1;
1094         c2 = (struct air_ip_vcc_rsp *) p2;
1095
1096         /*
1097          * Compare the interface names
1098          */
1099         rc = strcmp(c1->aip_intf, c2->aip_intf);
1100         if (rc)
1101                 return(rc);
1102
1103         /*
1104          * Compare the VPI values
1105          */
1106         rc = c1->aip_vpi - c2->aip_vpi;
1107         if (rc)
1108                 return(rc);
1109
1110         /*
1111          * Compare the VCI values
1112          */
1113         rc = c1->aip_vci - c2->aip_vci;
1114         return(rc);
1115 }
1116
1117
1118 /*
1119  * Comparison function for qsort
1120  * 
1121  * Arguments:
1122  *      p1      pointer to the first ARP or IP map entry
1123  *      p2      pointer to the second ARP or IP map entry
1124  *
1125  * Returns:
1126  *      int     a number less than, greater than, or equal to zero,
1127  *              depending on whether *p1 is less than, greater than, or
1128  *              equal to *p2
1129  *
1130  */
1131 static int
1132 arp_compare(p1, p2)
1133         const void *p1, *p2;
1134 {
1135         int rc;
1136         struct air_arp_rsp      *c1, *c2;
1137         struct sockaddr_in      *sin1, *sin2;
1138
1139         c1 = (struct air_arp_rsp *) p1;
1140         c2 = (struct air_arp_rsp *) p2;
1141         sin1 = (struct sockaddr_in *) &c1->aap_arp_addr;
1142         sin2 = (struct sockaddr_in *) &c2->aap_arp_addr;
1143
1144         /*
1145          * Compare the IP addresses
1146          */
1147         if ((rc = sin1->sin_family - sin2->sin_family) != 0)
1148                 return(rc);
1149         if ((rc = sin1->sin_addr.s_addr - sin2->sin_addr.s_addr) != 0)
1150                 return(rc);
1151
1152         /*
1153          * Compare the ATM addresses
1154          */
1155         if ((rc = c1->aap_addr.address_format - c2->aap_addr.address_format) != 0)
1156                 return(rc);
1157         if ((rc = c1->aap_addr.address_length - c2->aap_addr.address_length) != 0)
1158                 return(rc);
1159         switch(c1->aap_addr.address_format) {
1160         case T_ATM_ABSENT:
1161                 rc = 0;
1162                 break;
1163         case T_ATM_ENDSYS_ADDR:
1164                 rc = bcmp((caddr_t)c1->aap_addr.address,
1165                                 (caddr_t)c2->aap_addr.address,
1166                                 sizeof(Atm_addr_nsap));
1167                 break;
1168         case T_ATM_E164_ADDR:
1169                 rc = bcmp((caddr_t)c1->aap_addr.address,
1170                                 (caddr_t)c2->aap_addr.address,
1171                                 sizeof(Atm_addr_e164));
1172                 break;
1173         case T_ATM_SPANS_ADDR:
1174                 rc = bcmp((caddr_t)c1->aap_addr.address,
1175                                 (caddr_t)c2->aap_addr.address,
1176                                 sizeof(Atm_addr_spans));
1177                 break;
1178         }
1179
1180         return(rc);
1181 }