Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / sbin / atm / atm / atm.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.c,v 1.3.2.1 2000/07/01 06:02:14 ps Exp $
27  *      @(#) $DragonFly: src/sbin/atm/atm/atm.c,v 1.2 2003/06/17 04:27:32 dillon Exp $
28  */
29
30 /*
31  * User configuration and display program
32  * --------------------------------------
33  *
34  * Main routine
35  *
36  */
37
38 #include <sys/param.h>
39 #include <sys/socket.h>
40 #include <sys/sockio.h>
41 #include <net/if.h>
42 #include <netinet/in.h>
43 #include <netatm/port.h>
44 #include <netatm/atm.h>
45 #include <netatm/atm_if.h>
46 #include <netatm/atm_sap.h>
47 #include <netatm/atm_sys.h>
48 #include <netatm/atm_cm.h>
49 #include <netatm/atm_sigmgr.h>
50 #include <netatm/atm_ioctl.h>
51
52 #include <errno.h>
53 #include <libatm.h>
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <string.h>
57 #include <unistd.h>
58
59 #include "atm.h"
60
61 /*
62  * Usage string
63  */
64 #define USAGE_STR       "Interface management subcommands:\n\
65     attach <intf> <protocol>\n\
66     detach <intf>\n\
67     set mac <intf> <MAC/ESI address>\n\
68     set netif <intf> <prefix> <n>\n\
69     set prefix <intf> <NSAP prefix>\n\
70     show config [<intf>]\n\
71     show interface [<intf>]\n\
72     show netif [<netif>]\n\
73     show stats interface [<intf> phy | dev | atm | aal0 | aal4 |\n\
74         aal5 | driver]\n\
75 \n\
76 VC management subcommands:\n\
77     add pvc <intf> <vpi> <vci> <aal> <encaps> <owner> ...\n\
78     delete pvc <intf> <vpi> <vci>\n\
79     delete svc <intf> <vpi> <vci>\n\
80     show stats vcc [<intf> [vpi [vci]]]\n\
81     show vcc [<intf> [<vpi> [<vci>] | SVC | PVC]]\n\
82 \n\
83 IP management subcommands:\n\
84     add arp [<netif>] <IP addr> <ATM addr>\n\
85     add pvc <intf> <vpi> <vci> <aal> <encaps> IP <netif> <IP addr> |\n\
86         dynamic\n\
87     delete arp [<netif>] <IP addr>\n\
88     set arpserver <netif> <server> <IP prefix> ...\n\
89     show arp [<host>]\n\
90     show arpserver [<netif>]\n\
91     show ipvcc [<IP addr> | <netif>]\n\
92 \n\
93 Miscellaneous subcommands:\n\
94     help\n\
95     show version\n"
96
97
98 /*
99  * Local definitions
100  */
101
102 struct cmd      add_subcmd[];
103 struct cmd      dlt_subcmd[];
104 struct cmd      set_subcmd[];
105 struct cmd      show_subcmd[];
106 struct cmd      stats_subcmd[];
107
108 struct cmd      cmds[] = {
109         { "add",        0,      0,      NULL,   (char *) add_subcmd },
110         { "attach",     2,      2,      attach, "<intf> <protocol>" },
111         { "delete",     0,      0,      NULL,   (char *) dlt_subcmd },
112         { "detach",     1,      1,      detach, "<intf>" },
113         { "set",        0,      0,      NULL,   (char *) set_subcmd },
114         { "show",       0,      0,      NULL,   (char *) show_subcmd },
115         { "help",       0,      99,     help,   "" },
116         { 0,            0,      0,      NULL,   "" }
117 };
118
119 struct cmd add_subcmd[] = {
120         { "arp",        2,      3,      arp_add, "[<netif>] <IP addr> <ATM addr>" },
121         { "pvc",        6,      12,     pvc_add, "<intf> <vpi> <vci> <aal> <encaps> <owner> ..." },
122         { 0,            0,      0,      NULL,   "" }
123 };
124
125 struct cmd dlt_subcmd[] = {
126         { "arp",        1,      2,      arp_dlt, "[<netif>] <IP addr>" },
127         { "pvc",        3,      3,      pvc_dlt, "<intf> <vpi> <vci>" },
128         { "svc",        3,      3,      svc_dlt, "<intf> <vpi> <vci>" },
129         { 0,            0,      0,      NULL,   "" }
130 };
131
132 struct cmd set_subcmd[] = {
133         { "arpserver",  2,      18,     set_arpserver, "<netif> <server>" },
134         { "mac",        2,      2,      set_macaddr, "<intf> <MAC/ESI address>" },
135         { "netif",      3,      3,      set_netif, "<intf> <prefix> <n>" },
136         { "prefix",     2,      2,      set_prefix, "<intf> <NSAP prefix>" },
137         { 0,            0,      0,      NULL,   ""}
138 };
139
140 struct cmd show_subcmd[] = {
141         { "arp",        0,      1,      show_arp, "[<host>]" },
142         { "arpserver",  0,      1,      show_arpserv, "[<netif>]" },
143         { "config",     0,      1,      show_config, "[<intf>]" },
144         { "interface",  0,      1,      show_intf, "[<intf>]" },
145         { "ipvcc",      0,      3,      show_ip_vcc, "[<IP addr> | <netif>]" },
146         { "netif",      0,      1,      show_netif, "[<netif>]" },
147         { "stats",      0,      3,      NULL, (char *) stats_subcmd },
148         { "vcc",        0,      3,      show_vcc, "[<intf>] [<vpi> [<vci>] | SVC | PVC]" },
149         { "version",    0,      0,      show_version, "" },
150         { 0,            0,      0,      NULL,   "" }
151 };
152
153 struct cmd stats_subcmd[] = {
154         { "interface",  0,      2,      show_intf_stats, "[<intf> [cfg | phy | dev | atm | aal0 | aal4 | aal5 | driver]]" },
155         { "vcc",        0,      3,      show_vcc_stats, "[<intf> [vpi [vci]]]" },
156         { 0,            0,      0,      NULL,   "" }
157 };
158
159
160 /*
161  * Supported signalling protocols
162  */
163 struct proto    protos[] = {
164         { "SIGPVC",     ATM_SIG_PVC },
165         { "SPANS",      ATM_SIG_SPANS },
166         { "UNI30",      ATM_SIG_UNI30 },
167         { "UNI31",      ATM_SIG_UNI31 },
168         { "UNI40",      ATM_SIG_UNI40 },
169         { 0,            0 }
170 };
171
172 /*
173  * Supported VCC owners
174  */
175 struct owner    owners[] = {
176         { "IP",         ENDPT_IP,       ip_pvcadd },
177         { "SPANS",      ENDPT_SPANS_SIG,0 },
178         { "SPANS CLS",  ENDPT_SPANS_CLS,0 },
179         { "UNI SIG",    ENDPT_UNI_SIG,  0 },
180         { 0,            0,              0 }
181 };
182
183 /*
184  * Supported AAL parameters
185  */
186 struct aal      aals[] = {
187         { "Null",       ATM_AAL0 },
188         { "AAL0",       ATM_AAL0 },
189         { "AAL1",       ATM_AAL1 },
190         { "AAL2",       ATM_AAL2 },
191         { "AAL4",       ATM_AAL3_4 },
192         { "AAL3",       ATM_AAL3_4 },
193         { "AAL3/4",     ATM_AAL3_4 },
194         { "AAL5",       ATM_AAL5 },
195         { 0,    0 },
196 };
197
198 /*
199  * Supported VCC encapsulations
200  */
201 struct encaps   encaps[] = {
202         { "Null",       ATM_ENC_NULL },
203         { "None",       ATM_ENC_NULL },
204         { "LLC/SNAP",   ATM_ENC_LLC },
205         { "LLC",        ATM_ENC_LLC },
206         { "SNAP",       ATM_ENC_LLC },
207         { 0,    0 },
208 };
209
210
211 char    *prog;
212 char    prefix[128] = "";
213
214
215 int
216 main(argc, argv)
217         int     argc;
218         char    **argv;
219 {
220         int     error;
221
222         /*
223          * Save program name, ignoring any path components
224          */
225         if ((prog = (char *)strrchr(argv[0], '/')) != NULL)
226                 prog++;
227         else
228                 prog = argv[0];
229
230         if (argc < 2) {
231                 usage(cmds, "");
232                 exit(1);
233         }
234         argc--; argv++;
235                 
236         /*
237          * Validate and process command
238          */
239         if ((error = do_cmd(cmds, argc, argv)) != 0)
240                 usage(cmds, "");
241
242         exit(error);
243 }
244
245
246 /*
247  * Validate and process user command
248  * 
249  * Arguments:
250  *      descp   pointer to command description array
251  *      argc    number of arguments left in command
252  *      argv    pointer to argument strings
253  *
254  * Returns:
255  *      none
256  *
257  */
258 int
259 do_cmd(descp, argc, argv)
260         struct cmd      *descp;
261         int             argc;
262         char            **argv;
263 {
264         struct cmd      *cmdp = 0;
265
266         /*
267          * Make sure we have paramaters to process
268          */
269         if (!argc) {
270                 usage(cmds, "");
271                 exit(1);
272         }
273
274         /*
275          * Figure out what command user wants
276          */
277         for (; descp->name; descp++) {
278                 /*
279                  * Use an exact match if there is one
280                  */
281                 if (!strcasecmp(descp->name, argv[0])) {
282                         cmdp = descp;
283                         break;
284                 }
285                 /*
286                  * Look for a match on the first part of keyword
287                  */
288                 if (!strncasecmp(descp->name, argv[0], strlen(argv[0]))) {
289                         if (cmdp) {
290                                 fprintf(stderr, "%s: Ambiguous parameter \"%s\"\n",
291                                                 prog, argv[0]);
292                                 exit(1);
293                         }
294                         cmdp = descp;
295                 }
296         }
297         if (!cmdp)
298                 return(1);
299         argc--; argv++;
300
301         /*
302          * See if this command has subcommands
303          */
304         if (cmdp->func == NULL) {
305                 strcat(prefix, cmdp->name);
306                 strcat(prefix, " ");
307                 return(do_cmd((struct cmd *)cmdp->help, argc, argv));
308         }
309
310         /*
311          * Minimal validation
312          */
313         if ((argc < cmdp->minp) || (argc > cmdp->maxp)) {
314                 fprintf(stderr, "%s: Invalid number of arguments\n",
315                         prog);
316                 fprintf(stderr, "\tformat is: %s%s %s\n",
317                         prefix, cmdp->name, cmdp->help);
318                 exit(1);
319         }
320
321         /*
322          * Process command
323          */
324         (*cmdp->func)(argc, argv, cmdp);
325         return(0);
326 }
327
328
329 /*
330  * Print command usage information
331  * 
332  * Arguments:
333  *      cmdp    pointer to command description 
334  *      pref    pointer current command prefix 
335  *
336  * Returns:
337  *      none
338  *
339  */
340 void
341 usage(cmdp, pref)
342         struct cmd      *cmdp;
343         char            *pref;
344 {
345         fprintf(stderr, "usage: %s command [arg] [arg]...\n", prog);
346         fprintf(stderr, USAGE_STR);
347 }
348
349
350 /*
351  * Process interface attach command
352  * 
353  * Command format: 
354  *      atm attach <interface_name> <protocol_name>
355  *
356  * Arguments:
357  *      argc    number of arguments to command
358  *      argv    pointer to argument strings
359  *      cmdp    pointer to command description 
360  *
361  * Returns:
362  *      none
363  *
364  */
365 void
366 attach(argc, argv, cmdp)
367         int             argc;
368         char            **argv;
369         struct cmd      *cmdp;
370 {
371         struct atmcfgreq        aar;
372         struct proto    *prp;
373         int             s;
374
375         /*
376          * Validate interface name
377          */
378         if (strlen(argv[0]) > sizeof(aar.acr_att_intf) - 1) {
379                 fprintf(stderr, "%s: Illegal interface name\n", prog);
380                 exit(1);
381         }
382
383         /*
384          * Find/validate requested signalling protocol
385          */
386         for (prp = protos; prp->p_name; prp++) {
387                 if (strcasecmp(prp->p_name, argv[1]) == 0)
388                         break;
389         }
390         if (prp->p_name == NULL) {
391                 fprintf(stderr, "%s: Unknown signalling protocol\n", prog);
392                 exit(1);
393         }
394
395
396         /*
397          * Build ioctl request
398          */
399         aar.acr_opcode = AIOCS_CFG_ATT;
400         strncpy(aar.acr_att_intf, argv[0], sizeof(aar.acr_att_intf));
401         aar.acr_att_proto = prp->p_id;
402
403         /*
404          * Tell the kernel to do the attach
405          */
406         s = socket(AF_ATM, SOCK_DGRAM, 0);
407         if (s < 0) {
408                 sock_error(errno);
409         }
410         if (ioctl(s, AIOCCFG, (caddr_t)&aar) < 0) {
411                 fprintf(stderr, "%s: ", prog);
412                 switch (errno) {
413                 case EINVAL:
414                 case EOPNOTSUPP:
415                 case EPROTONOSUPPORT:
416                         perror("Internal error");
417                         break;
418                 case ENOMEM:
419                         fprintf(stderr, "Kernel memory exhausted\n");
420                         break;
421                 case EEXIST:
422                         fprintf(stderr, "Signalling manager already attached to %s\n",
423                                         argv[0]);
424                         break;
425                 case ENETDOWN:
426                         fprintf(stderr, "ATM network is inoperable\n");
427                         break;
428                 case EPERM:
429                         fprintf(stderr, "Must be super user to use attach subcommand\n");
430                         break;
431                 case ENXIO:
432                         fprintf(stderr, "%s is not an ATM device\n",
433                                         argv[0]);
434                         break;
435                 case ETOOMANYREFS:
436                         fprintf(stderr, "%s has too few or too many network interfaces\n",
437                                         argv[0]);
438                         break;
439                 default:
440                         perror("Ioctl (AIOCCFG) attach");
441                         break;
442                 }
443                 exit(1);
444         }
445         (void)close(s);
446 }
447
448
449 /*
450  * Process interface detach command
451  * 
452  * Command format: 
453  *      atm detach <interface_name>
454  *
455  * Arguments:
456  *      argc    number of arguments to command
457  *      argv    pointer to argument strings
458  *      cmdp    pointer to command description 
459  *
460  * Returns:
461  *      none
462  *
463  */
464 void
465 detach(argc, argv, cmdp)
466         int             argc;
467         char            **argv;
468         struct cmd      *cmdp;
469 {
470         struct atmcfgreq        adr;
471         int             s;
472
473         /*
474          * Validate interface name
475          */
476         if (strlen(argv[0]) > sizeof(adr.acr_det_intf) - 1) {
477                 fprintf(stderr, "%s: Illegal interface name\n", prog);
478                 exit(1);
479         }
480
481         /*
482          * Build ioctl request
483          */
484         adr.acr_opcode = AIOCS_CFG_DET;
485         strncpy(adr.acr_det_intf, argv[0], sizeof(adr.acr_det_intf));
486
487         /*
488          * Tell the kernel to do the detach
489          */
490         s = socket(AF_ATM, SOCK_DGRAM, 0);
491         if (s < 0) {
492                 sock_error(errno);
493         }
494         if (ioctl(s, AIOCCFG, (caddr_t)&adr) < 0) {
495                 fprintf(stderr, "%s: ", prog);
496                 switch (errno) {
497                 case EALREADY:
498                         fprintf(stderr, "Signalling manager already detaching from %s\n",
499                                         argv[0]);
500                         break;
501                 case EINVAL:
502                         perror("Internal error");
503                         break;
504                 case EPERM:
505                         fprintf(stderr, "Must be super user to use detach subcommand\n");
506                         break;
507                 default:
508                         perror("ioctl (AIOCCFG) detach");
509                         break;
510                 }
511                 exit(1);
512         }
513         (void)close(s);
514 }
515
516
517 /*
518  * Process PVC add command
519  * 
520  * Command format: 
521  *      atm add PVC <interface_name> <vpi> <vci> <aal> <encaps>
522  *              <owner_name>
523  *
524  * Arguments:
525  *      argc    number of arguments to command
526  *      argv    pointer to argument strings
527  *      cmdp    pointer to command description 
528  *
529  * Returns:
530  *      none
531  *
532  */
533 void
534 pvc_add(argc, argv, cmdp)
535         int             argc;
536         char            **argv;
537         struct cmd      *cmdp;
538 {
539         struct atmaddreq        apr;
540         struct atminfreq        air;
541         struct air_int_rsp      *int_info;
542         struct owner    *owp;
543         struct aal      *alp;
544         struct encaps   *enp;
545         char    *cp;
546         long    v;
547         int     buf_len, s;
548
549         /*
550          * Initialize opcode and flags
551          */
552         apr.aar_opcode = AIOCS_ADD_PVC;
553         apr.aar_pvc_flags = 0;
554
555         /*
556          * Validate interface name and issue an information
557          * request IOCTL for the interface
558          */
559         if (strlen(argv[0]) > sizeof(apr.aar_pvc_intf) - 1) {
560                 fprintf(stderr, "%s: Illegal interface name\n", prog);
561                 exit(1);
562         }
563         UM_ZERO(air.air_int_intf, sizeof(air.air_int_intf));
564         strcpy(air.air_int_intf, argv[0]);
565         buf_len = sizeof(struct air_int_rsp);
566         air.air_opcode = AIOCS_INF_INT;
567         buf_len = do_info_ioctl(&air, buf_len);
568         if (buf_len < 0) {
569                 fprintf(stderr, "%s: ", prog);
570                 switch (errno) {
571                 case ENOPROTOOPT:
572                 case EOPNOTSUPP:
573                         perror("Internal error");
574                         break;
575                 case ENXIO:
576                         fprintf(stderr, "%s is not an ATM device\n",
577                                         argv[0]);
578                         break;
579                 default:
580                         perror("ioctl (AIOCINFO)");
581                         break;
582                 }
583                 exit(1);
584         }
585         int_info = (struct air_int_rsp *) air.air_buf_addr;
586         strcpy(apr.aar_pvc_intf, argv[0]);
587         argc--; argv++;
588
589         /*
590          * Validate vpi/vci values
591          */
592         v = strtol(argv[0], &cp, 0);
593         if ((*cp != '\0') || (v < 0) || (v >= 1 << 8)) {
594                 fprintf(stderr, "%s: Invalid VPI value\n", prog);
595                 exit(1);
596         }
597         apr.aar_pvc_vpi = (u_short) v;
598         argc--; argv++;
599
600         v = strtol(argv[0], &cp, 0);
601         if ((*cp != '\0') || (v < MIN_VCI) || (v >= 1 << 16)) {
602                 fprintf(stderr, "%s: Invalid VCI value\n", prog);
603                 exit(1);
604         }
605         apr.aar_pvc_vci = (u_short) v;
606         argc--; argv++;
607
608         /*
609          * Validate requested PVC AAL
610          */
611         for (alp = aals; alp->a_name; alp++) {
612                 if (strcasecmp(alp->a_name, argv[0]) == 0)
613                         break;
614         }
615         if (alp->a_name == NULL) {
616                 fprintf(stderr, "%s: Invalid PVC AAL\n", prog);
617                 exit(1);
618         }
619         apr.aar_pvc_aal = alp->a_id;
620         argc--; argv++;
621
622         /*
623          * Validate requested PVC encapsulation
624          */
625         for (enp = encaps; enp->e_name; enp++) {
626                 if (strcasecmp(enp->e_name, argv[0]) == 0)
627                         break;
628         }
629         if (enp->e_name == NULL) {
630                 fprintf(stderr, "%s: Invalid PVC encapsulation\n", prog);
631                 exit(1);
632         }
633         apr.aar_pvc_encaps = enp->e_id;
634         argc--; argv++;
635
636         /*
637          * Validate requested PVC owner
638          */
639         for (owp = owners; owp->o_name; owp++) {
640                 if (strcasecmp(owp->o_name, argv[0]) == 0)
641                         break;
642         }
643         if (owp->o_name == NULL) {
644                 fprintf(stderr, "%s: Unknown PVC owner\n", prog);
645                 exit(1);
646         }
647         apr.aar_pvc_sap = owp->o_sap;
648         argc--; argv++;
649
650         /*
651          * Perform service user processing
652          */
653         if (owp->o_pvcadd) {
654                 (*owp->o_pvcadd)(argc, argv, cmdp, &apr, int_info);
655         } else {
656                 fprintf(stderr, "%s: Unsupported PVC owner\n", prog);
657                 exit(1);
658         }
659
660         /*
661          * Tell the kernel to add the PVC
662          */
663         s = socket(AF_ATM, SOCK_DGRAM, 0);
664         if (s < 0) {
665                 sock_error(errno);
666         }
667         if (ioctl(s, AIOCADD, (caddr_t)&apr) < 0) {
668                 fprintf(stderr, "%s: ", prog);
669                 switch (errno) {
670                 case EPROTONOSUPPORT:
671                 case ENOPROTOOPT:
672                         perror("Internal error");
673                         break;
674                 case EINVAL:
675                         fprintf(stderr, "Invalid parameter\n");
676                         break;
677                 case EEXIST:
678                         fprintf(stderr, "PVC already exists\n");
679                         break;
680                 case ENETDOWN:
681                         fprintf(stderr, "ATM network is inoperable\n");
682                         break;
683                 case ENOMEM:
684                         fprintf(stderr, "Kernel memory exhausted\n");
685                         break;
686                 case EPERM:
687                         fprintf(stderr, "Must be super user to use add subcommand\n");
688                         break;
689                 case ERANGE:
690                         fprintf(stderr, "Invalid VPI or VCI value\n");
691                         break;
692                 default:
693                         perror("ioctl (AIOCADD) add PVC");
694                         break;
695                 }
696                 exit(1);
697         }
698         (void)close(s);
699 }
700
701
702 /*
703  * Process ARP add command
704  * 
705  * Command formats: 
706  *      atm add arp [<netif>] <IP addr> <ATM addr>
707  *
708  * Arguments:
709  *      argc    number of arguments to command
710  *      argv    pointer to argument strings
711  *      cmdp    pointer to command description 
712  *
713  * Returns:
714  *      none
715  *
716  */
717 void
718 arp_add(argc, argv, cmdp)
719         int             argc;
720         char            **argv;
721         struct cmd      *cmdp;
722 {
723         int                     len, s;
724         struct atmaddreq        apr;
725         Atm_addr                host_atm;
726         struct sockaddr_in      *sin;
727         union {
728                 struct sockaddr_in      sin;
729                 struct sockaddr         sa;
730         } host_ip;
731
732         /*
733          * Initialize add request structure
734          */
735         UM_ZERO(&apr, sizeof(apr));
736
737         /*
738          * Get network interface name if one is present
739          */
740         if (argc == 3) {
741                 check_netif_name(argv[0]);
742                 strcpy(apr.aar_arp_intf, argv[0]);
743                 argc--; argv++;
744         }
745
746         /*
747          * Get IP address of specified host name
748          */
749         UM_ZERO(&host_ip, sizeof(host_ip));
750         host_ip.sa.sa_family = AF_INET;
751         sin = get_ip_addr(argv[0]);
752         host_ip.sin.sin_addr.s_addr = sin->sin_addr.s_addr;
753         argc--; argv++;
754
755         /*
756          * Get specified ATM address
757          */
758         len = get_hex_atm_addr(argv[0], (u_char *)host_atm.address,
759                         sizeof(Atm_addr_nsap));
760         switch(len) {
761         case sizeof(Atm_addr_nsap):
762                 host_atm.address_format = T_ATM_ENDSYS_ADDR;
763                 host_atm.address_length = sizeof(Atm_addr_nsap);
764                 break;
765         case sizeof(Atm_addr_spans):
766                 host_atm.address_format = T_ATM_SPANS_ADDR;
767                 host_atm.address_length = sizeof(Atm_addr_spans);
768                 break;
769         default:
770                 fprintf(stderr, "%s: Invalid ATM address\n", prog);
771                 exit(1);
772         }
773
774         /*
775          * Build IOCTL request
776          */
777         apr.aar_opcode = AIOCS_ADD_ARP;
778         apr.aar_arp_dst = host_ip.sa;
779         ATM_ADDR_COPY(&host_atm, &apr.aar_arp_addr);
780         apr.aar_arp_origin = ARP_ORIG_PERM;
781
782         /*
783          * Tell the kernel to add the ARP table entry
784          */
785         s = socket(AF_ATM, SOCK_DGRAM, 0);
786         if (s < 0) {
787                 sock_error(errno);
788         }
789         if (ioctl(s, AIOCADD, (caddr_t)&apr) < 0) {
790                 fprintf(stderr, "%s: ", prog);
791                 switch (errno) {
792                 case EINVAL:
793                         fprintf(stderr, "Invalid parameter\n");
794                         break;
795                 case EPERM:
796                         fprintf(stderr, "Must be super user to use add subcommand\n");
797                         break;
798                 case EADDRNOTAVAIL:
799                         fprintf(stderr, "IP address not valid for interface\n");
800                         break;
801                 default:
802                         perror("ioctl (AIOCADD) add");
803                         break;
804                 }
805                 exit(1);
806         }
807         (void)close(s);
808 }
809
810
811 /*
812  * Process PVC delete command
813  * 
814  * Command formats: 
815  *      atm delete pvc <interface_name> <vpi> <vci>
816  *
817  * Arguments:
818  *      argc    number of arguments to command
819  *      argv    pointer to argument strings
820  *      cmdp    pointer to command description 
821  *
822  * Returns:
823  *      none
824  *
825  */
826 void
827 pvc_dlt(argc, argv, cmdp)
828         int             argc;
829         char            **argv;
830         struct cmd      *cmdp;
831 {
832         struct atmdelreq        apr;
833
834         /*
835          * Set opcode
836          */
837         apr.adr_opcode = AIOCS_DEL_PVC;
838
839         /*
840          * Complete request by calling subroutine
841          */
842         vcc_dlt(argc, argv, cmdp, &apr);
843 }
844
845
846 /*
847  * Process SVC delete command
848  * 
849  * Command formats: 
850  *      atm delete svc <interface_name> <vpi> <vci>
851  *
852  * Arguments:
853  *      argc    number of arguments to command
854  *      argv    pointer to argument strings
855  *      cmdp    pointer to command description 
856  *
857  * Returns:
858  *      none
859  *
860  */
861 void
862 svc_dlt(argc, argv, cmdp)
863         int             argc;
864         char            **argv;
865         struct cmd      *cmdp;
866 {
867         struct atmdelreq        apr;
868
869         /*
870          * Set opcode
871          */
872         apr.adr_opcode = AIOCS_DEL_SVC;
873
874         /*
875          * Complete request by calling subroutine
876          */
877         vcc_dlt(argc, argv, cmdp, &apr);
878 }
879
880
881 /*
882  * Complete an SVC or PVC delete command
883  * 
884  * Arguments:
885  *      argc    number of arguments to command
886  *      argv    pointer to argument strings
887  *      cmdp    pointer to command description 
888  *      apr     pointer to ATM delete IOCTL structure
889  *
890  * Returns:
891  *      none
892  *
893  */
894 void
895 vcc_dlt(argc, argv, cmdp, apr)
896         int                     argc;
897         char                    **argv;
898         struct cmd              *cmdp;
899         struct atmdelreq        *apr;
900 {
901         char    *cp;
902         long    v;
903         int     s;
904
905         /*
906          * Validate interface name
907          */
908         if (strlen(argv[0]) > sizeof(apr->adr_pvc_intf) - 1) {
909                 fprintf(stderr, "%s: Illegal interface name\n", prog);
910                 exit(1);
911         }
912         strcpy(apr->adr_pvc_intf, argv[0]);
913         argc--; argv++;
914
915         /*
916          * Validate vpi/vci values
917          */
918         v = strtol(argv[0], &cp, 0);
919         if ((*cp != '\0') || (v < 0) || (v >= 1 << 8)) {
920                 fprintf(stderr, "%s: Invalid VPI value\n", prog);
921                 exit(1);
922         }
923         apr->adr_pvc_vpi = (u_short) v;
924         argc--; argv++;
925
926         v = strtol(argv[0], &cp, 0);
927         if ((*cp != '\0') || (v < MIN_VCI) || (v >= 1 << 16)) {
928                 fprintf(stderr, "%s: Invalid VCI value\n", prog);
929                 exit(1);
930         }
931         apr->adr_pvc_vci = (u_short) v;
932         argc--; argv++;
933
934         /*
935          * Tell the kernel to delete the VCC
936          */
937         s = socket(AF_ATM, SOCK_DGRAM, 0);
938         if (s < 0) {
939                 sock_error(errno);
940         }
941         if (ioctl(s, AIOCDEL, (caddr_t)apr) < 0) {
942                 fprintf(stderr, "%s: ", prog);
943                 switch (errno) {
944                 case EINVAL:
945                         fprintf(stderr, "Invalid parameter\n");
946                         break;
947                 case ENOENT:
948                         fprintf(stderr, "VCC not found\n");
949                         break;
950                 case EALREADY:
951                         fprintf(stderr, "VCC already being closed\n");
952                         break;
953                 case ENXIO:
954                         fprintf(stderr, "%s is not an ATM device\n",
955                                         apr->adr_pvc_intf);
956                         break;
957                 case EPERM:
958                         fprintf(stderr, "Must be super user to use delete subcommand\n");
959                         break;
960                 default:
961                         perror("ioctl (AIOCDEL) delete");
962                         break;
963                 }
964                 exit(1);
965         }
966         (void)close(s);
967 }
968
969
970 /*
971  * Process ARP delete command
972  * 
973  * Command formats: 
974  *      atm delete arp <IP addr>
975  *
976  * Arguments:
977  *      argc    number of arguments to command
978  *      argv    pointer to argument strings
979  *      cmdp    pointer to command description 
980  *
981  * Returns:
982  *      none
983  *
984  */
985 void
986 arp_dlt(argc, argv, cmdp)
987         int             argc;
988         char            **argv;
989         struct cmd      *cmdp;
990 {
991         int     s;
992         struct atmdelreq        apr;
993         struct sockaddr_in      *sin;
994         union {
995                 struct sockaddr_in      sin;
996                 struct sockaddr         sa;
997         } host_addr;
998
999         /*
1000          * Set opcode
1001          */
1002         UM_ZERO(&apr, sizeof(apr));
1003         apr.adr_opcode = AIOCS_DEL_ARP;
1004
1005         /*
1006          * Get network interface name if one is present
1007          */
1008         if (argc == 2) {
1009                 check_netif_name(argv[0]);
1010                 strcpy(apr.adr_arp_intf, argv[0]);
1011                 argc--; argv++;
1012         }
1013
1014         /*
1015          * Get IP address of specified host name
1016          */
1017         UM_ZERO(&host_addr, sizeof(host_addr));
1018         host_addr.sa.sa_family = AF_INET;
1019         sin = get_ip_addr(argv[0]);
1020         host_addr.sin.sin_addr.s_addr = sin->sin_addr.s_addr;
1021         apr.adr_arp_dst = host_addr.sa;
1022
1023         /*
1024          * Tell the kernel to delete the ARP table entry
1025          */
1026         s = socket(AF_ATM, SOCK_DGRAM, 0);
1027         if (s < 0) {
1028                 sock_error(errno);
1029         }
1030         if (ioctl(s, AIOCDEL, (caddr_t)&apr) < 0) {
1031                 fprintf(stderr, "%s: ", prog);
1032                 switch (errno) {
1033                 case EINVAL:
1034                         fprintf(stderr, "Invalid parameter\n");
1035                         break;
1036                 case EPERM:
1037                         fprintf(stderr, "Must be super user to use delete subcommand\n");
1038                         break;
1039                 default:
1040                         perror("ioctl (AIOCDEL) delete");
1041                         break;
1042                 }
1043                 exit(1);
1044         }
1045         (void)close(s);
1046 }
1047
1048
1049 /*
1050  * Process help command
1051  * 
1052  * Arguments:
1053  *      argc    number of arguments to command
1054  *      argv    pointer to argument strings
1055  *      cmdp    pointer to command description 
1056  *
1057  * Returns:
1058  *      none
1059  *
1060  */
1061 void
1062 help(argc, argv, cmdp)
1063         int             argc;
1064         char            **argv;
1065         struct cmd      *cmdp;
1066 {
1067         usage(cmds, "");
1068 }