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