diff --git a/src/bin/network/Jamfile b/src/bin/network/Jamfile
index 05d170aa61..1f2e1d53a7 100644
--- a/src/bin/network/Jamfile
+++ b/src/bin/network/Jamfile
@@ -15,6 +15,7 @@ SubInclude HAIKU_TOP src bin network netstat ;
#SubInclude HAIKU_TOP src bin network pppconfig ;
#SubInclude HAIKU_TOP src bin network ppp_up ;
SubInclude HAIKU_TOP src bin network ping ;
+SubInclude HAIKU_TOP src bin network ping6 ;
SubInclude HAIKU_TOP src bin network route ;
SubInclude HAIKU_TOP src bin network setwep ;
SubInclude HAIKU_TOP src bin network tcpdump ;
diff --git a/src/bin/network/ifconfig/ifconfig.cpp b/src/bin/network/ifconfig/ifconfig.cpp
index 6ae74eb30b..80a8c53160 100644
--- a/src/bin/network/ifconfig/ifconfig.cpp
+++ b/src/bin/network/ifconfig/ifconfig.cpp
@@ -1,10 +1,11 @@
/*
- * Copyright 2006-2008, Haiku, Inc. All Rights Reserved.
+ * Copyright 2006-2010, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler, axeld@pinc-software.de
* Oliver Tappe, zooey@hirschkaefer.de
+ * Atis Elsts, the.kfx@gmail.com
*/
@@ -33,30 +34,82 @@ extern const char* __progname;
const char* kProgramName = __progname;
+enum preferred_output_format {
+ PREFER_OUTPUT_MASK,
+ PREFER_OUTPUT_PREFIX_LENGTH,
+};
+
+
struct address_family {
int family;
const char* name;
const char* identifiers[4];
+ preferred_output_format preferred_format;
bool (*parse_address)(const char* string, sockaddr* _address);
+ bool (*prefix_length_to_mask)(uint8 prefixLength, sockaddr* mask);
+ uint8 (*mask_to_prefix_length)(sockaddr* mask);
void (*print_address)(sockaddr* address);
};
+
+bool initialize_address_families();
+
// AF_INET family
static bool inet_parse_address(const char* string, sockaddr* address);
+static bool inet_prefix_length_to_mask(uint8 prefixLength, sockaddr* mask);
+static uint8 inet_mask_to_prefix_length(sockaddr* mask);
static void inet_print_address(sockaddr* address);
+// AF_INET6 family
+static bool inet6_parse_address(const char* string, sockaddr* address);
+static bool inet6_prefix_length_to_mask(uint8 prefixLength, sockaddr* mask);
+static uint8 inet6_mask_to_prefix_length(sockaddr* mask);
+static void inet6_print_address(sockaddr* address);
+
static const address_family kFamilies[] = {
{
AF_INET,
"inet",
{"AF_INET", "inet", "ipv4", NULL},
+ PREFER_OUTPUT_MASK,
inet_parse_address,
+ inet_prefix_length_to_mask,
+ inet_mask_to_prefix_length,
inet_print_address
},
- { -1, NULL, {NULL}, NULL, NULL }
+ {
+ AF_INET6,
+ "inet6",
+ {"AF_INET6", "inet6", "ipv6", NULL},
+ PREFER_OUTPUT_PREFIX_LENGTH,
+ inet6_parse_address,
+ inet6_prefix_length_to_mask,
+ inet6_mask_to_prefix_length,
+ inet6_print_address
+ },
+ { -1, NULL, {NULL}, PREFER_OUTPUT_MASK, NULL, NULL, NULL, NULL }
};
+static int sAddressFamilySockets[sizeof(kFamilies) / sizeof(kFamilies[0])];
+
+
+bool
+initialize_address_families()
+{
+ bool ok = false;
+ for (int32 i = 0; kFamilies[i].family >= 0; i++) {
+ int fd = socket(kFamilies[i].family, SOCK_DGRAM, 0);
+ if (fd != -1) {
+ sAddressFamilySockets[i] = fd;
+ ok = true;
+ }
+ }
+ return ok;
+}
+
+
+
static bool
inet_parse_address(const char* string, sockaddr* _address)
{
@@ -65,9 +118,9 @@ inet_parse_address(const char* string, sockaddr* _address)
if (inet_aton(string, &inetAddress) != 1)
return false;
- sockaddr_in& address = *(sockaddr_in *)_address;
+ sockaddr_in& address = *(sockaddr_in*)_address;
address.sin_family = AF_INET;
- address.sin_len = sizeof(struct sockaddr_in);
+ address.sin_len = sizeof(sockaddr_in);
address.sin_port = 0;
address.sin_addr = inetAddress;
memset(&address.sin_zero[0], 0, sizeof(address.sin_zero));
@@ -76,10 +129,50 @@ inet_parse_address(const char* string, sockaddr* _address)
}
+static bool
+inet_prefix_length_to_mask(uint8 prefixLength, sockaddr* _mask)
+{
+ if (prefixLength > 32)
+ return false;
+
+ sockaddr_in& mask = *(sockaddr_in*)_mask;
+ mask.sin_family = AF_INET;
+ mask.sin_len = sizeof(sockaddr_in);
+ mask.sin_port = 0;
+ memset(&mask.sin_zero[0], 0, sizeof(mask.sin_zero));
+
+ uint32 hostMask = 0;
+ for (uint8 i = 32; i > 32 - prefixLength; i--)
+ hostMask |= 1 << (i - 1);
+ mask.sin_addr.s_addr = htonl(hostMask);
+
+ return true;
+}
+
+
+static uint8
+inet_mask_to_prefix_length(sockaddr* _mask)
+{
+ sockaddr_in& mask = *(sockaddr_in*)_mask;
+ if (mask.sin_family != AF_INET)
+ return (uint8)-1;
+
+ uint8 result = 0;
+ uint32 hostMask = ntohl(mask.sin_addr.s_addr);
+ for (uint8 i = 32; i > 0; i--) {
+ if (hostMask & (1 << (i - 1)) == 0)
+ break;
+ result++;
+ }
+
+ return result;
+}
+
+
static void
inet_print_address(sockaddr* _address)
{
- sockaddr_in& address = *(sockaddr_in *)_address;
+ sockaddr_in& address = *(sockaddr_in*)_address;
if (address.sin_family != AF_INET)
return;
@@ -88,6 +181,90 @@ inet_print_address(sockaddr* _address)
}
+static bool
+inet6_parse_address(const char* string, sockaddr* _address)
+{
+ sockaddr_in6& address = *(sockaddr_in6*)_address;
+
+ if (inet_pton(AF_INET6, string, &address.sin6_addr) != 1)
+ return false;
+
+ address.sin6_family = AF_INET6;
+ address.sin6_len = sizeof(sockaddr_in6);
+ address.sin6_port = 0;
+ address.sin6_flowinfo = 0;
+ address.sin6_scope_id = 0;
+
+ return true;
+}
+
+
+static bool
+inet6_prefix_length_to_mask(uint8 prefixLength, sockaddr* _mask)
+{
+ if (prefixLength > 128)
+ return false;
+
+ sockaddr_in6& mask = *(sockaddr_in6*)_mask;
+ mask.sin6_family = AF_INET6;
+ mask.sin6_len = sizeof(sockaddr_in6);
+ mask.sin6_port = 0;
+ mask.sin6_flowinfo = 0;
+ mask.sin6_scope_id = 0;
+ memset(mask.sin6_addr.s6_addr, 0, sizeof(in6_addr));
+
+ for (uint8 i = 0; i < sizeof(in6_addr); i++, prefixLength -= 8) {
+ if (prefixLength < 8) {
+ const uint8 masks[] = {
+ 0x00, 0x80, 0xc0, 0xe0,
+ 0xf0, 0xf8, 0xfc, 0xfe
+ };
+ mask.sin6_addr.s6_addr[i] = masks[prefixLength];
+ break;
+ }
+
+ mask.sin6_addr.s6_addr[i] = 0xff;
+ }
+
+ return true;
+}
+
+
+static uint8
+inet6_mask_to_prefix_length(sockaddr* _mask)
+{
+ sockaddr_in6& mask = *(sockaddr_in6*)_mask;
+ if (mask.sin6_family != AF_INET6)
+ return (uint8)~0;
+
+ uint8 result = 0;
+ for (uint8 i = 0; i < sizeof(in6_addr); i++) {
+ for (uint8 j = 0; j < 8; j++) {
+ if (!(mask.sin6_addr.s6_addr[i] & (1 << j)))
+ return result;
+ result++;
+ }
+ }
+
+ return 128;
+}
+
+
+static void
+inet6_print_address(sockaddr* _address)
+{
+ sockaddr_in6& address = *(sockaddr_in6*)_address;
+
+ if (address.sin6_family != AF_INET6)
+ return;
+
+ char buffer[INET6_ADDRSTRLEN];
+
+ printf("%s",
+ inet_ntop(AF_INET6, &address.sin6_addr, buffer, sizeof(buffer)));
+}
+
+
// #pragma mark -
@@ -181,12 +358,13 @@ usage(int status)
"auto-config] [