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