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