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