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