This patch from Bart Visscher <magick@linux-fan.com> adds
IPV6 support to busybox. This patch does the following:
* Add IPv6 support to libbb
* Enable IPv6 interface address display
* Add IPv6 config option
* Adds ping6, an adaptation of the ping applet for IPv6
* Adds support routines for ping6:
- xgethostbyname2
- create_icmp6_socket
* Adds ifconfig support for IPv6
* Add support IPv6 to netstat
* Add IPv6 support to route
Thanks Bart!
diff --git a/networking/ifconfig.c b/networking/ifconfig.c
index 0b834e7..9e87c8b 100644
--- a/networking/ifconfig.c
+++ b/networking/ifconfig.c
@@ -15,7 +15,7 @@
* Foundation; either version 2 of the License, or (at
* your option) any later version.
*
- * $Id: ifconfig.c,v 1.16 2001/11/10 11:22:43 andersen Exp $
+ * $Id: ifconfig.c,v 1.17 2002/07/03 11:46:34 andersen Exp $
*
*/
@@ -27,6 +27,9 @@
* args missing from initial port.
*
* Still missing: media, tunnel.
+ *
+ * 2002-04-20
+ * IPV6 support added by Bart Visscher <magick@linux-fan.com>
*/
#include <stdio.h>
@@ -65,6 +68,14 @@
#define IFF_DYNAMIC 0x8000 /* dialup device with changing addresses */
#endif
+#if CONFIG_FEATURE_IPV6
+struct in6_ifreq {
+ struct in6_addr ifr6_addr;
+ uint32_t ifr6_prefixlen;
+ int ifr6_ifindex;
+};
+#endif
+
/*
* Here are the bit masks for the "flags" member of struct options below.
* N_ signifies no arg prefix; M_ signifies arg prefixed by '-'.
@@ -143,6 +154,7 @@
#define ARG_KEEPALIVE (A_ARG_REQ | A_CAST_CHAR_PTR)
#define ARG_OUTFILL (A_ARG_REQ | A_CAST_CHAR_PTR)
#define ARG_HOSTNAME (A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER | A_COLON_CHK)
+#define ARG_ADD_DEL (A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER)
/*
@@ -187,6 +199,10 @@
{"SIOCSIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.irq)},
#endif
/* Last entry if for unmatched (possibly hostname) arg. */
+#if CONFIG_FEATURE_IPV6
+ {"SIOCSIFADDR", SIOCSIFADDR, ifreq_offsetof(ifr_addr)}, /* IPv6 version ignores the offset */
+ {"SIOCDIFADDR", SIOCDIFADDR, ifreq_offsetof(ifr_addr)}, /* IPv6 version ignores the offset */
+#endif
{"SIOCSIFADDR", SIOCSIFADDR, ifreq_offsetof(ifr_addr)},
};
@@ -212,6 +228,10 @@
{"io_addr", N_ARG, ARG_IO_ADDR, 0},
{"irq", N_ARG, ARG_IRQ, 0},
#endif
+#if CONFIG_FEATURE_IPV6
+ {"add", N_ARG, ARG_ADD_DEL, 0},
+ {"del", N_ARG, ARG_ADD_DEL, 0},
+#endif
{"arp", N_CLR | M_SET, 0, IFF_NOARP},
{"trailers", N_CLR | M_SET, 0, IFF_NOTRAILERS},
{"promisc", N_SET | M_CLR, 0, IFF_PROMISC},
@@ -244,6 +264,9 @@
{
struct ifreq ifr;
struct sockaddr_in sai;
+#if CONFIG_FEATURE_IPV6
+ struct sockaddr_in6 sai6;
+#endif
#ifdef CONFIG_FEATURE_IFCONFIG_HW
struct sockaddr sa;
#endif
@@ -334,12 +357,54 @@
#ifdef CONFIG_FEATURE_IFCONFIG_HW
if (mask & A_CAST_RESOLVE) {
#endif
+#if CONFIG_FEATURE_IPV6
+ char *prefix;
+ int prefix_len=0;
+#endif
+
safe_strncpy(host, *argv, (sizeof host));
+#if CONFIG_FEATURE_IPV6
+ if ((prefix = strchr(host, '/'))) {
+ prefix_len = atol(prefix + 1);
+ if ((prefix_len < 0) || (prefix_len > 128)) {
+ ++goterr;
+ goto LOOP;
+ }
+ *prefix = 0;
+ }
+#endif
+
sai.sin_family = AF_INET;
sai.sin_port = 0;
if (!strcmp(host, bb_INET_default)) {
/* Default is special, meaning 0.0.0.0. */
sai.sin_addr.s_addr = INADDR_ANY;
+#if CONFIG_FEATURE_IPV6
+ } else
+ if (inet_pton(AF_INET6, host, &sai6.sin6_addr) > 0) {
+ int sockfd6;
+ struct in6_ifreq ifr6;
+
+ memcpy((char *) &ifr6.ifr6_addr, (char *) &sai6.sin6_addr,
+ sizeof(struct in6_addr));
+
+ /* Create a channel to the NET kernel. */
+ if ((sockfd6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ perror_msg_and_die("socket6");
+ }
+ if (ioctl(sockfd6, SIOGIFINDEX, &ifr) < 0) {
+ perror("SIOGIFINDEX");
+ ++goterr;
+ continue;
+ }
+ ifr6.ifr6_ifindex = ifr.ifr_ifindex;
+ ifr6.ifr6_prefixlen = prefix_len;
+ if (ioctl(sockfd6, a1op->selector, &ifr6) < 0) {
+ perror(a1op->name);
+ ++goterr;
+ }
+ continue;
+#endif
} else if (inet_aton(host, &sai.sin_addr) == 0) {
/* It's not a dotted quad. */
++goterr;