a090d31378f0bd643fe0fd9f31a9cd53fb0b560d
[platform/upstream/net-tools.git] / arp.c
1 /*
2  * arp                This file contains an implementation of the command
3  *              that maintains the kernel's ARP cache.  It is derived
4  *              from Berkeley UNIX arp(8), but cleaner and with sup-
5  *              port for devices other than Ethernet.
6  *
7  * NET-TOOLS    A collection of programs that form the base set of the
8  *              NET-3 Networking Distribution for the LINUX operating
9  *              system.
10  *
11  * Version:     $Id: arp.c,v 1.19 2000/12/19 00:34:27 ecki Exp $
12  *
13  * Maintainer:  Bernd 'eckes' Eckenfels, <net-tools@lina.inka.de>
14  *
15  * Author:      Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
16  *
17  * Changes:
18  *              (based on work from Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>)
19  *              Alan Cox        :       modified for NET3
20  *              Andrew Tridgell :       proxy arp netmasks
21  *              Bernd Eckenfels :       -n option
22  *              Bernd Eckenfels :       Use only /proc for display
23  *       {1.60} Bernd Eckenfels :       new arpcode (-i) for 1.3.42 but works 
24  *                                      with 1.2.x, too
25  *       {1.61} Bernd Eckenfels :       more verbose messages
26  *       {1.62} Bernd Eckenfels :       check -t for hw adresses and try to
27  *                                      explain EINVAL (jeff)
28  *970125 {1.63} Bernd Eckenfels :       -a print hardwarename instead of tiltle
29  *970201 {1.64} Bernd Eckenfels :       net-features.h support
30  *970203 {1.65} Bernd Eckenfels :       "#define" in "#if", 
31  *                                      -H|-A additional to -t|-p
32  *970214 {1.66} Bernd Eckenfels :       Fix optarg required for -H and -A
33  *970412 {1.67} Bernd Eckenfels :       device=""; is default
34  *970514 {1.68} Bernd Eckenfels :       -N and -D
35  *970517 {1.69} Bernd Eckenfels :       usage() fixed
36  *970622 {1.70} Bernd Eckenfels :       arp -d priv
37  *970106 {1.80} Bernd Eckenfels :       new syntax without -D and with "dev <If>",
38  *                                      ATF_MAGIC, ATF_DONTPUB support. 
39  *                                      Typo fix (Debian Bug#5728 Giuliano Procida)
40  *970803 {1.81} Bernd Eckenfels :       removed junk comment line 1
41  *970925 {1.82} Bernd Eckenfels :       include fix for libc6
42  *980213 (1.83) Phil Blundell:          set ATF_COM on new entries
43  *980629 (1.84) Arnaldo Carvalho de Melo: gettext instead of catgets
44  *990101 {1.85} Bernd Eckenfels         fixed usage and return codes
45  *990105 (1.86) Phil Blundell:          don't ignore EINVAL in arp_set
46  *991121 (1.87) Bernd Eckenfels:        yes --device has a mandatory arg
47  *
48  *              This program is free software; you can redistribute it
49  *              and/or  modify it under  the terms of  the GNU General
50  *              Public  License as  published  by  the  Free  Software
51  *              Foundation;  either  version 2 of the License, or  (at
52  *              your option) any later version.
53  */
54 #include <sys/types.h>
55 #include <sys/socket.h>
56 #include <sys/ioctl.h>
57 #include <net/if.h>
58 /* #include <linux/netdevice.h> */
59 /* #include <linux/if_arp.h>    */
60 #include <net/if_arp.h>
61 #include <stdlib.h>
62 #include <stdio.h>
63 #include <errno.h>
64 #include <ctype.h>
65 #include <fcntl.h>
66 #include <string.h>
67 #include <getopt.h>
68 #include <unistd.h>
69 #include "net-support.h"
70 #include "pathnames.h"
71 #include "version.h"
72 #include "config.h"
73 #include "intl.h"
74 #include "util.h"
75
76 #define DFLT_AF "inet"
77 #define DFLT_HW "ether"
78
79 #define FEATURE_ARP
80 #include "lib/net-features.h"
81
82 char *Release = RELEASE, *Version = "arp 1.87 (1999-11-21)";
83
84 int opt_n = 0;                  /* do not resolve addresses     */
85 int opt_N = 0;                  /* use symbolic names           */
86 int opt_v = 0;                  /* debugging output flag        */
87 int opt_D = 0;                  /* HW-address is devicename     */
88 int opt_e = 0;                  /* 0=BSD output, 1=new linux    */
89 int opt_a = 0;                  /* all entries, substring match */
90 struct aftype *ap;              /* current address family       */
91 struct hwtype *hw;              /* current hardware type        */
92 int sockfd = 0;                 /* active socket descriptor     */
93 int hw_set = 0;                 /* flag if hw-type was set (-H) */
94 char device[16] = "";           /* current device               */
95 static void usage(void);
96
97 /* Delete an entry from the ARP cache. */
98 static int arp_del(char **args)
99 {
100     char host[128];
101     struct arpreq req;
102     struct sockaddr sa;
103     int flags = 0;
104     int err;
105
106     memset((char *) &req, 0, sizeof(req));
107
108     /* Resolve the host name. */
109     if (*args == NULL) {
110         fprintf(stderr, _("arp: need host name\n"));
111         return (-1);
112     }
113     safe_strncpy(host, *args, (sizeof host));
114     if (ap->input(0, host, &sa) < 0) {
115         ap->herror(host);
116         return (-1);
117     }
118     /* If a host has more than one address, use the correct one! */
119     memcpy((char *) &req.arp_pa, (char *) &sa, sizeof(struct sockaddr));
120
121     if (hw_set)
122         req.arp_ha.sa_family = hw->type;
123
124     req.arp_flags = ATF_PERM;
125     args++;
126     while (*args != NULL) {
127         if (opt_v)
128             fprintf(stderr, "args=%s\n", *args);
129         if (!strcmp(*args, "pub")) {
130             flags |= 1;
131             args++;
132             continue;
133         }
134         if (!strcmp(*args, "priv")) {
135             flags |= 2;
136             args++;
137             continue;
138         }
139         if (!strcmp(*args, "temp")) {
140             req.arp_flags &= ~ATF_PERM;
141             args++;
142             continue;
143         }
144         if (!strcmp(*args, "trail")) {
145             req.arp_flags |= ATF_USETRAILERS;
146             args++;
147             continue;
148         }
149         if (!strcmp(*args, "dontpub")) {
150 #ifdef HAVE_ATF_DONTPUB
151             req.arp_flags |= ATF_DONTPUB;
152 #else
153             ENOSUPP("arp", "ATF_DONTPUB");
154 #endif
155             args++;
156             continue;
157         }
158         if (!strcmp(*args, "auto")) {
159 #ifdef HAVE_ATF_MAGIC
160             req.arp_flags |= ATF_MAGIC;
161 #else
162             ENOSUPP("arp", "ATF_MAGIC");
163 #endif
164             args++;
165             continue;
166         }
167         if (!strcmp(*args, "dev")) {
168             if (*++args == NULL)
169                 usage();
170             safe_strncpy(device, *args, sizeof(device));
171             args++;
172             continue;
173         }
174         if (!strcmp(*args, "netmask")) {
175             if (*++args == NULL)
176                 usage();
177             if (strcmp(*args, "255.255.255.255") != 0) {
178                 strcpy(host, *args);
179                 if (ap->input(0, host, &sa) < 0) {
180                     ap->herror(host);
181                     return (-1);
182                 }
183                 memcpy((char *) &req.arp_netmask, (char *) &sa,
184                        sizeof(struct sockaddr));
185                 req.arp_flags |= ATF_NETMASK;
186             }
187             args++;
188             continue;
189         }
190         usage();
191     }
192     if (flags == 0)
193         flags = 3;
194
195     strcpy(req.arp_dev, device);
196
197     err = -1;
198
199     /* Call the kernel. */
200     if (flags & 2) {
201         if (opt_v)
202             fprintf(stderr, "arp: SIOCDARP(nopub)\n");
203         if ((err = ioctl(sockfd, SIOCDARP, &req) < 0)) {
204             if (errno == ENXIO) {
205                 if (flags & 1)
206                     goto nopub;
207                 printf(_("No ARP entry for %s\n"), host);
208                 return (-1);
209             }
210             perror("SIOCDARP(priv)");
211             return (-1);
212         }
213     }
214     if ((flags & 1) && (err)) {
215       nopub:
216         req.arp_flags |= ATF_PUBL;
217         if (opt_v)
218             fprintf(stderr, "arp: SIOCDARP(pub)\n");
219         if (ioctl(sockfd, SIOCDARP, &req) < 0) {
220             if (errno == ENXIO) {
221                 printf(_("No ARP entry for %s\n"), host);
222                 return (-1);
223             }
224             perror("SIOCDARP(pub)");
225             return (-1);
226         }
227     }
228     return (0);
229 }
230
231 /* Get the hardware address to a specified interface name */
232 static int arp_getdevhw(char *ifname, struct sockaddr *sa, struct hwtype *hw)
233 {
234     struct ifreq ifr;
235     struct hwtype *xhw;
236
237     strcpy(ifr.ifr_name, ifname);
238     if (ioctl(sockfd, SIOCGIFHWADDR, &ifr) < 0) {
239         fprintf(stderr, _("arp: cant get HW-Address for `%s': %s.\n"), ifname, strerror(errno));
240         return (-1);
241     }
242     if (hw && (ifr.ifr_hwaddr.sa_family != hw->type)) {
243         fprintf(stderr, _("arp: protocol type mismatch.\n"));
244         return (-1);
245     }
246     memcpy((char *) sa, (char *) &(ifr.ifr_hwaddr), sizeof(struct sockaddr));
247
248     if (opt_v) {
249         if (!(xhw = get_hwntype(ifr.ifr_hwaddr.sa_family)) || (xhw->print == 0)) {
250             xhw = get_hwntype(-1);
251         }
252         fprintf(stderr, _("arp: device `%s' has HW address %s `%s'.\n"), ifname, xhw->name, xhw->print((char *)&ifr.ifr_hwaddr.sa_data));
253     }
254     return (0);
255 }
256
257 /* Set an entry in the ARP cache. */
258 static int arp_set(char **args)
259 {
260     char host[128];
261     struct arpreq req;
262     struct sockaddr sa;
263     int flags;
264
265     memset((char *) &req, 0, sizeof(req));
266
267     /* Resolve the host name. */
268     if (*args == NULL) {
269         fprintf(stderr, _("arp: need host name\n"));
270         return (-1);
271     }
272     safe_strncpy(host, *args++, (sizeof host));
273     if (ap->input(0, host, &sa) < 0) {
274         ap->herror(host);
275         return (-1);
276     }
277     /* If a host has more than one address, use the correct one! */
278     memcpy((char *) &req.arp_pa, (char *) &sa, sizeof(struct sockaddr));
279
280     /* Fetch the hardware address. */
281     if (*args == NULL) {
282         fprintf(stderr, _("arp: need hardware address\n"));
283         return (-1);
284     }
285     if (opt_D) {
286         if (arp_getdevhw(*args++, &req.arp_ha, hw_set ? hw : NULL) < 0)
287             return (-1);
288     } else {
289         if (hw->input(*args++, &req.arp_ha) < 0) {
290             fprintf(stderr, _("arp: invalid hardware address\n"));
291             return (-1);
292         }
293     }
294
295     /* Check out any modifiers. */
296     flags = ATF_PERM | ATF_COM;
297     while (*args != NULL) {
298         if (!strcmp(*args, "temp")) {
299             flags &= ~ATF_PERM;
300             args++;
301             continue;
302         }
303         if (!strcmp(*args, "pub")) {
304             flags |= ATF_PUBL;
305             args++;
306             continue;
307         }
308         if (!strcmp(*args, "priv")) {
309             flags &= ~ATF_PUBL;
310             args++;
311             continue;
312         }
313         if (!strcmp(*args, "trail")) {
314             flags |= ATF_USETRAILERS;
315             args++;
316             continue;
317         }
318         if (!strcmp(*args, "dontpub")) {
319 #ifdef HAVE_ATF_DONTPUB
320             flags |= ATF_DONTPUB;
321 #else
322             ENOSUPP("arp", "ATF_DONTPUB");
323 #endif
324             args++;
325             continue;
326         }
327         if (!strcmp(*args, "auto")) {
328 #ifdef HAVE_ATF_MAGIC
329             flags |= ATF_MAGIC;
330 #else
331             ENOSUPP("arp", "ATF_MAGIC");
332 #endif
333             args++;
334             continue;
335         }
336         if (!strcmp(*args, "dev")) {
337             if (*++args == NULL)
338                 usage();
339             safe_strncpy(device, *args, sizeof(device));
340             args++;
341             continue;
342         }
343         if (!strcmp(*args, "netmask")) {
344             if (*++args == NULL)
345                 usage();
346             if (strcmp(*args, "255.255.255.255") != 0) {
347                 strcpy(host, *args);
348                 if (ap->input(0, host, &sa) < 0) {
349                     ap->herror(host);
350                     return (-1);
351                 }
352                 memcpy((char *) &req.arp_netmask, (char *) &sa,
353                        sizeof(struct sockaddr));
354                 flags |= ATF_NETMASK;
355             }
356             args++;
357             continue;
358         }
359         usage();
360     }
361
362     /* Fill in the remainder of the request. */
363     req.arp_flags = flags;
364
365     strcpy(req.arp_dev, device);
366
367     /* Call the kernel. */
368     if (opt_v)
369         fprintf(stderr, "arp: SIOCSARP()\n");
370     if (ioctl(sockfd, SIOCSARP, &req) < 0) {
371         perror("SIOCSARP");
372         return (-1);
373     }
374     return (0);
375 }
376
377
378 /* Process an EtherFile */
379 static int arp_file(char *name)
380 {
381     char buff[1024];
382     char *sp, *args[32];
383     int linenr, argc;
384     FILE *fp;
385
386     if ((fp = fopen(name, "r")) == NULL) {
387         fprintf(stderr, _("arp: cannot open etherfile %s !\n"), name);
388         return (-1);
389     }
390     /* Read the lines in the file. */
391     linenr = 0;
392     while (fgets(buff, sizeof(buff), fp) != (char *) NULL) {
393         linenr++;
394         if (opt_v == 1)
395             fprintf(stderr, ">> %s", buff);
396         if ((sp = strchr(buff, '\n')) != (char *) NULL)
397             *sp = '\0';
398         if (buff[0] == '#' || buff[0] == '\0')
399             continue;
400
401         argc = getargs(buff, args);
402         if (argc < 2) {
403             fprintf(stderr, _("arp: format error on line %u of etherfile %s !\n"),
404                     linenr, name);
405             continue;
406         }
407         if (strchr (args[0], ':') != NULL) {
408             /* We have a correct ethers file, switch hw adress and hostname
409                for arp */
410             char *cp;
411             cp = args[1];
412             args[1] = args[0];
413             args[0] = cp;
414         }
415         if (arp_set(args) != 0)
416             fprintf(stderr, _("arp: cannot set entry on line %u of etherfile %s !\n"),
417                     linenr, name);
418     }
419
420     (void) fclose(fp);
421     return (0);
422 }
423
424
425 /* Print the contents of an ARP request block. */
426 static void arp_disp_2(char *name, int type, int arp_flags, char *hwa, char *mask, char *dev)
427 {
428     static int title = 0;
429     struct hwtype *xhw;
430     char flags[10];
431
432     xhw = get_hwntype(type);
433     if (xhw == NULL)
434         xhw = get_hwtype(DFLT_HW);
435
436     if (title++ == 0) {
437         printf(_("Address                  HWtype  HWaddress           Flags Mask            Iface\n"));
438     }
439     /* Setup the flags. */
440     flags[0] = '\0';
441     if (arp_flags & ATF_COM)
442         strcat(flags, "C");
443     if (arp_flags & ATF_PERM)
444         strcat(flags, "M");
445     if (arp_flags & ATF_PUBL)
446         strcat(flags, "P");
447 #ifdef HAVE_ATF_MAGIC
448     if (arp_flags & ATF_MAGIC)
449         strcat(flags, "A");
450 #endif
451 #ifdef HAVE_ATF_DONTPUB
452     if (arp_flags & ATF_DONTPUB)
453         strcat(flags, "!");
454 #endif
455     if (arp_flags & ATF_USETRAILERS)
456         strcat(flags, "T");
457
458     if (!(arp_flags & ATF_NETMASK))
459         mask = "";
460
461     printf("%-23.23s  ", name);
462
463     if (!(arp_flags & ATF_COM)) {
464         if (arp_flags & ATF_PUBL)
465             printf("%-8.8s%-20.20s", "*", "*");
466         else
467             printf("%-8.8s%-20.20s", "", _("(incomplete)"));
468     } else {
469         printf("%-8.8s%-20.20s", xhw->name, hwa);
470     }
471
472     printf("%-6.6s%-15.15s %s\n", flags, mask, dev);
473 }
474
475 /* Print the contents of an ARP request block. */
476 static void arp_disp(char *name, char *ip, int type, int arp_flags, char *hwa, char *mask, char *dev)
477 {
478     struct hwtype *xhw;
479
480     xhw = get_hwntype(type);
481     if (xhw == NULL)
482         xhw = get_hwtype(DFLT_HW);
483
484     printf(_("%s (%s) at "), name, ip);
485
486     if (!(arp_flags & ATF_COM)) {
487         if (arp_flags & ATF_PUBL)
488             printf("* ");
489         else
490             printf(_("<incomplete> "));
491     } else {
492         printf("%s [%s] ", hwa, xhw->name);
493     }
494
495     if (arp_flags & ATF_NETMASK)
496         printf(_("netmask %s "), mask);
497
498     if (arp_flags & ATF_PERM)
499         printf("PERM ");
500     if (arp_flags & ATF_PUBL)
501         printf("PUP ");
502 #ifdef HAVE_ATF_MAGIC
503     if (arp_flags & ATF_MAGIC)
504         printf("AUTO ");
505 #endif
506 #ifdef HAVE_ATF_DONTPUB
507     if (arp_flags & ATF_DONTPUB)
508         printf("DONTPUB ");
509 #endif
510     if (arp_flags & ATF_USETRAILERS)
511         printf("TRAIL ");
512
513     printf(_("on %s\n"), dev);
514 }
515
516
517 /* Display the contents of the ARP cache in the kernel. */
518 static int arp_show(char *name)
519 {
520     char host[100];
521     struct sockaddr sa;
522     char ip[100];
523     char hwa[100];
524     char mask[100];
525     char line[200];
526     char dev[100];
527     int type, flags;
528     FILE *fp;
529     char *hostname;
530     int num, entries = 0, showed = 0;
531
532     host[0] = '\0';
533
534     if (name != NULL) {
535         /* Resolve the host name. */
536         safe_strncpy(host, name, (sizeof host));
537         if (ap->input(0, host, &sa) < 0) {
538             ap->herror(host);
539             return (-1);
540         }
541         safe_strncpy(host, ap->sprint(&sa, 1), sizeof(host));
542     }
543     /* Open the PROCps kernel table. */
544     if ((fp = fopen(_PATH_PROCNET_ARP, "r")) == NULL) {
545         perror(_PATH_PROCNET_ARP);
546         return (-1);
547     }
548     /* Bypass header -- read until newline */
549     if (fgets(line, sizeof(line), fp) != (char *) NULL) {
550         strcpy(mask, "-");
551         strcpy(dev, "-");
552         /* Read the ARP cache entries. */
553         for (; fgets(line, sizeof(line), fp);) {
554             num = sscanf(line, "%s 0x%x 0x%x %100s %100s %100s\n",
555                          ip, &type, &flags, hwa, mask, dev);
556             if (num < 4)
557                 break;
558
559             entries++;
560             /* if the user specified hw-type differs, skip it */
561             if (hw_set && (type != hw->type))
562                 continue;
563
564             /* if the user specified address differs, skip it */
565             if (host[0] && strcmp(ip, host))
566                 continue;
567
568             /* if the user specified device differs, skip it */
569             if (device[0] && strcmp(dev, device))
570                 continue;
571
572             showed++;
573             /* This IS ugly but it works -be */
574             if (opt_n)
575                 hostname = "?";
576             else {
577                 if (ap->input(0, ip, &sa) < 0)
578                     hostname = ip;
579                 else
580                     hostname = ap->sprint(&sa, opt_n | 0x8000);
581                 if (strcmp(hostname, ip) == 0)
582                     hostname = "?";
583             }
584
585             if (opt_e)
586                 arp_disp_2(hostname[0] == '?' ? ip : hostname, type, flags, hwa, mask, dev);
587             else
588                 arp_disp(hostname, ip, type, flags, hwa, mask, dev);
589         }
590     }
591     if (opt_v)
592         printf(_("Entries: %d\tSkipped: %d\tFound: %d\n"), entries, entries - showed, showed);
593
594     if (!showed) {
595         if (host[0] && !opt_a)
596             printf(_("%s (%s) -- no entry\n"), name, host);
597         else if (hw_set || host[0] || device[0]) {
598             printf(_("arp: in %d entries no match found.\n"), entries);
599         }
600     }
601     (void) fclose(fp);
602     return (0);
603 }
604
605 static void version(void)
606 {
607     fprintf(stderr, "%s\n%s\n%s\n", Release, Version, Features);
608     exit(E_VERSION);
609 }
610
611 static void usage(void)
612 {
613     fprintf(stderr, _("Usage:\n  arp [-vn]  [<HW>] [-i <if>] [-a] [<hostname>]             <-Display ARP cache\n"));
614     fprintf(stderr, _("  arp [-v]          [-i <if>] -d  <hostname> [pub][nopub]    <-Delete ARP entry\n"));
615     fprintf(stderr, _("  arp [-vnD] [<HW>] [-i <if>] -f  [<filename>]              <-Add entry from file\n"));
616     fprintf(stderr, _("  arp [-v]   [<HW>] [-i <if>] -s  <hostname> <hwaddr> [temp][nopub] <-Add entry\n"));
617     fprintf(stderr, _("  arp [-v]   [<HW>] [-i <if>] -s  <hostname> <hwaddr> [netmask <nm>] pub  <-''-\n"));
618     fprintf(stderr, _("  arp [-v]   [<HW>] [-i <if>] -Ds <hostname> <if> [netmask <nm>] pub      <-''-\n\n"));
619     
620     fprintf(stderr, _("        -a                       display (all) hosts in alternative (BSD) style\n"));
621     fprintf(stderr, _("        -s, --set                set a new ARP entry\n"));
622     fprintf(stderr, _("        -d, --delete             delete a specified entry\n"));
623     fprintf(stderr, _("        -v, --verbose            be verbose\n"));
624     fprintf(stderr, _("        -n, --numeric            don't resolve names\n"));
625     fprintf(stderr, _("        -i, --device             specify network interface (e.g. eth0)\n"));
626     fprintf(stderr, _("        -D, --use-device         read <hwaddr> from given device\n"));
627     fprintf(stderr, _("        -A, -p, --protocol       specify protocol family\n"));
628     fprintf(stderr, _("        -f, --file               read new entries from file or from /etc/ethers\n\n"));
629
630     fprintf(stderr, _("  <HW>=Use '-H <hw>' to specify hardware address type. Default: %s\n"), DFLT_HW);
631     fprintf(stderr, _("  List of possible hardware types (which support ARP):\n"));
632     print_hwlist(1); /* 1 = ARPable */
633     exit(E_USAGE);
634 }
635
636 int main(int argc, char **argv)
637 {
638     int i, lop, what;
639     struct option longopts[] =
640     {
641         {"verbose", 0, 0, 'v'},
642         {"version", 0, 0, 'V'},
643         {"all", 0, 0, 'a'},
644         {"delete", 0, 0, 'd'},
645         {"file", 0, 0, 'f'},
646         {"numeric", 0, 0, 'n'},
647         {"set", 0, 0, 's'},
648         {"protocol", 1, 0, 'A'},
649         {"hw-type", 1, 0, 'H'},
650         {"device", 1, 0, 'i'},
651         {"help", 0, 0, 'h'},
652         {"use-device", 0, 0, 'D'},
653         {"symbolic", 0, 0, 'N'},
654         {NULL, 0, 0, 0}
655     };
656
657 #if I18N
658     bindtextdomain("net-tools", "/usr/share/locale");
659     textdomain("net-tools");
660 #endif
661
662     /* Initialize variables... */
663     if ((hw = get_hwtype(DFLT_HW)) == NULL) {
664         fprintf(stderr, _("%s: hardware type not supported!\n"), DFLT_HW);
665         return (-1);
666     }
667     if ((ap = get_aftype(DFLT_AF)) == NULL) {
668         fprintf(stderr, _("%s: address family not supported!\n"), DFLT_AF);
669         return (-1);
670     }
671     what = 0;
672
673     /* Fetch the command-line arguments. */
674     /* opterr = 0; */
675     while ((i = getopt_long(argc, argv, "A:H:adfp:nsei:t:vh?DNV", longopts, &lop)) != EOF)
676         switch (i) {
677         case 'a':
678             what = 1;
679             opt_a = 1;
680             break;
681         case 'f':
682             what = 2;
683             break;
684         case 'd':
685             what = 3;
686             break;
687         case 's':
688             what = 4;
689             break;
690
691
692         case 'e':
693             opt_e = 1;
694             break;
695         case 'n':
696             opt_n = FLAG_NUM;
697             break;
698         case 'D':
699             opt_D = 1;
700             break;
701         case 'N':
702             opt_N = FLAG_SYM;
703             fprintf(stderr, _("arp: -N not yet supported.\n"));
704             break;
705         case 'v':
706             opt_v = 1;
707             break;
708
709         case 'A':
710         case 'p':
711             ap = get_aftype(optarg);
712             if (ap == NULL) {
713                 fprintf(stderr, _("arp: %s: unknown address family.\n"),
714                         optarg);
715                 exit(-1);
716             }
717             break;
718         case 'H':
719         case 't':
720             hw = get_hwtype(optarg);
721             if (hw == NULL) {
722                 fprintf(stderr, _("arp: %s: unknown hardware type.\n"),
723                         optarg);
724                 exit(-1);
725             }
726             hw_set = 1;
727             break;
728         case 'i':
729             safe_strncpy(device, optarg, sizeof(device));
730             break;
731
732         case 'V':
733             version();
734         case '?':
735         case 'h':
736         default:
737             usage();
738         }
739
740     if (ap->af != AF_INET) {
741         fprintf(stderr, _("arp: %s: kernel only supports 'inet'.\n"),
742                 ap->name);
743         exit(-1);
744     }
745
746     /* If not hw type specified get default */
747     if(hw_set==0)
748         if ((hw = get_hwtype(DFLT_HW)) == NULL) {
749           fprintf(stderr, _("%s: hardware type not supported!\n"), DFLT_HW);
750           return (-1);
751         }
752
753     if (hw->alen <= 0) {
754         fprintf(stderr, _("arp: %s: hardware type without ARP support.\n"),
755                 hw->name);
756         exit(-1);
757     }
758     if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
759         perror("socket");
760         exit(-1);
761     }
762     /* Now see what we have to do here... */
763     switch (what) {
764     case 0:
765         opt_e = 1;
766         what = arp_show(argv[optind]);
767         break;
768
769     case 1:                     /* show an ARP entry in the cache */
770         what = arp_show(argv[optind]);
771         break;
772
773     case 2:                     /* process an EtherFile */
774         what = arp_file(argv[optind] ? argv[optind] : "/etc/ethers");
775         break;
776
777     case 3:                     /* delete an ARP entry from the cache */
778         what = arp_del(&argv[optind]);
779         break;
780
781     case 4:                     /* set an ARP entry in the cache */
782         what = arp_set(&argv[optind]);
783         break;
784
785     default:
786         usage();
787     }
788
789     exit(what);
790 }