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