PATCH - arp applet (Re: [BusyBox] Adding arp to busybox)

Charlie Brady charlieb-busybox at e-smith.com
Tue Apr 27 17:54:38 UTC 2004


On Mon, 26 Jan 2004, Paul van Gool wrote:

> I recently had to use arp on an embedded system and noticed busybox does
> not contain arp. So I added it. It's basically a port of the net-tools arp
> to busybox.
> 
> This mail has two attachments:
> 
> - A diff against the current busybox code to add arp
> - networking/arp.c

I've combined these into a single patch (unified diff), and ported to
1.00-pre10. Patch attached. Thanks!

--
Charlie

A: Because we read from top to bottom, left to right.
Q: Why should i start my reply below the quoted text?
-------------- next part --------------
diff -ruN busybox-1.00-pre10/include/applets.h busybox-1.00-pre10+arp/include/applets.h
--- busybox-1.00-pre10/include/applets.h	2004-04-06 12:59:43.000000000 -0400
+++ busybox-1.00-pre10+arp/include/applets.h	2004-04-26 12:02:43.000000000 -0400
@@ -63,6 +63,9 @@
 #ifdef CONFIG_AR
 	APPLET(ar, ar_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)
 #endif
+#ifdef CONFIG_ARP
+        APPLET(arp, arp_main, _BB_DIR_SBIN, _BB_SUID_NEVER)
+#endif
 #ifdef CONFIG_ARPING
 	APPLET(arping, arping_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)
 #endif
diff -ruN busybox-1.00-pre10/include/libbb.h busybox-1.00-pre10+arp/include/libbb.h
--- busybox-1.00-pre10/include/libbb.h	2004-03-15 03:28:38.000000000 -0500
+++ busybox-1.00-pre10+arp/include/libbb.h	2004-04-26 12:04:19.000000000 -0400
@@ -488,4 +488,36 @@
 #define HASH_MD5	2
 extern int hash_fd(int fd, const size_t size, const uint8_t hash_algo, uint8_t *hashval);
 
+/* This structure defines protocol families and their handlers. */
+struct aftype {
+        char *name;
+        char *title;
+        int af;
+        int alen;
+        char *(*print) (unsigned char *);
+        char *(*sprint) (struct sockaddr *, int numeric);
+        int (*input) (int type, char *bufp, struct sockaddr *);
+        void (*herror) (char *text);
+        int (*rprint) (int options);
+        int (*rinput) (int typ, int ext, char **argv);
+
+        /* may modify src */
+        int (*getmask) (char *src, struct sockaddr * mask, char *name);
+
+        int fd;
+        char *flag_file;
+};
+
+/* This structure defines hardware protocols and their handlers. */
+struct hwtype {
+        char *name;
+        char *title;
+        int type;
+        int alen;
+        char *(*print) (unsigned char *);
+        int (*input) (char *, struct sockaddr *);
+        int (*activate) (int fd);
+        int suppress_null_addr;
+};
+
 #endif /* __LIBCONFIG_H__ */
diff -ruN busybox-1.00-pre10/include/usage.h busybox-1.00-pre10+arp/include/usage.h
--- busybox-1.00-pre10/include/usage.h	2004-04-13 15:27:20.000000000 -0400
+++ busybox-1.00-pre10+arp/include/usage.h	2004-04-26 12:08:37.000000000 -0400
@@ -45,6 +45,28 @@
 	"\t-x\t\textract\n" \
 	"\t-v\t\tverbosely list files processed"
 
+#define arp_trivial_usage \
+        "[-evn] [-H type] [-i if] -a [hostname]\n" \
+        "\tarp [-v] [-i if] -d hostname [pub]\n" \
+        "\tarp [-v] [-H type] [-i if] -s hostname hw_addr [temp]\n" \
+        "\tarp [-v] [-H type] [-i if] -s hostname hw_addr [netmask nm] pub\n" \
+        "\tarp [-v] [-H type] [-i if] -Ds hostname ifa [netmask nm] pub\n" \
+        "\tarp [-vnD] [-H type] [-i if] -f [filename]\n"
+#define arp_full_usage \
+        "Manipulate the system ARP cache.\n"
+        "Options:\n" \
+        "\t-a\t\tdisplay (all) hosts in alternative (BSD) style\n" \
+        "\t-e\t\tdisplay (all) hosts in default (Linux) style\n" \
+        "\t-s\t\tset a new ARP entry\n" \
+        "\t-d\t\tdelete a specified entry\n" \
+        "\t-v\t\tbe verbose\n" \
+        "\t-n\t\tdon't resolve names\n" \
+        "\t-i if\tspecify network interface (e.g. eth0)\n" \
+        "\t-D\t\tread <hwaddr> from given device\n" \
+        "\t-A, -p\t\tspecify protocol family\n" \
+        "\t-f\t\tread new entries from file or from /etc/ethers\n" \
+        "\t-H hwtype\tto specify hardware address type\n"
+                           
 #define arping_trivial_usage \
 	"[-fqbDUA] [-c count] [-w timeout] [-I device] [-s sender] target\n"
 #define arping_full_usage \
