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