fixes for man page bugs reported by Hugh Redelmeier.
[oss-qm-packages.git] / arp.c
blob5c20449e1960c2c75abcab5c7f573c2285a96fc0
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.
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.
11 * Version: $Id: arp.c,v 1.23 2003/02/08 19:56:25 ecki Exp $
13 * Maintainer: Bernd 'eckes' Eckenfels, <net-tools@lina.inka.de>
15 * Author: Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
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
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.
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"
77 #define DFLT_AF "inet"
78 #define DFLT_HW "ether"
80 #define FEATURE_ARP
81 #include "lib/net-features.h"
83 char *Release = RELEASE, *Version = "arp 1.88 (2001-04-04)";
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);
98 /* Delete an entry from the ARP cache. */
99 static int arp_del(char **args)
101 char host[128];
102 struct arpreq req;
103 struct sockaddr sa;
104 int flags = 0;
105 int deleted = 0;
107 memset((char *) &req, 0, sizeof(req));
109 /* Resolve the host name. */
110 if (*args == NULL) {
111 fprintf(stderr, _("arp: need host name\n"));
112 return (-1);
114 safe_strncpy(host, *args, (sizeof host));
115 if (ap->input(0, host, &sa) < 0) {
116 ap->herror(host);
117 return (-1);
119 /* If a host has more than one address, use the correct one! */
120 memcpy((char *) &req.arp_pa, (char *) &sa, sizeof(struct sockaddr));
122 if (hw_set)
123 req.arp_ha.sa_family = hw->type;
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;
135 if (!strcmp(*args, "priv")) {
136 flags |= 2;
137 args++;
138 continue;
140 if (!strcmp(*args, "temp")) {
141 req.arp_flags &= ~ATF_PERM;
142 args++;
143 continue;
145 if (!strcmp(*args, "trail")) {
146 req.arp_flags |= ATF_USETRAILERS;
147 args++;
148 continue;
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;
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;
168 if (!strcmp(*args, "dev")) {
169 if (*++args == NULL)
170 usage();
171 safe_strncpy(device, *args, sizeof(device));
172 args++;
173 continue;
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);
184 memcpy((char *) &req.arp_netmask, (char *) &sa,
185 sizeof(struct sockaddr));
186 req.arp_flags |= ATF_NETMASK;
188 args++;
189 continue;
191 usage();
194 // if neighter priv nor pub is given, work on both
195 if (flags == 0)
196 flags = 3;
198 strcpy(req.arp_dev, device);
200 /* unfortuatelly the kernel interface does not allow us to
201 delete private entries anlone, so we need this hack
202 to avoid "not found" errors if we try both. */
203 deleted = 0;
205 /* Call the kernel. */
206 if (flags & 2) {
207 if (opt_v)
208 fprintf(stderr, "arp: SIOCDARP(nopub)\n");
209 if (ioctl(sockfd, SIOCDARP, &req) < 0) {
210 if ((errno == ENXIO) || (errno == ENOENT)) {
211 if (flags & 1)
212 goto nopub;
213 printf(_("No ARP entry for %s\n"), host);
214 return (-1);
216 perror("SIOCDARP(nopub)");
217 return (-1);
218 } else
219 deleted = 1;
221 if (!deleted && (flags & 1)) {
222 nopub:
223 req.arp_flags |= ATF_PUBL;
224 if (opt_v)
225 fprintf(stderr, "arp: SIOCDARP(pub)\n");
226 if (ioctl(sockfd, SIOCDARP, &req) < 0) {
227 if ((errno == ENXIO) || (errno == ENOENT)) {
228 printf(_("No ARP entry for %s\n"), host);
229 return (-1);
231 perror("SIOCDARP(pub)");
232 return (-1);
235 return (0);
238 /* Get the hardware address to a specified interface name */
239 static int arp_getdevhw(char *ifname, struct sockaddr *sa, struct hwtype *hw)
241 struct ifreq ifr;
242 struct hwtype *xhw;
244 strcpy(ifr.ifr_name, ifname);
245 if (ioctl(sockfd, SIOCGIFHWADDR, &ifr) < 0) {
246 fprintf(stderr, _("arp: cant get HW-Address for `%s': %s.\n"), ifname, strerror(errno));
247 return (-1);
249 if (hw && (ifr.ifr_hwaddr.sa_family != hw->type)) {
250 fprintf(stderr, _("arp: protocol type mismatch.\n"));
251 return (-1);
253 memcpy((char *) sa, (char *) &(ifr.ifr_hwaddr), sizeof(struct sockaddr));
255 if (opt_v) {
256 if (!(xhw = get_hwntype(ifr.ifr_hwaddr.sa_family)) || (xhw->print == 0)) {
257 xhw = get_hwntype(-1);
259 fprintf(stderr, _("arp: device `%s' has HW address %s `%s'.\n"), ifname, xhw->name, xhw->print((char *)&ifr.ifr_hwaddr.sa_data));
261 return (0);
264 /* Set an entry in the ARP cache. */
265 static int arp_set(char **args)
267 char host[128];
268 struct arpreq req;
269 struct sockaddr sa;
270 int flags;
272 memset((char *) &req, 0, sizeof(req));
274 /* Resolve the host name. */
275 if (*args == NULL) {
276 fprintf(stderr, _("arp: need host name\n"));
277 return (-1);
279 safe_strncpy(host, *args++, (sizeof host));
280 if (ap->input(0, host, &sa) < 0) {
281 ap->herror(host);
282 return (-1);
284 /* If a host has more than one address, use the correct one! */
285 memcpy((char *) &req.arp_pa, (char *) &sa, sizeof(struct sockaddr));
287 /* Fetch the hardware address. */
288 if (*args == NULL) {
289 fprintf(stderr, _("arp: need hardware address\n"));
290 return (-1);
292 if (opt_D) {
293 if (arp_getdevhw(*args++, &req.arp_ha, hw_set ? hw : NULL) < 0)
294 return (-1);
295 } else {
296 if (hw->input(*args++, &req.arp_ha) < 0) {
297 fprintf(stderr, _("arp: invalid hardware address\n"));
298 return (-1);
302 /* Check out any modifiers. */
303 flags = ATF_PERM | ATF_COM;
304 while (*args != NULL) {
305 if (!strcmp(*args, "temp")) {
306 flags &= ~ATF_PERM;
307 args++;
308 continue;
310 if (!strcmp(*args, "pub")) {
311 flags |= ATF_PUBL;
312 args++;
313 continue;
315 if (!strcmp(*args, "priv")) {
316 flags &= ~ATF_PUBL;
317 args++;
318 continue;
320 if (!strcmp(*args, "trail")) {
321 flags |= ATF_USETRAILERS;
322 args++;
323 continue;
325 if (!strcmp(*args, "dontpub")) {
326 #ifdef HAVE_ATF_DONTPUB
327 flags |= ATF_DONTPUB;
328 #else
329 ENOSUPP("arp", "ATF_DONTPUB");
330 #endif
331 args++;
332 continue;
334 if (!strcmp(*args, "auto")) {
335 #ifdef HAVE_ATF_MAGIC
336 flags |= ATF_MAGIC;
337 #else
338 ENOSUPP("arp", "ATF_MAGIC");
339 #endif
340 args++;
341 continue;
343 if (!strcmp(*args, "dev")) {
344 if (*++args == NULL)
345 usage();
346 safe_strncpy(device, *args, sizeof(device));
347 args++;
348 continue;
350 if (!strcmp(*args, "netmask")) {
351 if (*++args == NULL)
352 usage();
353 if (strcmp(*args, "255.255.255.255") != 0) {
354 strcpy(host, *args);
355 if (ap->input(0, host, &sa) < 0) {
356 ap->herror(host);
357 return (-1);
359 memcpy((char *) &req.arp_netmask, (char *) &sa,
360 sizeof(struct sockaddr));
361 flags |= ATF_NETMASK;
363 args++;
364 continue;
366 usage();
369 /* Fill in the remainder of the request. */
370 req.arp_flags = flags;
372 strcpy(req.arp_dev, device);
374 /* Call the kernel. */
375 if (opt_v)
376 fprintf(stderr, "arp: SIOCSARP()\n");
377 if (ioctl(sockfd, SIOCSARP, &req) < 0) {
378 perror("SIOCSARP");
379 return (-1);
381 return (0);
385 /* Process an EtherFile */
386 static int arp_file(char *name)
388 char buff[1024];
389 char *sp, *args[32];
390 int linenr, argc;
391 FILE *fp;
393 if ((fp = fopen(name, "r")) == NULL) {
394 fprintf(stderr, _("arp: cannot open etherfile %s !\n"), name);
395 return (-1);
397 /* Read the lines in the file. */
398 linenr = 0;
399 while (fgets(buff, sizeof(buff), fp) != (char *) NULL) {
400 linenr++;
401 if (opt_v == 1)
402 fprintf(stderr, ">> %s", buff);
403 if ((sp = strchr(buff, '\n')) != (char *) NULL)
404 *sp = '\0';
405 if (buff[0] == '#' || buff[0] == '\0')
406 continue;
408 argc = getargs(buff, args);
409 if (argc < 2) {
410 fprintf(stderr, _("arp: format error on line %u of etherfile %s !\n"),
411 linenr, name);
412 continue;
414 if (strchr (args[0], ':') != NULL) {
415 /* We have a correct ethers file, switch hw adress and hostname
416 for arp */
417 char *cp;
418 cp = args[1];
419 args[1] = args[0];
420 args[0] = cp;
422 if (arp_set(args) != 0)
423 fprintf(stderr, _("arp: cannot set entry on line %u of etherfile %s !\n"),
424 linenr, name);
427 (void) fclose(fp);
428 return (0);
432 /* Print the contents of an ARP request block. */
433 static void arp_disp_2(char *name, int type, int arp_flags, char *hwa, char *mask, char *dev)
435 static int title = 0;
436 struct hwtype *xhw;
437 char flags[10];
439 xhw = get_hwntype(type);
440 if (xhw == NULL)
441 xhw = get_hwtype(DFLT_HW);
443 if (title++ == 0) {
444 printf(_("Address HWtype HWaddress Flags Mask Iface\n"));
446 /* Setup the flags. */
447 flags[0] = '\0';
448 if (arp_flags & ATF_COM)
449 strcat(flags, "C");
450 if (arp_flags & ATF_PERM)
451 strcat(flags, "M");
452 if (arp_flags & ATF_PUBL)
453 strcat(flags, "P");
454 #ifdef HAVE_ATF_MAGIC
455 if (arp_flags & ATF_MAGIC)
456 strcat(flags, "A");
457 #endif
458 #ifdef HAVE_ATF_DONTPUB
459 if (arp_flags & ATF_DONTPUB)
460 strcat(flags, "!");
461 #endif
462 if (arp_flags & ATF_USETRAILERS)
463 strcat(flags, "T");
465 if (!(arp_flags & ATF_NETMASK))
466 mask = "";
468 printf("%-23.23s ", name);
470 if (!(arp_flags & ATF_COM)) {
471 if (arp_flags & ATF_PUBL)
472 printf("%-8.8s%-20.20s", "*", _("<from_interface>"));
473 else
474 printf("%-8.8s%-20.20s", "", _("(incomplete)"));
475 } else {
476 printf("%-8.8s%-20.20s", xhw->name, hwa);
479 printf("%-6.6s%-15.15s %s\n", flags, mask, dev);
482 /* Print the contents of an ARP request block. */
483 static void arp_disp(char *name, char *ip, int type, int arp_flags, char *hwa, char *mask, char *dev)
485 struct hwtype *xhw;
487 xhw = get_hwntype(type);
488 if (xhw == NULL)
489 xhw = get_hwtype(DFLT_HW);
491 printf(_("%s (%s) at "), name, ip);
493 if (!(arp_flags & ATF_COM)) {
494 if (arp_flags & ATF_PUBL)
495 printf("<from_interface> ");
496 else
497 printf(_("<incomplete> "));
498 } else {
499 printf("%s [%s] ", hwa, xhw->name);
502 if (arp_flags & ATF_NETMASK)
503 printf(_("netmask %s "), mask);
505 if (arp_flags & ATF_PERM)
506 printf("PERM ");
507 if (arp_flags & ATF_PUBL)
508 printf("PUB ");
509 #ifdef HAVE_ATF_MAGIC
510 if (arp_flags & ATF_MAGIC)
511 printf("AUTO ");
512 #endif
513 #ifdef HAVE_ATF_DONTPUB
514 if (arp_flags & ATF_DONTPUB)
515 printf("DONTPUB ");
516 #endif
517 if (arp_flags & ATF_USETRAILERS)
518 printf("TRAIL ");
520 printf(_("on %s\n"), dev);
524 /* Display the contents of the ARP cache in the kernel. */
525 static int arp_show(char *name)
527 char host[100];
528 struct sockaddr sa;
529 char ip[100];
530 char hwa[100];
531 char mask[100];
532 char line[200];
533 char dev[100];
534 int type, flags;
535 FILE *fp;
536 char *hostname;
537 int num, entries = 0, showed = 0;
539 host[0] = '\0';
541 if (name != NULL) {
542 /* Resolve the host name. */
543 safe_strncpy(host, name, (sizeof host));
544 if (ap->input(0, host, &sa) < 0) {
545 ap->herror(host);
546 return (-1);
548 safe_strncpy(host, ap->sprint(&sa, 1), sizeof(host));
550 /* Open the PROCps kernel table. */
551 if ((fp = fopen(_PATH_PROCNET_ARP, "r")) == NULL) {
552 perror(_PATH_PROCNET_ARP);
553 return (-1);
555 /* Bypass header -- read until newline */
556 if (fgets(line, sizeof(line), fp) != (char *) NULL) {
557 strcpy(mask, "-");
558 strcpy(dev, "-");
559 /* Read the ARP cache entries. */
560 for (; fgets(line, sizeof(line), fp);) {
561 num = sscanf(line, "%s 0x%x 0x%x %100s %100s %100s\n",
562 ip, &type, &flags, hwa, mask, dev);
563 if (num < 4)
564 break;
566 entries++;
567 /* if the user specified hw-type differs, skip it */
568 if (hw_set && (type != hw->type))
569 continue;
571 /* if the user specified address differs, skip it */
572 if (host[0] && strcmp(ip, host))
573 continue;
575 /* if the user specified device differs, skip it */
576 if (device[0] && strcmp(dev, device))
577 continue;
579 showed++;
580 /* This IS ugly but it works -be */
581 if (opt_n)
582 hostname = "?";
583 else {
584 if (ap->input(0, ip, &sa) < 0)
585 hostname = ip;
586 else
587 hostname = ap->sprint(&sa, opt_n | 0x8000);
588 if (strcmp(hostname, ip) == 0)
589 hostname = "?";
592 if (opt_e)
593 arp_disp_2(hostname[0] == '?' ? ip : hostname, type, flags, hwa, mask, dev);
594 else
595 arp_disp(hostname, ip, type, flags, hwa, mask, dev);
598 if (opt_v)
599 printf(_("Entries: %d\tSkipped: %d\tFound: %d\n"), entries, entries - showed, showed);
601 if (!showed) {
602 if (host[0] && !opt_a)
603 printf(_("%s (%s) -- no entry\n"), name, host);
604 else if (hw_set || host[0] || device[0]) {
605 printf(_("arp: in %d entries no match found.\n"), entries);
608 (void) fclose(fp);
609 return (0);
612 static void version(void)
614 fprintf(stderr, "%s\n%s\n%s\n", Release, Version, Features);
615 exit(E_VERSION);
618 static void usage(void)
620 fprintf(stderr, _("Usage:\n arp [-vn] [<HW>] [-i <if>] [-a] [<hostname>] <-Display ARP cache\n"));
621 fprintf(stderr, _(" arp [-v] [-i <if>] -d <hostname> [pub][nopub] <-Delete ARP entry\n"));
622 fprintf(stderr, _(" arp [-vnD] [<HW>] [-i <if>] -f [<filename>] <-Add entry from file\n"));
623 fprintf(stderr, _(" arp [-v] [<HW>] [-i <if>] -s <hostname> <hwaddr> [temp][nopub] <-Add entry\n"));
624 fprintf(stderr, _(" arp [-v] [<HW>] [-i <if>] -Ds <hostname> <if> [netmask <nm>] pub <-''-\n\n"));
626 fprintf(stderr, _(" -a display (all) hosts in alternative (BSD) style\n"));
627 fprintf(stderr, _(" -s, --set set a new ARP entry\n"));
628 fprintf(stderr, _(" -d, --delete delete a specified entry\n"));
629 fprintf(stderr, _(" -v, --verbose be verbose\n"));
630 fprintf(stderr, _(" -n, --numeric don't resolve names\n"));
631 fprintf(stderr, _(" -i, --device specify network interface (e.g. eth0)\n"));
632 fprintf(stderr, _(" -D, --use-device read <hwaddr> from given device\n"));
633 fprintf(stderr, _(" -A, -p, --protocol specify protocol family\n"));
634 fprintf(stderr, _(" -f, --file read new entries from file or from /etc/ethers\n\n"));
636 fprintf(stderr, _(" <HW>=Use '-H <hw>' to specify hardware address type. Default: %s\n"), DFLT_HW);
637 fprintf(stderr, _(" List of possible hardware types (which support ARP):\n"));
638 print_hwlist(1); /* 1 = ARPable */
639 exit(E_USAGE);
642 int main(int argc, char **argv)
644 int i, lop, what;
645 struct option longopts[] =
647 {"verbose", 0, 0, 'v'},
648 {"version", 0, 0, 'V'},
649 {"all", 0, 0, 'a'},
650 {"delete", 0, 0, 'd'},
651 {"file", 0, 0, 'f'},
652 {"numeric", 0, 0, 'n'},
653 {"set", 0, 0, 's'},
654 {"protocol", 1, 0, 'A'},
655 {"hw-type", 1, 0, 'H'},
656 {"device", 1, 0, 'i'},
657 {"help", 0, 0, 'h'},
658 {"use-device", 0, 0, 'D'},
659 {"symbolic", 0, 0, 'N'},
660 {NULL, 0, 0, 0}
663 #if I18N
664 setlocale (LC_ALL, "");
665 bindtextdomain("net-tools", "/usr/share/locale");
666 textdomain("net-tools");
667 #endif
669 /* Initialize variables... */
670 if ((hw = get_hwtype(DFLT_HW)) == NULL) {
671 fprintf(stderr, _("%s: hardware type not supported!\n"), DFLT_HW);
672 return (-1);
674 if ((ap = get_aftype(DFLT_AF)) == NULL) {
675 fprintf(stderr, _("%s: address family not supported!\n"), DFLT_AF);
676 return (-1);
678 what = 0;
680 /* Fetch the command-line arguments. */
681 /* opterr = 0; */
682 while ((i = getopt_long(argc, argv, "A:H:adfp:nsei:t:vh?DNV", longopts, &lop)) != EOF)
683 switch (i) {
684 case 'a':
685 what = 1;
686 opt_a = 1;
687 break;
688 case 'f':
689 what = 2;
690 break;
691 case 'd':
692 what = 3;
693 break;
694 case 's':
695 what = 4;
696 break;
699 case 'e':
700 opt_e = 1;
701 break;
702 case 'n':
703 opt_n = FLAG_NUM;
704 break;
705 case 'D':
706 opt_D = 1;
707 break;
708 case 'N':
709 opt_N = FLAG_SYM;
710 fprintf(stderr, _("arp: -N not yet supported.\n"));
711 break;
712 case 'v':
713 opt_v = 1;
714 break;
716 case 'A':
717 case 'p':
718 ap = get_aftype(optarg);
719 if (ap == NULL) {
720 fprintf(stderr, _("arp: %s: unknown address family.\n"),
721 optarg);
722 exit(-1);
724 break;
725 case 'H':
726 case 't':
727 hw = get_hwtype(optarg);
728 if (hw == NULL) {
729 fprintf(stderr, _("arp: %s: unknown hardware type.\n"),
730 optarg);
731 exit(-1);
733 hw_set = 1;
734 break;
735 case 'i':
736 safe_strncpy(device, optarg, sizeof(device));
737 break;
739 case 'V':
740 version();
741 case '?':
742 case 'h':
743 default:
744 usage();
747 if (ap->af != AF_INET) {
748 fprintf(stderr, _("arp: %s: kernel only supports 'inet'.\n"),
749 ap->name);
750 exit(-1);
753 /* If not hw type specified get default */
754 if(hw_set==0)
755 if ((hw = get_hwtype(DFLT_HW)) == NULL) {
756 fprintf(stderr, _("%s: hardware type not supported!\n"), DFLT_HW);
757 return (-1);
760 if (hw->alen <= 0) {
761 fprintf(stderr, _("arp: %s: hardware type without ARP support.\n"),
762 hw->name);
763 exit(-1);
765 if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
766 perror("socket");
767 exit(-1);
769 /* Now see what we have to do here... */
770 switch (what) {
771 case 0:
772 opt_e = 1;
773 what = arp_show(argv[optind]);
774 break;
776 case 1: /* show an ARP entry in the cache */
777 what = arp_show(argv[optind]);
778 break;
780 case 2: /* process an EtherFile */
781 what = arp_file(argv[optind] ? argv[optind] : "/etc/ethers");
782 break;
784 case 3: /* delete an ARP entry from the cache */
785 what = arp_del(&argv[optind]);
786 break;
788 case 4: /* set an ARP entry in the cache */
789 what = arp_set(&argv[optind]);
790 break;
792 default:
793 usage();
796 exit(what);