diff -ruN busybox-1.00-pre10/libbb/interface.c busybox-1.00-pre10+arp/libbb/interface.c
--- busybox-1.00-pre10/libbb/interface.c	2004-03-15 03:28:42.000000000 -0500
+++ busybox-1.00-pre10+arp/libbb/interface.c	2004-04-26 16:29:25.000000000 -0400
@@ -135,26 +135,6 @@
 #define IFF_DYNAMIC     0x8000	/* dialup device with changing addresses */
 #endif
 
-/* This structure defines protocol families and their handlers. */
-struct aftype {
-	const char *name;
-	const char *title;
-	int af;
-	int alen;
-	char *(*print) (unsigned char *);
-	char *(*sprint) (struct sockaddr *, int numeric);
-	int (*input) (int type, char *bufp, struct sockaddr *);
-	void (*herror) (char *text);
-	int (*rprint) (int options);
-	int (*rinput) (int typ, int ext, char **argv);
-
-	/* may modify src */
-	int (*getmask) (char *src, struct sockaddr * mask, char *name);
-
-	int fd;
-	char *flag_file;
-};
-
 #ifdef KEEP_UNUSED
 
 static int flag_unx;
@@ -319,21 +299,22 @@
 		return (NULL);
 	return (buff);
 }
+#endif                                                  /* KEEP_UNUSED */
 
 static int INET_getsock(char *bufp, struct sockaddr *sap)
 {
 	char *sp = bufp, *bp;
 	unsigned int i;
 	unsigned val;
-	struct sockaddr_in *sin;
+        struct sockaddr_in *sock_in;
 
-	sin = (struct sockaddr_in *) sap;
-	sin->sin_family = AF_INET;
-	sin->sin_port = 0;
-
-	val = 0;
-	bp = (char *) &val;
-	for (i = 0; i < sizeof(sin->sin_addr.s_addr); i++) {
+        sock_in = (struct sockaddr_in *) sap;
+        sock_in->sin_family = AF_INET;
+        sock_in->sin_port = 0;
+
+        val = 0;
+        bp = (char *) &val;
+        for (i = 0; i < sizeof(sock_in->sin_addr.s_addr); i++) {
 		*sp = toupper(*sp);
 
 		if ((*sp >= 'A') && (*sp <= 'F'))
@@ -356,7 +337,7 @@
 
 		sp++;
 	}
-	sin->sin_addr.s_addr = htonl(val);
+        sock_in->sin_addr.s_addr = htonl(val);
 
 	return (sp - bufp);
 }
@@ -373,6 +354,7 @@
 	}
 }
 
+#ifdef KEEP_UNUSED
 static int INET_getnetmask(char *adr, struct sockaddr *m, char *name)
 {
 	struct sockaddr_in *mask = (struct sockaddr_in *) m;
@@ -399,7 +381,7 @@
 static struct aftype inet_aftype = {
 	"inet", "DARPA Internet", AF_INET, sizeof(unsigned long),
 	NULL /* UNUSED INET_print */ , INET_sprint,
-	NULL /* UNUSED INET_input */ , NULL /* UNUSED INET_reserror */ ,
+        INET_input, NULL /* UNUSED INET_reserror */ ,
 	NULL /*INET_rprint */ , NULL /*INET_rinput */ ,
 	NULL /* UNUSED INET_getnetmask */ ,
 	-1,
@@ -440,7 +422,6 @@
 	return (buff);
 }
 
-#ifdef KEEP_UNUSED
 static int INET6_getsock(char *bufp, struct sockaddr *sap)
 {
 	struct sockaddr_in6 *sin6;
@@ -464,12 +445,11 @@
 		return (INET6_resolve(bufp, (struct sockaddr_in6 *) sap));
 	}
 }
