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