-#endif							/* KEEP_UNUSED */
 
 static struct aftype inet6_aftype = {
 	"inet6", "IPv6", AF_INET6, sizeof(struct in6_addr),
 	NULL /* UNUSED INET6_print */ , INET6_sprint,
-	NULL /* UNUSED INET6_input */ , NULL /* UNUSED INET6_reserror */ ,
+        INET6_input, NULL /* UNUSED INET6_reserror */ ,
 	NULL /*INET6_rprint */ , NULL /*INET6_rinput */ ,
 	NULL /* UNUSED INET6_getnetmask */ ,
 	-1,
@@ -670,9 +650,10 @@
 
 	free(buf);
 }
+#endif
 
 /* Check our protocol family table for this family. */
-static struct aftype *get_aftype(const char *name)
+struct aftype *get_aftype(const char *name)
 {
 	struct aftype **afp;
 
@@ -691,7 +672,6 @@
 		bb_error_msg(_("Please don't supply more than one address family."));
 	return (NULL);
 }
-#endif							/* KEEP_UNUSED */
 
 /* Check our protocol family table for this family. */
 static struct aftype *get_afntype(int af)
@@ -1349,18 +1329,6 @@
 	return 0;
 }
 
-/* This structure defines hardware protocols and their handlers. */
-struct hwtype {
-	const char *name;
-	const char *title;
-	int type;
-	int alen;
-	char *(*print) (unsigned char *);
-	int (*input) (char *, struct sockaddr *);
-	int (*activate) (int fd);
-	int suppress_null_addr;
-};
-
 static struct hwtype unspec_hwtype = {
 	"unspec", "UNSPEC", -1, 0,
 	UNSPEC_print, NULL, NULL
@@ -1677,7 +1645,26 @@
 #endif
 
 /* Check our hardware type table for this type. */
-static struct hwtype *get_hwntype(int type)
+struct hwtype *get_hwtype(const char *name)
+{
+   struct hwtype **hwp;
+
+#ifdef KEEP_UNUSED
+   if (!sVhwinit)
+      hwinit();
+#endif
+
+   hwp = hwtypes;
+   while (*hwp != NULL) {
+      if (!strcmp((*hwp)->name, name))
+         return (*hwp);
+      hwp++;
+   }
+   return (NULL);
+}
+
+/* Check our hardware type table for this type. */
+struct hwtype *get_hwntype(int type)
 {
 	struct hwtype **hwp;
 
diff -ruN busybox-1.00-pre10/networking/arp.c busybox-1.00-pre10+arp/networking/arp.c
--- busybox-1.00-pre10/networking/arp.c	1969-12-31 19:00:00.000000000 -0500
+++ busybox-1.00-pre10+arp/networking/arp.c	2004-04-26 16:44:31.000000000 -0400
@@ -0,0 +1,757 @@
+/*
+ * arp.c - Manipulate the system ARP cache
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Author: Fred N. van Kempen, <waltje at uwalt.nl.mugnet.org>
+ * Busybox port: Paul van Gool <pvangool at mimotech.com>
+ */
+
+#include <sys/ioctl.h>
+#include <sys/signal.h>
+#include <sys/time.h>
+
+#include <errno.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/ether.h>
+#include <netpacket/packet.h>
+
+#include "busybox.h"
+#include "inet_common.h"
+
+#define APPLET_NAME "arp"
+
+#define DFLT_AF "inet"
+#define DFLT_HW "ether"
+
+#define _PATH_PROCNET_ARP "/proc/net/arp"
+
+extern struct aftype *get_aftype(const char *name);
+extern struct hwtype *get_hwntype(int type);
+extern struct hwtype *get_hwtype(const char *name);
+
+int opt_n = 0;                  /* do not resolve addresses     */
+int opt_v = 0;                  /* debugging output flag        */
+int opt_D = 0;                  /* HW-address is devicename     */
+int opt_e = 0;                  /* 0=BSD output, 1=new linux    */
+int opt_a = 0;                  /* all entries, substring match */
+struct aftype *ap;              /* current address family       */
+struct hwtype *hw;              /* current hardware type        */
+int sockfd = 0;                 /* active socket descriptor     */
+int hw_set = 0;                 /* flag if hw-type was set (-H) */
+char device[16] = "";           /* current device               */
+
+/* Split the input string into multiple fields. */
+int getargs(char *string, char *arguments[])
+{
+    int len = strlen(string); 
+    char temp[len+1];
+    char *sp, *ptr;
+    int i, argc;
+    char want;
+
+    /*
+     * Copy the string into a buffer.  We may have to modify
+     * the original string because of all the quoting...
+     */
+    sp = string;
+    i = 0;
+    strcpy(temp, string);
+    ptr = temp;
+
+    /*
+     * Look for delimiters ("); if present whatever
+     * they enclose will be considered one argument.
+     */
+    while (*ptr != '\0' && i < 31) {
+	/* Ignore leading whitespace on input string. */
+	while (*ptr == ' ' || *ptr == '\t')
+	    ptr++;
+
+	/* Set string pointer. */
+	arguments[i++] = sp;
+
+	/* Check for any delimiters. */
+	if (*ptr == '"' || *ptr == '\'') {
+	    /*
+	     * Copy the string up to any whitespace OR the next
+	     * delimiter. If the delimiter was escaped, skip it
+	     * as it if was not there.
+	     */
+	    want = *ptr++;
+	    while (*ptr != '\0') {
+		if (*ptr == want && *(ptr - 1) != '\\') {
+		    ptr++;
+		    break;
+		}
+		*sp++ = *ptr++;
+	    }
+	} else {
+	    /* Just copy the string up to any whitespace. */
+	    while (*ptr != '\0' && *ptr != ' ' && *ptr != '\t')
+		*sp++ = *ptr++;
+	}
+	*sp++ = '\0';
+
+	/* Skip trailing whitespace. */
+	if (*ptr != '\0') {
+	    while (*ptr == ' ' || *ptr == '\t')
+		ptr++;
+	}
+    }
+    argc = i;
+    while (i < 32)
+	arguments[i++] = (char *) NULL;
+    return (argc);
+}
+
+/* Delete an entry from the ARP cache. */
+static int arp_del(char **args)
+{
+    char host[128];
+    struct arpreq req;
+    struct sockaddr sa;
+    int flags = 0;
+    int err;
+
+    memset((char *) &req, 0, sizeof(req));
+
+    /* Resolve the host name. */
+    if (*args == NULL) {
+        bb_error_msg("need host name\n");
+        return -1;
+    }
+
+    safe_strncpy(host, *args, (sizeof host));
+    if (ap->input(0, host, &sa) < 0) {
+        bb_herror_msg("%s", host);
+        return -1;
+    }
+
+    /* If a host has more than one address, use the correct one! */
+    memcpy((char *) &req.arp_pa, (char *) &sa, sizeof(struct sockaddr));
+
+    if (hw_set)
+        req.arp_ha.sa_family = hw->type;
+
+    req.arp_flags = ATF_PERM;
+    args++;
+    while (*args != NULL) {
+        if (opt_v)
+            bb_error_msg("args=%s\n", *args);
+        if (!strcmp(*args, "pub")) {
+            flags |= 1;
+            args++;
+            continue;
+        }
+        if (!strcmp(*args, "priv")) {
+            flags |= 2;
+            args++;
+            continue;
+        }
+        if (!strcmp(*args, "temp")) {
+            req.arp_flags &= ~ATF_PERM;
+            args++;
+            continue;
+        }
+        if (!strcmp(*args, "trail")) {
+            req.arp_flags |= ATF_USETRAILERS;
+            args++;
+            continue;
+        }
+        if (!strcmp(*args, "dontpub")) {
+#ifdef HAVE_ATF_DONTPUB
+            req.arp_flags |= ATF_DONTPUB;
+#else
+            bb_error_msg("feature ATF_DONTPUB is not supported");
+#endif
+            args++;
+            continue;
+        }
+        if (!strcmp(*args, "auto")) {
+#ifdef HAVE_ATF_MAGIC
+            req.arp_flags |= ATF_MAGIC;
+#else
+	    bb_error_msg("feature ATF_MAGIC is not supported");
+#endif
+            args++;
+            continue;
+        }
+        if (!strcmp(*args, "dev")) {
+            if (*++args == NULL)
+                bb_show_usage();
+            safe_strncpy(device, *args, sizeof(device));
+            args++;
+            continue;
+        }
+        if (!strcmp(*args, "netmask")) {
+            if (*++args == NULL)
+                bb_show_usage();
+            if (strcmp(*args, "255.255.255.255") != 0) {
+                strcpy(host, *args);
+                if (ap->input(0, host, &sa) < 0) {
+                    bb_herror_msg("%s", host);
+                    return (-1);
+                }
+                memcpy((char *) &req.arp_netmask, (char *) &sa,
+                       sizeof(struct sockaddr));
+                req.arp_flags |= ATF_NETMASK;
+            }
+            args++;
+            continue;
+        }
+        bb_show_usage();
+    }
+    if (flags == 0)
+        flags = 3;
+
+    strcpy(req.arp_dev, device);
+
+    err = -1;
+
+    /* Call the kernel. */
+    if (flags & 2) {
+        if (opt_v)
+            bb_error_msg("SIOCDARP(nopub)\n");
+        if ((err = ioctl(sockfd, SIOCDARP, &req) < 0)) {
+            if (errno == ENXIO) {
+                if (flags & 1)
+                    goto nopub;
+                printf("No ARP entry for %s\n", host);
+                return -1;
+            }
+            perror("SIOCDARP(priv)");
+            return -1;
+        }
+    }
+    if ((flags & 1) && (err)) {
+      nopub:
+        req.arp_flags |= ATF_PUBL;
+        if (opt_v)
+            bb_error_msg("SIOCDARP(pub)\n");
+        if (ioctl(sockfd, SIOCDARP, &req) < 0) {
+            if (errno == ENXIO) {
+                printf("No ARP entry for %s\n", host);
+                return -1;
+            }
+            perror("SIOCDARP(pub)");
+            return -1;
+        }
+    }
+    return 0;
+}
+
+/* Get the hardware address to a specified interface name */
+static int arp_getdevhw(char *ifname, struct sockaddr *sa, struct hwtype *hwt)
+{
+    struct ifreq ifr;
+    struct hwtype *xhw;
+
+    strcpy(ifr.ifr_name, ifname);
+    if (ioctl(sockfd, SIOCGIFHWADDR, &ifr) < 0) {
+        bb_error_msg("cant get HW-Address for `%s': %s.\n",
+              ifname, strerror(errno));
+        return -1;
+    }
+    if (hwt && (ifr.ifr_hwaddr.sa_family != hw->type)) {
+        bb_error_msg("protocol type mismatch.\n");
+        return -1;
+    }
+    memcpy((char *) sa, (char *) &(ifr.ifr_hwaddr), sizeof(struct sockaddr));
+
+    if (opt_v) {
+       if (!(xhw = get_hwntype(ifr.ifr_hwaddr.sa_family)) ||
+             (xhw->print == 0))
+       {
+          xhw = get_hwntype(-1);
+       }
+       bb_error_msg("device `%s' has HW address %s `%s'.\n",
+             ifname, xhw->name, xhw->print((char *)&ifr.ifr_hwaddr.sa_data));
+    }
+    return 0;
+}
+
+/* Set an entry in the ARP cache. */
+static int arp_set(char **args)
+{
+    char host[128];
+    struct arpreq req;
+    struct sockaddr sa;
+    int flags;
+
+    memset((char *) &req, 0, sizeof(req));
+
+    /* Resolve the host name. */
+    if (*args == NULL) {
+        bb_error_msg("need host name\n");
+        return -1;
+    }
+    safe_strncpy(host, *args++, (sizeof host));
+    if (ap->input(0, host, &sa) < 0) {
+        bb_herror_msg("%s", host);
+        return -1;
+    }
+    /* If a host has more than one address, use the correct one! */
+    memcpy((char *) &req.arp_pa, (char *) &sa, sizeof(struct sockaddr));
+
+    /* Fetch the hardware address. */
+    if (*args == NULL) {
+        bb_error_msg("need hardware address\n");
+        return -1;
+    }
+    if (opt_D) {
+        if (arp_getdevhw(*args++, &req.arp_ha, hw_set ? hw : NULL) < 0)
+            return (-1);
+    } else {
+        if (hw->input(*args++, &req.arp_ha) < 0) {
+            bb_error_msg("invalid hardware address\n");
+            return -1;
+        }
+    }
+
+    /* Check out any modifiers. */
+    flags = ATF_PERM | ATF_COM;
+    while (*args != NULL) {
+        if (!strcmp(*args, "temp")) {
+            flags &= ~ATF_PERM;
+            args++;
+            continue;
+        }
+        if (!strcmp(*args, "pub")) {
+            flags |= ATF_PUBL;
+            args++;
+            continue;
+        }
+        if (!strcmp(*args, "priv")) {
+            flags &= ~ATF_PUBL;
+            args++;
+            continue;
+        }
+        if (!strcmp(*args, "trail")) {
+            flags |= ATF_USETRAILERS;
+            args++;
+            continue;
+        }
+        if (!strcmp(*args, "dontpub")) {
+#ifdef HAVE_ATF_DONTPUB
+            flags |= ATF_DONTPUB;
+#else
+	    bb_error_msg("feature ATF_DONTPUB is not supported");
+#endif
+            args++;
+            continue;
+        }
+        if (!strcmp(*args, "auto")) {
+#ifdef HAVE_ATF_MAGIC
+            flags |= ATF_MAGIC;
+#else
+	    bb_error_msg("feature ATF_MAGIC is not supported");
+#endif
+            args++;
+            continue;
+        }
+        if (!strcmp(*args, "dev")) {
+            if (*++args == NULL)
+                bb_show_usage();
+            safe_strncpy(device, *args, sizeof(device));
+            args++;
+            continue;
+        }
+        if (!strcmp(*args, "netmask")) {
+            if (*++args == NULL)
+                bb_show_usage();
+            if (strcmp(*args, "255.255.255.255") != 0) {
+                strcpy(host, *args);
+                if (ap->input(0, host, &sa) < 0) {
+                    bb_herror_msg("%s", host);
+                    return (-1);
+                }
+                memcpy((char *) &req.arp_netmask, (char *) &sa,
+                       sizeof(struct sockaddr));
+                flags |= ATF_NETMASK;
+            }
+            args++;
+            continue;
+        }
+        bb_show_usage();
+    }
+
+    /* Fill in the remainder of the request. */
+    req.arp_flags = flags;
+
+    strcpy(req.arp_dev, device);
+
+    /* Call the kernel. */
+    if (opt_v)
+        bb_error_msg("SIOCSARP()\n");
+    if (ioctl(sockfd, SIOCSARP, &req) < 0) {
+        perror("SIOCSARP");
+        return -1;
+    }
+    return 0;
+}
+
+/* Process an EtherFile */
+static int arp_file(char *name)
+{
+    char buff[1024];
+    char *sp, *args[32];
+    int linenr, argc;
+    FILE *fp;
+
+    if ((fp = fopen(name, "r")) == NULL) {
+        bb_error_msg("cannot open etherfile %s!\n", name);
+        return -1;
+    }
+
+    /* Read the lines in the file. */
+    linenr = 0;
+    while (fgets(buff, sizeof(buff), fp) != (char *) NULL) {
+        linenr++;
+        if (opt_v == 1)
+            fprintf(stderr, ">> %s", buff);
+        if ((sp = strchr(buff, '\n')) != (char *) NULL)
+            *sp = '\0';
+        if (buff[0] == '#' || buff[0] == '\0')
+            continue;
+
+        argc = getargs(buff, args);
+        if (argc < 2) {
+            bb_error_msg("format error on line %u of etherfile %s!\n",
+                    linenr, name);
+            continue;
+        }
+        if (strchr (args[0], ':') != NULL) {
+            /* We have a correct ethers file, switch hw adress and hostname
+               for arp */
+            char *cp;
+            cp = args[1];
+            args[1] = args[0];
+            args[0] = cp;
+        }
+        if (arp_set(args) != 0)
+            bb_error_msg("cannot set entry on line %u of etherfile %s!\n",
+                    linenr, name);
+    }
+
+    (void) fclose(fp);
+
+    return 0;
+}
+
+/* Print the contents of an ARP request block. */
+static void arp_disp_2(char *name, int type, int arp_flags, char *hwa,
+      char *mask, char *dev)
+{
+    static int title = 0;
+    struct hwtype *xhw;
+    char flags[10];
+
+    xhw = get_hwntype(type);
+    if (xhw == NULL)
+        xhw = get_hwtype(DFLT_HW);
+
+    if (title++ == 0) {
+        printf("Address                  HWtype  HWaddress           Flags Mask            Iface\n");
+    }
+    /* Setup the flags. */
+    flags[0] = '\0';
+    if (arp_flags & ATF_COM)
+        strcat(flags, "C");
+    if (arp_flags & ATF_PERM)
+        strcat(flags, "M");
+    if (arp_flags & ATF_PUBL)
+        strcat(flags, "P");
+#ifdef HAVE_ATF_MAGIC
+    if (arp_flags & ATF_MAGIC)
+        strcat(flags, "A");
+#endif
+#ifdef HAVE_ATF_DONTPUB
+    if (arp_flags & ATF_DONTPUB)
+        strcat(flags, "!");
+#endif
+    if (arp_flags & ATF_USETRAILERS)
+        strcat(flags, "T");
+
+    if (!(arp_flags & ATF_NETMASK))
+        mask = "";
+
+    printf("%-23.23s  ", name);
+
+    if (!(arp_flags & ATF_COM)) {
+        if (arp_flags & ATF_PUBL)
+            printf("%-8.8s%-20.20s", "*", "*");
+        else
+            printf("%-8.8s%-20.20s", "", "(incomplete)");
+    } else {
+        printf("%-8.8s%-20.20s", xhw->name, hwa);
+    }
+
+    printf("%-6.6s%-15.15s %s\n", flags, mask, dev);
+}
+
+/* Print the contents of an ARP request block. */
+static void arp_disp(char *name, char *ip, int type, int arp_flags,
+      char *hwa, char *mask, char *dev)
+{
+    struct hwtype *xhw;
+
+    xhw = get_hwntype(type);
+    if (xhw == NULL)
+        xhw = get_hwtype(DFLT_HW);
+
+    printf("%s (%s) at ", name, ip);
+
+    if (!(arp_flags & ATF_COM)) {
+        if (arp_flags & ATF_PUBL)
+            printf("* ");
+        else
+            printf("<incomplete> ");
+    } else {
+        printf("%s [%s] ", hwa, xhw->name);
+    }
+
+    if (arp_flags & ATF_NETMASK)
+        printf("netmask %s ", mask);
+
+    if (arp_flags & ATF_PERM)
+        printf("PERM ");
+    if (arp_flags & ATF_PUBL)
+        printf("PUP ");
+#ifdef HAVE_ATF_MAGIC
+    if (arp_flags & ATF_MAGIC)
+        printf("AUTO ");
+#endif
+#ifdef HAVE_ATF_DONTPUB
+    if (arp_flags & ATF_DONTPUB)
+        printf("DONTPUB ");
+#endif
+    if (arp_flags & ATF_USETRAILERS)
+        printf("TRAIL ");
+
+    printf("on %s\n", dev);
+}
+
+/* Display the contents of the ARP cache in the kernel. */
+static int arp_show(char *name)
+{
+    char host[100];
+    struct sockaddr sa;
+    char ip[100];
+    char hwa[100];
+    char mask[100];
+    char line[200];
+    char dev[100];
+    int type, flags;
+    FILE *fp;
+    char *hostname;
+    int num, entries = 0, showed = 0;
+
+    host[0] = '\0';
+
+    if (name != NULL) {
+        /* Resolve the host name. */
+        safe_strncpy(host, name, (sizeof host));
+        if (ap->input(0, host, &sa) < 0) {
+            bb_herror_msg("%s", host);
+            return -1;
+        }
+        safe_strncpy(host, ap->sprint(&sa, 1), sizeof(host));
+    }
+    /* Open the PROCps kernel table. */
+    if ((fp = fopen(_PATH_PROCNET_ARP, "r")) == NULL) {
+        perror(_PATH_PROCNET_ARP);
+        return -1;
+    }
+    /* Bypass header -- read until newline */
+    if (fgets(line, sizeof(line), fp) != (char *) NULL) {
+        strcpy(mask, "-");
+        strcpy(dev, "-");
+        /* Read the ARP cache entries. */
+        for (; fgets(line, sizeof(line), fp);) {
+            num = sscanf(line, "%s 0x%x 0x%x %100s %100s %100s\n",
+                         ip, &type, &flags, hwa, mask, dev);
+            if (num < 4)
+                break;
+
+            entries++;
+            /* if the user specified hw-type differs, skip it */
+            if (hw_set && (type != hw->type))
+                continue;
+
+            /* if the user specified address differs, skip it */
+            if (host[0] && strcmp(ip, host))
+                continue;
+
+            /* if the user specified device differs, skip it */
+            if (device[0] && strcmp(dev, device))
+                continue;
+
+            showed++;
+            /* This IS ugly but it works -be */
+            if (opt_n)
+                hostname = "?";
+            else {
+                if (ap->input(0, ip, &sa) < 0)
+                    hostname = ip;
+                else
+                    hostname = ap->sprint(&sa, opt_n | 0x8000);
+                if (strcmp(hostname, ip) == 0)
+                    hostname = "?";
+            }
+
+            if (opt_e)
+                arp_disp_2(hostname[0] == '?' ? ip : hostname, type, flags,
+                      hwa, mask, dev);
+            else
+                arp_disp(hostname, ip, type, flags, hwa, mask, dev);
+        }
+    }
+    if (opt_v)
+        printf("Entries: %d\tSkipped: %d\tFound: %d\n",
+              entries, entries - showed, showed);
+
+    if (!showed) {
+        if (host[0] && !opt_a)
+            printf("%s (%s) -- no entry\n", name, host);
+        else if (hw_set || host[0] || device[0]) {
+            printf("in %d entries no match found.\n", entries);
+        }
+    }
+
+    (void) fclose(fp);
+
+    return 0;
+}
+
+int arp_main(int argc, char **argv)
+{
+   int what, i;
+
+   /* Initialize variables... */
+   if ((hw = get_hwtype(DFLT_HW)) == NULL) {
+      bb_error_msg("%s: hardware type not supported!\n", DFLT_HW);
+      return -1;
+   }
+   if ((ap = get_aftype(DFLT_AF)) == NULL) {
+      bb_error_msg("%s: address family not supported!\n", DFLT_AF);
+      return -1;
+   }
+   what = 0;
+
+   /* Fetch the command-line arguments. */
+   while ((i = getopt(argc, argv, "A:H:adfp:nsei:t:vh?DNV")) != EOF)
+      switch (i) {
+         case 'a':
+            what = 1;
+            opt_a = 1;
+            break;
+         case 'f':
+            what = 2;
+            break;
+         case 'd':
+            what = 3;
+            break;
+         case 's':
+            what = 4;
+            break;
+         case 'e':
+            opt_e = 1;
+            break;
+         case 'n':
+            opt_n = 1;
+            break;
+         case 'D':
+            opt_D = 1;
+            break;
+         case 'v':
+            opt_v = 1;
+            break;
+         case 'A':
+         case 'p':
+            ap = get_aftype(optarg);
+            if (ap == NULL) {
+               bb_error_msg("%s: unknown address family.\n", optarg);
+               exit(-1);
+            }
+            break;
+         case 'H':
+         case 't':
+            hw = get_hwtype(optarg);
+            if (hw == NULL) {
+               bb_error_msg("%s: unknown hardware type.\n", optarg);
+               exit(-1);
+            }
+            hw_set = 1;
+            break;
+         case 'i':
+            safe_strncpy(device, optarg, sizeof(device));
+            break;
+         case '?':
+         case 'h':
+         default:
+            bb_show_usage();
+      }
+
+   if (ap->af != AF_INET) {
+      bb_error_msg("%s: kernel only supports 'inet'.\n", ap->name);
+      exit(-1);
+   }
+
+   /* If not hw type specified get default */
+   if (hw_set==0) {
+      if ((hw = get_hwtype(DFLT_HW)) == NULL) {
+         bb_error_msg("%s: hardware type not supported!\n", DFLT_HW);
+         return (-1);
+      }
+   }
+
+   if (hw->alen <= 0) {
+      bb_error_msg("%s: hardware type without ARP support.\n", hw->name);
+      exit(-1);
+   }
+   if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+      perror("socket");
+      return -1;
+   }
+   /* Now see what we have to do here... */
+   switch (what) {
+      case 0:
+         opt_e = 1;
+         what = arp_show(argv[optind]);
+         break;
+
+      case 1:                     /* show an ARP entry in the cache */
+         what = arp_show(argv[optind]);
+         break;
+
+      case 2:                     /* process an EtherFile */
+         what = arp_file(argv[optind] ? argv[optind] : "/etc/ethers");
+         break;
+
+      case 3:                     /* delete an ARP entry from the cache */
+         what = arp_del(&argv[optind]);
+         break;
+
+      case 4:                     /* set an ARP entry in the cache */
+         what = arp_set(&argv[optind]);
+         break;
+
+      default:
+         bb_show_usage();
+   }
+
+   return what;
+}
+
diff -ruN busybox-1.00-pre10/networking/Config.in busybox-1.00-pre10+arp/networking/Config.in
--- busybox-1.00-pre10/networking/Config.in	2004-03-15 03:28:48.000000000 -0500
+++ busybox-1.00-pre10+arp/networking/Config.in	2004-04-26 12:24:12.000000000 -0400
@@ -12,6 +12,12 @@
 	  Enable IPv6 support to busybox. This makes applets that talk IP
 	  able to work with IPv6.
 
+config CONFIG_ARP
+        bool "arp"
+        default n
+        help
+          Manipulate the system ARP cache
+
 config CONFIG_ARPING
 	bool "arping"
 	default n
diff -ruN busybox-1.00-pre10/networking/Makefile.in busybox-1.00-pre10+arp/networking/Makefile.in
--- busybox-1.00-pre10/networking/Makefile.in	2004-04-06 12:56:00.000000000 -0400
+++ busybox-1.00-pre10+arp/networking/Makefile.in	2004-04-26 12:18:13.000000000 -0400
@@ -23,6 +23,7 @@
 endif
 
 NETWORKING-y:=
+NETWORKING-$(CONFIG_ARP)        += arp.o
 NETWORKING-$(CONFIG_ARPING)	+= arping.o
 NETWORKING-$(CONFIG_FTPGET)	+= ftpgetput.o
 NETWORKING-$(CONFIG_FTPPUT)	+= ftpgetput.o


More information about the busybox mailing list