Work in progress commit by Atis Elsts (I'm posting his ChangeLog comments
directly here), I made only a few style changes: * introduced 'has_broadcast_address' field in struct net_address_module_info - REVIEW: the name, and the status of this field for UNIX and L2CAP families * ipv6 address family support * ipv6 address printing * ipv6 protocol support * ipv6 multicast support - TODO: add and remove multicast routes in a more proper way - TODO: support MLD * ipv6 datalink protocol support * icmpv6 protocol support (EchoRequest and EchoResponse messages) * ipv6 neigbor discovery protocol support (Advertisement and Solicitation messages) - TODO: only the very basic support is present, the protocol state machine is by no means completed - TODO: replying to Solicitation does not work too good ATM (visible, when pinging Haiku from outside) * added Jenkin's hash algorith * minor changes in existing IPv4 code - cleanup function ipv4_get_loopback_address(), written by myself * add tests: raw, udp, tcp/udp, mullicast sender * add 'hoplimit' field in struct net_buffer - TODO: this is just a hack, more generic approach would be better. * add 'receive_data' function pointer in struct net_datalink_protocol_module_info - TODO: this is also more like a hack, to support information passing from ICMPv6 to IPv6_datagram level. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@37604 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -36,6 +36,7 @@ typedef struct net_buffer {
|
|||||||
uint32 flags;
|
uint32 flags;
|
||||||
uint32 size;
|
uint32 size;
|
||||||
uint8 protocol;
|
uint8 protocol;
|
||||||
|
uint8 hoplimit;
|
||||||
} net_buffer;
|
} net_buffer;
|
||||||
|
|
||||||
struct ancillary_data_container;
|
struct ancillary_data_container;
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ struct net_datalink_module_info {
|
|||||||
|
|
||||||
struct net_address_module_info {
|
struct net_address_module_info {
|
||||||
module_info info;
|
module_info info;
|
||||||
|
bool has_broadcast_address;
|
||||||
|
|
||||||
status_t (*copy_address)(const sockaddr *from, sockaddr **to,
|
status_t (*copy_address)(const sockaddr *from, sockaddr **to,
|
||||||
bool replaceWithZeros, const sockaddr *mask);
|
bool replaceWithZeros, const sockaddr *mask);
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ struct net_datalink_protocol_module_info {
|
|||||||
|
|
||||||
status_t (*send_data)(net_datalink_protocol *self,
|
status_t (*send_data)(net_datalink_protocol *self,
|
||||||
net_buffer *buffer);
|
net_buffer *buffer);
|
||||||
|
status_t (*receive_data)(net_buffer *buffer);
|
||||||
|
|
||||||
status_t (*interface_up)(net_datalink_protocol *self);
|
status_t (*interface_up)(net_datalink_protocol *self);
|
||||||
void (*interface_down)(net_datalink_protocol *self);
|
void (*interface_down)(net_datalink_protocol *self);
|
||||||
|
|||||||
@@ -3,4 +3,5 @@ SubDir HAIKU_TOP src add-ons kernel network datalink_protocols ;
|
|||||||
SubInclude HAIKU_TOP src add-ons kernel network datalink_protocols arp ;
|
SubInclude HAIKU_TOP src add-ons kernel network datalink_protocols arp ;
|
||||||
SubInclude HAIKU_TOP src add-ons kernel network datalink_protocols ethernet_frame ;
|
SubInclude HAIKU_TOP src add-ons kernel network datalink_protocols ethernet_frame ;
|
||||||
SubInclude HAIKU_TOP src add-ons kernel network datalink_protocols ipv4_datagram ;
|
SubInclude HAIKU_TOP src add-ons kernel network datalink_protocols ipv4_datagram ;
|
||||||
|
SubInclude HAIKU_TOP src add-ons kernel network datalink_protocols ipv6_datagram ;
|
||||||
SubInclude HAIKU_TOP src add-ons kernel network datalink_protocols loopback_frame ;
|
SubInclude HAIKU_TOP src add-ons kernel network datalink_protocols loopback_frame ;
|
||||||
|
|||||||
@@ -1095,6 +1095,7 @@ static net_datalink_protocol_module_info sARPModule = {
|
|||||||
arp_init_protocol,
|
arp_init_protocol,
|
||||||
arp_uninit_protocol,
|
arp_uninit_protocol,
|
||||||
arp_send_data,
|
arp_send_data,
|
||||||
|
NULL, // receive_data
|
||||||
arp_up,
|
arp_up,
|
||||||
arp_down,
|
arp_down,
|
||||||
arp_control,
|
arp_control,
|
||||||
|
|||||||
@@ -210,6 +210,7 @@ static net_datalink_protocol_module_info sEthernetFrameModule = {
|
|||||||
ethernet_frame_init,
|
ethernet_frame_init,
|
||||||
ethernet_frame_uninit,
|
ethernet_frame_uninit,
|
||||||
ethernet_frame_send_data,
|
ethernet_frame_send_data,
|
||||||
|
NULL, // receive_data
|
||||||
ethernet_frame_up,
|
ethernet_frame_up,
|
||||||
ethernet_frame_down,
|
ethernet_frame_down,
|
||||||
ethernet_frame_control,
|
ethernet_frame_control,
|
||||||
|
|||||||
@@ -136,6 +136,7 @@ net_datalink_protocol_module_info gIPv4DataLinkModule = {
|
|||||||
ipv4_datalink_init,
|
ipv4_datalink_init,
|
||||||
ipv4_datalink_uninit,
|
ipv4_datalink_uninit,
|
||||||
ipv4_datalink_send_data,
|
ipv4_datalink_send_data,
|
||||||
|
NULL, // receive_data
|
||||||
ipv4_datalink_up,
|
ipv4_datalink_up,
|
||||||
ipv4_datalink_down,
|
ipv4_datalink_down,
|
||||||
ipv4_datalink_control,
|
ipv4_datalink_control,
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
SubDir HAIKU_TOP src add-ons kernel network datalink_protocols ipv6_datagram ;
|
||||||
|
|
||||||
|
SetSubDirSupportedPlatformsBeOSCompatible ;
|
||||||
|
|
||||||
|
if $(TARGET_PLATFORM) != haiku {
|
||||||
|
UseHeaders [ FStandardOSHeaders ] : true ;
|
||||||
|
# Needed for <support/Errors.h> and maybe other stuff.
|
||||||
|
UseHeaders [ FDirName $(HAIKU_TOP) headers posix ] : true ;
|
||||||
|
# We need the public network headers also when not compiling for Haiku.
|
||||||
|
# Unfortunately we get more than we want, namely all POSIX headers.
|
||||||
|
}
|
||||||
|
|
||||||
|
UsePrivateKernelHeaders ;
|
||||||
|
UsePrivateHeaders kernel net ;
|
||||||
|
|
||||||
|
KernelAddon ipv6_datagram :
|
||||||
|
ipv6_datagram.cpp
|
||||||
|
;
|
||||||
|
|
||||||
|
# Installation
|
||||||
|
HaikuInstall install-networking : /boot/home/config/add-ons/kernel/haiku_network/datalink_protocols
|
||||||
|
: ipv6_datagram ;
|
||||||
|
|
||||||
|
Package haiku-networkingkit-cvs :
|
||||||
|
haiku :
|
||||||
|
boot home config add-ons kernel haiku_network datalink_protocols ;
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -171,6 +171,7 @@ static net_datalink_protocol_module_info sLoopbackFrameModule = {
|
|||||||
loopback_frame_init,
|
loopback_frame_init,
|
||||||
loopback_frame_uninit,
|
loopback_frame_uninit,
|
||||||
loopback_frame_send_data,
|
loopback_frame_send_data,
|
||||||
|
NULL, // receive_data
|
||||||
loopback_frame_up,
|
loopback_frame_up,
|
||||||
loopback_frame_down,
|
loopback_frame_down,
|
||||||
loopback_frame_control,
|
loopback_frame_control,
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
SubDir HAIKU_TOP src add-ons kernel network protocols ;
|
SubDir HAIKU_TOP src add-ons kernel network protocols ;
|
||||||
|
|
||||||
SubInclude HAIKU_TOP src add-ons kernel network protocols icmp ;
|
SubInclude HAIKU_TOP src add-ons kernel network protocols icmp ;
|
||||||
|
SubInclude HAIKU_TOP src add-ons kernel network protocols icmp6 ;
|
||||||
SubInclude HAIKU_TOP src add-ons kernel network protocols ipv4 ;
|
SubInclude HAIKU_TOP src add-ons kernel network protocols ipv4 ;
|
||||||
|
SubInclude HAIKU_TOP src add-ons kernel network protocols ipv6 ;
|
||||||
SubInclude HAIKU_TOP src add-ons kernel network protocols l2cap ;
|
SubInclude HAIKU_TOP src add-ons kernel network protocols l2cap ;
|
||||||
SubInclude HAIKU_TOP src add-ons kernel network protocols tcp ;
|
SubInclude HAIKU_TOP src add-ons kernel network protocols tcp ;
|
||||||
SubInclude HAIKU_TOP src add-ons kernel network protocols udp ;
|
SubInclude HAIKU_TOP src add-ons kernel network protocols udp ;
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
SubDir HAIKU_TOP src add-ons kernel network protocols icmp6 ;
|
||||||
|
|
||||||
|
SetSubDirSupportedPlatformsBeOSCompatible ;
|
||||||
|
|
||||||
|
if $(TARGET_PLATFORM) != haiku {
|
||||||
|
UseHeaders [ FStandardOSHeaders ] : true ;
|
||||||
|
# Needed for <support/Errors.h> and maybe other stuff.
|
||||||
|
UseHeaders [ FDirName $(HAIKU_TOP) headers posix ] : true ;
|
||||||
|
# We need the public network headers also when not compiling for Haiku.
|
||||||
|
# Unfortunately we get more than we want, namely all POSIX headers.
|
||||||
|
}
|
||||||
|
|
||||||
|
UsePrivateHeaders kernel net ;
|
||||||
|
|
||||||
|
KernelAddon icmp6 :
|
||||||
|
icmp6.cpp
|
||||||
|
;
|
||||||
|
|
||||||
|
# Installation
|
||||||
|
HaikuInstall install-networking : /boot/home/config/add-ons/kernel/haiku_network/protocols
|
||||||
|
: icmp6 ;
|
||||||
|
|
||||||
|
Package haiku-networkingkit-cvs :
|
||||||
|
haiku :
|
||||||
|
boot home config add-ons kernel haiku_network protocols ;
|
||||||
@@ -0,0 +1,394 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2006-2010, Haiku, Inc. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <net_datalink.h>
|
||||||
|
#include <net_protocol.h>
|
||||||
|
#include <net_stack.h>
|
||||||
|
#include <net_datalink_protocol.h>
|
||||||
|
#include <NetBufferUtilities.h>
|
||||||
|
|
||||||
|
#include <KernelExport.h>
|
||||||
|
#include <util/list.h>
|
||||||
|
|
||||||
|
#include <netinet/icmp6.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <new>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "../ipv6/ipv6_utils.h" // ipv6_checksum()
|
||||||
|
|
||||||
|
|
||||||
|
#define TRACE_ICMP6
|
||||||
|
#ifdef TRACE_ICMP6
|
||||||
|
# define TRACE(x) dprintf x
|
||||||
|
#else
|
||||||
|
# define TRACE(x) ;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
typedef NetBufferField<uint16, offsetof(icmp6_hdr, icmp6_cksum)> ICMP6ChecksumField;
|
||||||
|
|
||||||
|
|
||||||
|
net_buffer_module_info *gBufferModule;
|
||||||
|
static net_stack_module_info *sStackModule;
|
||||||
|
static net_datalink_protocol_module_info *sIPv6DatalinkModule;
|
||||||
|
|
||||||
|
|
||||||
|
net_protocol *
|
||||||
|
icmp6_init_protocol(net_socket *socket)
|
||||||
|
{
|
||||||
|
net_protocol *protocol = new (std::nothrow) net_protocol;
|
||||||
|
if (protocol == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return protocol;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
icmp6_uninit_protocol(net_protocol *protocol)
|
||||||
|
{
|
||||||
|
delete protocol;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
icmp6_open(net_protocol *protocol)
|
||||||
|
{
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
icmp6_close(net_protocol *protocol)
|
||||||
|
{
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
icmp6_free(net_protocol *protocol)
|
||||||
|
{
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
icmp6_connect(net_protocol *protocol, const struct sockaddr *address)
|
||||||
|
{
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
icmp6_accept(net_protocol *protocol, struct net_socket **_acceptedSocket)
|
||||||
|
{
|
||||||
|
return EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
icmp6_control(net_protocol *protocol, int level, int option, void *value,
|
||||||
|
size_t *_length)
|
||||||
|
{
|
||||||
|
return protocol->next->module->control(protocol->next, level, option,
|
||||||
|
value, _length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
icmp6_getsockopt(net_protocol *protocol, int level, int option,
|
||||||
|
void *value, int *length)
|
||||||
|
{
|
||||||
|
return protocol->next->module->getsockopt(protocol->next, level, option,
|
||||||
|
value, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
icmp6_setsockopt(net_protocol *protocol, int level, int option,
|
||||||
|
const void *value, int length)
|
||||||
|
{
|
||||||
|
return protocol->next->module->setsockopt(protocol->next, level, option,
|
||||||
|
value, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
icmp6_bind(net_protocol *protocol, const struct sockaddr *address)
|
||||||
|
{
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
icmp6_unbind(net_protocol *protocol, struct sockaddr *address)
|
||||||
|
{
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
icmp6_listen(net_protocol *protocol, int count)
|
||||||
|
{
|
||||||
|
return EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
icmp6_shutdown(net_protocol *protocol, int direction)
|
||||||
|
{
|
||||||
|
return EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
icmp6_send_data(net_protocol *protocol, net_buffer *buffer)
|
||||||
|
{
|
||||||
|
return protocol->next->module->send_data(protocol->next, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
icmp6_send_routed_data(net_protocol *protocol, struct net_route *route,
|
||||||
|
net_buffer *buffer)
|
||||||
|
{
|
||||||
|
return protocol->next->module->send_routed_data(protocol->next, route, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
icmp6_send_avail(net_protocol *protocol)
|
||||||
|
{
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
icmp6_read_data(net_protocol *protocol, size_t numBytes, uint32 flags,
|
||||||
|
net_buffer **_buffer)
|
||||||
|
{
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
icmp6_read_avail(net_protocol *protocol)
|
||||||
|
{
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct net_domain *
|
||||||
|
icmp6_get_domain(net_protocol *protocol)
|
||||||
|
{
|
||||||
|
return protocol->next->module->get_domain(protocol->next);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t
|
||||||
|
icmp6_get_mtu(net_protocol *protocol, const struct sockaddr *address)
|
||||||
|
{
|
||||||
|
return protocol->next->module->get_mtu(protocol->next, address);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
icmp6_receive_data(net_buffer *buffer)
|
||||||
|
{
|
||||||
|
TRACE(("ICMPv6 received some data, buffer length %lu\n", buffer->size));
|
||||||
|
|
||||||
|
NetBufferHeaderReader<icmp6_hdr> bufferHeader(buffer);
|
||||||
|
if (bufferHeader.Status() < B_OK)
|
||||||
|
return bufferHeader.Status();
|
||||||
|
|
||||||
|
icmp6_hdr &header = bufferHeader.Data();
|
||||||
|
|
||||||
|
TRACE((" got type %u, code %u, checksum 0x%x\n", header.icmp6_type,
|
||||||
|
header.icmp6_code, header.icmp6_cksum));
|
||||||
|
|
||||||
|
// compute and check the checksum
|
||||||
|
uint16 checksum;
|
||||||
|
checksum = gBufferModule->checksum(buffer, 0, buffer->size, false);
|
||||||
|
checksum = ipv6_checksum(&((sockaddr_in6*)buffer->source)->sin6_addr,
|
||||||
|
&((sockaddr_in6*)buffer->destination)->sin6_addr,
|
||||||
|
buffer->size, IPPROTO_ICMPV6, checksum);
|
||||||
|
|
||||||
|
TRACE((" computed checksum: %ld\n", checksum));
|
||||||
|
|
||||||
|
if (checksum != 0)
|
||||||
|
return B_BAD_DATA;
|
||||||
|
|
||||||
|
switch (header.icmp6_type) {
|
||||||
|
case ICMP6_ECHO_REPLY:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ICMP6_ECHO_REQUEST:
|
||||||
|
{
|
||||||
|
net_domain *domain;
|
||||||
|
if (buffer->interface != NULL) {
|
||||||
|
domain = buffer->interface->domain;
|
||||||
|
|
||||||
|
// We only reply to echo requests of our local interface; we
|
||||||
|
// don't reply to broadcast requests
|
||||||
|
if (!domain->address_module->equal_addresses(
|
||||||
|
buffer->interface->address, buffer->destination))
|
||||||
|
break;
|
||||||
|
} else
|
||||||
|
domain = sStackModule->get_domain(buffer->source->sa_family);
|
||||||
|
|
||||||
|
if (domain == NULL || domain->module == NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
net_buffer *reply = gBufferModule->duplicate(buffer);
|
||||||
|
if (reply == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
gBufferModule->swap_addresses(reply);
|
||||||
|
|
||||||
|
// There already is an ICMP header, and we'll reuse it
|
||||||
|
NetBufferHeaderReader<icmp6_hdr> header(reply);
|
||||||
|
|
||||||
|
header->icmp6_type = ICMP6_ECHO_REPLY;
|
||||||
|
header->icmp6_code = 0;
|
||||||
|
header->icmp6_cksum = 0;
|
||||||
|
|
||||||
|
header.Sync();
|
||||||
|
|
||||||
|
checksum = gBufferModule->checksum(buffer, 0, buffer->size, false);
|
||||||
|
*ICMP6ChecksumField(reply) =
|
||||||
|
ipv6_checksum(&((sockaddr_in6*)buffer->source)->sin6_addr,
|
||||||
|
&((sockaddr_in6*)buffer->destination)->sin6_addr,
|
||||||
|
buffer->size, IPPROTO_ICMPV6, checksum);
|
||||||
|
|
||||||
|
status_t status = domain->module->send_data(NULL, reply);
|
||||||
|
if (status < B_OK) {
|
||||||
|
gBufferModule->free(reply);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
// forward unrecognized messages to datalink layer
|
||||||
|
return sIPv6DatalinkModule->receive_data(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
gBufferModule->free(buffer);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
icmp6_deliver_data(net_protocol *protocol, net_buffer *buffer)
|
||||||
|
{
|
||||||
|
// TODO: does this look OK?
|
||||||
|
return icmp6_receive_data(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
icmp6_error(uint32 code, net_buffer *data)
|
||||||
|
{
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
icmp6_error_reply(net_protocol *protocol, net_buffer *causedError, uint32 code,
|
||||||
|
void *errorData)
|
||||||
|
{
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
icmp6_init()
|
||||||
|
{
|
||||||
|
sStackModule->register_domain_protocols(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6,
|
||||||
|
"network/protocols/icmp6/v1",
|
||||||
|
"network/protocols/ipv6/v1",
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
sStackModule->register_domain_receiving_protocol(AF_INET6, IPPROTO_ICMPV6,
|
||||||
|
"network/protocols/icmp6/v1");
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
icmp6_std_ops(int32 op, ...)
|
||||||
|
{
|
||||||
|
switch (op) {
|
||||||
|
case B_MODULE_INIT:
|
||||||
|
return icmp6_init();
|
||||||
|
|
||||||
|
case B_MODULE_UNINIT:
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
net_protocol_module_info sICMP6Module = {
|
||||||
|
{
|
||||||
|
"network/protocols/icmp6/v1",
|
||||||
|
0,
|
||||||
|
icmp6_std_ops
|
||||||
|
},
|
||||||
|
NET_PROTOCOL_ATOMIC_MESSAGES,
|
||||||
|
|
||||||
|
icmp6_init_protocol,
|
||||||
|
icmp6_uninit_protocol,
|
||||||
|
icmp6_open,
|
||||||
|
icmp6_close,
|
||||||
|
icmp6_free,
|
||||||
|
icmp6_connect,
|
||||||
|
icmp6_accept,
|
||||||
|
icmp6_control,
|
||||||
|
icmp6_getsockopt,
|
||||||
|
icmp6_setsockopt,
|
||||||
|
icmp6_bind,
|
||||||
|
icmp6_unbind,
|
||||||
|
icmp6_listen,
|
||||||
|
icmp6_shutdown,
|
||||||
|
icmp6_send_data,
|
||||||
|
icmp6_send_routed_data,
|
||||||
|
icmp6_send_avail,
|
||||||
|
icmp6_read_data,
|
||||||
|
icmp6_read_avail,
|
||||||
|
icmp6_get_domain,
|
||||||
|
icmp6_get_mtu,
|
||||||
|
icmp6_receive_data,
|
||||||
|
icmp6_deliver_data,
|
||||||
|
icmp6_error,
|
||||||
|
icmp6_error_reply,
|
||||||
|
NULL, // add_ancillary_data()
|
||||||
|
NULL, // process_ancillary_data()
|
||||||
|
NULL, // process_ancillary_data_no_container()
|
||||||
|
NULL, // send_data_no_buffer()
|
||||||
|
NULL // read_data_no_buffer()
|
||||||
|
};
|
||||||
|
|
||||||
|
module_dependency module_dependencies[] = {
|
||||||
|
{NET_STACK_MODULE_NAME, (module_info **)&sStackModule},
|
||||||
|
{NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule},
|
||||||
|
{"network/datalink_protocols/ipv6_datagram/v1",
|
||||||
|
(module_info **)&sIPv6DatalinkModule},
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
module_info *modules[] = {
|
||||||
|
(module_info *)&sICMP6Module,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
@@ -1595,6 +1595,7 @@ ipv4_receive_data(net_buffer* buffer)
|
|||||||
memcpy(buffer->destination, &destination, sizeof(sockaddr_in));
|
memcpy(buffer->destination, &destination, sizeof(sockaddr_in));
|
||||||
|
|
||||||
uint8 protocol = buffer->protocol = header.protocol;
|
uint8 protocol = buffer->protocol = header.protocol;
|
||||||
|
buffer->hoplimit = header.time_to_live;
|
||||||
|
|
||||||
// remove any trailing/padding data
|
// remove any trailing/padding data
|
||||||
status_t status = gBufferModule->trim(buffer, packetLength);
|
status_t status = gBufferModule->trim(buffer, packetLength);
|
||||||
|
|||||||
@@ -489,14 +489,15 @@ ipv4_checksum_address(struct Checksum *checksum, const sockaddr *address)
|
|||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ipv4_get_loopback_address(sockaddr *result)
|
ipv4_get_loopback_address(sockaddr *_address)
|
||||||
{
|
{
|
||||||
sockaddr_in *resultIn = (sockaddr_in *)result;
|
sockaddr_in *address = (sockaddr_in *)_address;
|
||||||
memset(resultIn, 0, sizeof(resultIn));
|
memset(address, 0, sizeof(sockaddr_in));
|
||||||
resultIn->sin_len = sizeof(sockaddr_in);
|
address->sin_len = sizeof(sockaddr_in);
|
||||||
resultIn->sin_family = AF_INET;
|
address->sin_family = AF_INET;
|
||||||
resultIn->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
address->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -506,6 +507,7 @@ net_address_module_info gIPv4AddressModule = {
|
|||||||
0,
|
0,
|
||||||
NULL
|
NULL
|
||||||
},
|
},
|
||||||
|
true, // has_broadcast_address
|
||||||
ipv4_copy_address,
|
ipv4_copy_address,
|
||||||
ipv4_mask_address,
|
ipv4_mask_address,
|
||||||
ipv4_equal_addresses,
|
ipv4_equal_addresses,
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
SubDir HAIKU_TOP src add-ons kernel network protocols ipv6 ;
|
||||||
|
|
||||||
|
SetSubDirSupportedPlatformsBeOSCompatible ;
|
||||||
|
|
||||||
|
if $(TARGET_PLATFORM) != haiku {
|
||||||
|
UseHeaders [ FStandardOSHeaders ] : true ;
|
||||||
|
# Needed for <support/Errors.h> and maybe other stuff.
|
||||||
|
UseHeaders [ FDirName $(HAIKU_TOP) headers posix ] : true ;
|
||||||
|
# We need the public network headers also when not compiling for Haiku.
|
||||||
|
# Unfortunately we get more than we want, namely all POSIX headers.
|
||||||
|
}
|
||||||
|
|
||||||
|
UsePrivateKernelHeaders ;
|
||||||
|
UsePrivateHeaders net ;
|
||||||
|
|
||||||
|
KernelAddon ipv6 :
|
||||||
|
ipv6.cpp
|
||||||
|
ipv6_address.cpp
|
||||||
|
ipv6_utils.cpp
|
||||||
|
multicast.cpp
|
||||||
|
;
|
||||||
|
|
||||||
|
# Installation
|
||||||
|
HaikuInstall install-networking : /boot/home/config/add-ons/kernel/haiku_network/protocols
|
||||||
|
: ipv6 ;
|
||||||
|
|
||||||
|
Package haiku-networkingkit-cvs :
|
||||||
|
haiku :
|
||||||
|
boot home config add-ons kernel haiku_network protocols ;
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,569 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2006-2009, 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <net_datalink.h>
|
||||||
|
|
||||||
|
#include <NetUtilities.h>
|
||||||
|
|
||||||
|
#include <memory.h>
|
||||||
|
#include <netinet6/in6.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "ipv6_address.h"
|
||||||
|
#include "ipv6_utils.h"
|
||||||
|
#include "jenkins.h"
|
||||||
|
|
||||||
|
|
||||||
|
const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
|
||||||
|
const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
ipv6_mask_adress_inplace(sockaddr *address, const sockaddr *mask)
|
||||||
|
{
|
||||||
|
in6_addr &i6addr = ((sockaddr_in6 *)address)->sin6_addr;
|
||||||
|
const in6_addr &i6mask = ((const sockaddr_in6 *)mask)->sin6_addr;
|
||||||
|
|
||||||
|
for (uint32 i = 0; i < sizeof(in6_addr); i++)
|
||||||
|
i6addr.s6_addr[i] &= i6mask.s6_addr[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! Routing utility function: copies address \a from into a new address
|
||||||
|
that is put into \a to.
|
||||||
|
If \a replaceWithZeros is set \a from will be replaced by an empty
|
||||||
|
address.
|
||||||
|
If a \a mask is given it is applied to \a from (such that \a to is the
|
||||||
|
result of \a from & \a mask).
|
||||||
|
\return B_OK if the address could be copied
|
||||||
|
\return B_NO_MEMORY if the new address could not be allocated
|
||||||
|
\return B_BAD_VALUE if any of \a from or \a mask refers to an uninitialized
|
||||||
|
address
|
||||||
|
\return B_MISMATCHED_VALUES if \a address does not match family AF_INET
|
||||||
|
*/
|
||||||
|
static status_t
|
||||||
|
ipv6_copy_address(const sockaddr *from, sockaddr **to,
|
||||||
|
bool replaceWithZeros = false, const sockaddr *mask = NULL)
|
||||||
|
{
|
||||||
|
if (replaceWithZeros) {
|
||||||
|
*to = (sockaddr *)malloc(sizeof(sockaddr_in6));
|
||||||
|
if (*to == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
memset(*to, 0, sizeof(sockaddr_in6));
|
||||||
|
(*to)->sa_family = AF_INET6;
|
||||||
|
(*to)->sa_len = sizeof(sockaddr_in6);
|
||||||
|
} else {
|
||||||
|
if (from == NULL)
|
||||||
|
return B_OK;
|
||||||
|
if (from->sa_len == 0 || (mask != NULL && mask->sa_len == 0))
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
if (from->sa_family != AF_INET6)
|
||||||
|
return B_MISMATCHED_VALUES;
|
||||||
|
|
||||||
|
*to = (sockaddr *)malloc(sizeof(sockaddr_in6));
|
||||||
|
if (*to == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
memcpy(*to, from, sizeof(sockaddr_in6));
|
||||||
|
|
||||||
|
if (mask != NULL)
|
||||||
|
ipv6_mask_adress_inplace(*to, mask);
|
||||||
|
}
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! Routing utility function: applies \a mask to given \a address and puts
|
||||||
|
the resulting address into \a result.
|
||||||
|
\return B_OK if the mask has been applied
|
||||||
|
\return B_BAD_VALUE if \a address is NULL or if any of \a address or \a mask
|
||||||
|
refers to an uninitialized address
|
||||||
|
*/
|
||||||
|
static status_t
|
||||||
|
ipv6_mask_address(const sockaddr *address, const sockaddr *mask,
|
||||||
|
sockaddr *result)
|
||||||
|
{
|
||||||
|
if (address == NULL || address->sa_len == 0 || result == NULL
|
||||||
|
|| (mask != NULL && mask->sa_len == 0))
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
memcpy(result, address, sizeof(sockaddr_in6));
|
||||||
|
if (mask != NULL)
|
||||||
|
ipv6_mask_adress_inplace(result, mask);
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! Checks if the given \a address is the empty address. By default, the port
|
||||||
|
is checked, too, but you can avoid that by passing \a checkPort = false.
|
||||||
|
\return true if \a address is NULL, uninitialized or the empty address,
|
||||||
|
false if not
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
ipv6_is_empty_address(const sockaddr *_address, bool checkPort)
|
||||||
|
{
|
||||||
|
if (_address == NULL || _address->sa_len == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
const sockaddr_in6 *address = (const sockaddr_in6 *)_address;
|
||||||
|
if (checkPort && address->sin6_port != 0) return false;
|
||||||
|
return IN6_IS_ADDR_UNSPECIFIED(&address->sin6_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! Checks if the given \a address is an Ipv6 address.
|
||||||
|
\return false if \a address is NULL, or with family different from AF_INET
|
||||||
|
true if it has AF_INET address family
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
ipv6_is_same_family(const sockaddr *address)
|
||||||
|
{
|
||||||
|
if (address == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return address->sa_family == AF_INET6;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! Compares the IP-addresses of the two given address structures \a a and \a b.
|
||||||
|
\return true if IP-addresses of \a a and \a b are equal, false if not
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
ipv6_equal_addresses(const sockaddr *a, const sockaddr *b)
|
||||||
|
{
|
||||||
|
if (a == NULL && b == NULL)
|
||||||
|
return true;
|
||||||
|
if (a != NULL && b == NULL)
|
||||||
|
return ipv6_is_empty_address(a, false);
|
||||||
|
if (a == NULL && b != NULL)
|
||||||
|
return ipv6_is_empty_address(b, false);
|
||||||
|
|
||||||
|
const sockaddr_in6 *i6a = (const sockaddr_in6 *)a;
|
||||||
|
const sockaddr_in6 *i6b = (const sockaddr_in6 *)b;
|
||||||
|
return !memcmp(&i6a->sin6_addr, &i6b->sin6_addr, sizeof(in6_addr));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! Compares the ports of the two given address structures \a a and \a b.
|
||||||
|
\return true if ports of \a a and \a b are equal, false if not
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
ipv6_equal_ports(const sockaddr *a, const sockaddr *b)
|
||||||
|
{
|
||||||
|
uint16 portA = a ? ((sockaddr_in6 *)a)->sin6_port : 0;
|
||||||
|
uint16 portB = b ? ((sockaddr_in6 *)b)->sin6_port : 0;
|
||||||
|
return portA == portB;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! Compares the IP-addresses and ports of the two given address structures
|
||||||
|
\a a and \a b.
|
||||||
|
\return true if IP-addresses and ports of \a a and \a b are equal, false if
|
||||||
|
not
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
ipv6_equal_addresses_and_ports(const sockaddr *a, const sockaddr *b)
|
||||||
|
{
|
||||||
|
if (a == NULL && b == NULL)
|
||||||
|
return true;
|
||||||
|
if (a != NULL && b == NULL)
|
||||||
|
return ipv6_is_empty_address(a, true);
|
||||||
|
if (a == NULL && b != NULL)
|
||||||
|
return ipv6_is_empty_address(b, true);
|
||||||
|
|
||||||
|
const sockaddr_in6 *i6a = (const sockaddr_in6 *)a;
|
||||||
|
const sockaddr_in6 *i6b = (const sockaddr_in6 *)b;
|
||||||
|
return i6a->sin6_port == i6b->sin6_port
|
||||||
|
&& !memcmp(&i6a->sin6_addr, &i6b->sin6_addr, sizeof(in6_addr));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! Applies the given \a mask two \a a and \a b and then checks whether
|
||||||
|
the masked addresses match.
|
||||||
|
\return true if \a a matches \a b after masking both, false if not
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
ipv6_equal_masked_addresses(const sockaddr *a, const sockaddr *b,
|
||||||
|
const sockaddr *mask)
|
||||||
|
{
|
||||||
|
if (a == NULL && b == NULL)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
const in6_addr *i6a;
|
||||||
|
if (a == NULL)
|
||||||
|
i6a = &in6addr_any;
|
||||||
|
else
|
||||||
|
i6a = &((const sockaddr_in6*)a)->sin6_addr;
|
||||||
|
|
||||||
|
const in6_addr *i6b;
|
||||||
|
if (b == NULL)
|
||||||
|
i6b = &in6addr_any;
|
||||||
|
else
|
||||||
|
i6b = &((const sockaddr_in6*)b)->sin6_addr;
|
||||||
|
|
||||||
|
if (!mask)
|
||||||
|
return !memcmp(i6a, i6b, sizeof(in6_addr));
|
||||||
|
|
||||||
|
const uint8 *pmask = ((const sockaddr_in6 *)mask)->sin6_addr.s6_addr;
|
||||||
|
for (uint8 i = 0; i < sizeof(in6_addr); ++i) {
|
||||||
|
if (pmask[i] != 0xff) {
|
||||||
|
return (i6a->s6_addr[i] & pmask[i])
|
||||||
|
== (i6b->s6_addr[i] & pmask[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i6a->s6_addr[i] != i6b->s6_addr[i])
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! Routing utility function: determines the least significant bit that is set
|
||||||
|
in the given \a mask.
|
||||||
|
\return the number of the first bit that is set (0-32, where 32 means
|
||||||
|
that there's no bit set in the mask).
|
||||||
|
*/
|
||||||
|
static int32
|
||||||
|
ipv6_first_mask_bit(const sockaddr *_mask)
|
||||||
|
{
|
||||||
|
if (_mask == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
const uint8 *pmask = ((const sockaddr_in6 *)_mask)->sin6_addr.s6_addr;
|
||||||
|
for (uint8 i = 0; i < sizeof(in6_addr); ++i) {
|
||||||
|
if (pmask[i] == 0xff)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (uint8 bit = 0; bit < 8; bit++) {
|
||||||
|
if (pmask[i] & (1 << bit))
|
||||||
|
return bit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 128;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! Routing utility function: checks the given \a mask for correctness (which
|
||||||
|
means that (starting with LSB) consists zero or more unset bits, followed
|
||||||
|
by bits that are all set).
|
||||||
|
\return true if \a mask is ok, false if not
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
ipv6_check_mask(const sockaddr *_mask)
|
||||||
|
{
|
||||||
|
if (_mask == NULL)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
bool zero = false;
|
||||||
|
const uint8 *pmask = ((const sockaddr_in6 *)_mask)->sin6_addr.s6_addr;
|
||||||
|
for (uint8 i = 0; i < sizeof(in6_addr); ++i) {
|
||||||
|
if (pmask[i] == 0xff) {
|
||||||
|
if (zero)
|
||||||
|
return false;
|
||||||
|
} else if (pmask[i] == 0) {
|
||||||
|
zero = true;
|
||||||
|
} else {
|
||||||
|
for (int8 bit = 7; bit > 0; bit--) {
|
||||||
|
if (pmask[i] & (1 << bit)) {
|
||||||
|
if (zero)
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
zero = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! Creates a buffer for the given \a address and prints the address into
|
||||||
|
it (hexadecimal representation in network byte order or '<none>').
|
||||||
|
If \a printPort is set, the port is printed, too.
|
||||||
|
\return B_OK if the address could be printed, \a buffer will point to
|
||||||
|
the resulting string
|
||||||
|
\return B_BAD_VALUE if no buffer has been given
|
||||||
|
\return B_NO_MEMORY if the buffer could not be allocated,
|
||||||
|
or does not have enogh space
|
||||||
|
*/
|
||||||
|
static status_t
|
||||||
|
ipv6_print_address_buffer(const sockaddr *_address, char *buffer,
|
||||||
|
size_t bufferSize, bool printPort)
|
||||||
|
{
|
||||||
|
const sockaddr_in6 *address = (const sockaddr_in6 *)_address;
|
||||||
|
|
||||||
|
if (buffer == NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
if (address == NULL) {
|
||||||
|
if (bufferSize < sizeof("<none>"))
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
strcpy(buffer, "<none>");
|
||||||
|
} else {
|
||||||
|
if (printPort && bufferSize > 0) {
|
||||||
|
*buffer = '[';
|
||||||
|
buffer++;
|
||||||
|
bufferSize--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ip6_sprintf(&address->sin6_addr, buffer, bufferSize))
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
if (printPort) {
|
||||||
|
char port[7];
|
||||||
|
sprintf(port, "]:%d", ntohs(address->sin6_port));
|
||||||
|
if (bufferSize - strlen(buffer) < strlen(port) + 1)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
strcat(buffer, port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
ipv6_print_address(const sockaddr *_address, char **_buffer, bool printPort)
|
||||||
|
{
|
||||||
|
if (_buffer == NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
char tmp[64];
|
||||||
|
ipv6_print_address_buffer(_address, tmp, sizeof(tmp), printPort);
|
||||||
|
|
||||||
|
*_buffer = strdup(tmp);
|
||||||
|
if (*_buffer == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! Determines the port of the given \a address.
|
||||||
|
\return uint16 representing the port-nr
|
||||||
|
*/
|
||||||
|
static uint16
|
||||||
|
ipv6_get_port(const sockaddr *address)
|
||||||
|
{
|
||||||
|
if (address == NULL || address->sa_len == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return ((sockaddr_in6 *)address)->sin6_port;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! Sets the port of the given \a address to \a port.
|
||||||
|
\return B_OK if the port has been set
|
||||||
|
\return B_BAD_VALUE if \a address is NULL or has not been initialized
|
||||||
|
*/
|
||||||
|
static status_t
|
||||||
|
ipv6_set_port(sockaddr *address, uint16 port)
|
||||||
|
{
|
||||||
|
if (address == NULL || address->sa_len == 0)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
((sockaddr_in6 *)address)->sin6_port = port;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! Sets \a address to \a from.
|
||||||
|
\return B_OK if \a from has been copied into \a address
|
||||||
|
\return B_BAD_VALUE if either \a address or \a from is NULL or if the
|
||||||
|
address given in from has not been initialized
|
||||||
|
\return B_MISMATCHED_VALUES if from is not of family AF_INET6
|
||||||
|
*/
|
||||||
|
static status_t
|
||||||
|
ipv6_set_to(sockaddr *address, const sockaddr *from)
|
||||||
|
{
|
||||||
|
if (address == NULL || from == NULL || from->sa_len == 0)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
if (from->sa_family != AF_INET6)
|
||||||
|
return B_MISMATCHED_VALUES;
|
||||||
|
|
||||||
|
memcpy(address, from, sizeof(sockaddr_in6));
|
||||||
|
address->sa_len = sizeof(sockaddr_in6);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! Updates missing parts in \a address with the values in \a from.
|
||||||
|
\return B_OK if \a address has been updated from \a from
|
||||||
|
\return B_BAD_VALUE if either \a address or \a from is NULL or if the
|
||||||
|
address given in from has not been initialized
|
||||||
|
\return B_MISMATCHED_VALUES if from is not of family AF_INET6
|
||||||
|
*/
|
||||||
|
static status_t
|
||||||
|
ipv6_update_to(sockaddr *_address, const sockaddr *_from)
|
||||||
|
{
|
||||||
|
sockaddr_in6 *address = (sockaddr_in6 *)_address;
|
||||||
|
const sockaddr_in6 *from = (const sockaddr_in6 *)_from;
|
||||||
|
|
||||||
|
if (address == NULL || from == NULL || from->sin6_len == 0)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
if (from->sin6_family != AF_INET6)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
address->sin6_family = AF_INET6;
|
||||||
|
address->sin6_len = sizeof(sockaddr_in6);
|
||||||
|
|
||||||
|
if (address->sin6_port == 0)
|
||||||
|
address->sin6_port = from->sin6_port;
|
||||||
|
|
||||||
|
if (IN6_IS_ADDR_UNSPECIFIED(&address->sin6_addr)) {
|
||||||
|
memcpy(address->sin6_addr.s6_addr, from->sin6_addr.s6_addr,
|
||||||
|
sizeof(in6_addr));
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! Sets \a address to the empty address (0.0.0.0).
|
||||||
|
\return B_OK if \a address has been set
|
||||||
|
\return B_BAD_VALUE if \a address is NULL
|
||||||
|
*/
|
||||||
|
static status_t
|
||||||
|
ipv6_set_to_empty_address(sockaddr *address)
|
||||||
|
{
|
||||||
|
if (address == NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
memset(address, 0, sizeof(sockaddr_in6));
|
||||||
|
address->sa_len = sizeof(sockaddr_in6);
|
||||||
|
address->sa_family = AF_INET6;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
ipv6_set_to_defaults(sockaddr *_defaultMask, sockaddr *_defaultBroadcast,
|
||||||
|
sockaddr *_address, sockaddr *_mask)
|
||||||
|
{
|
||||||
|
sockaddr_in6 *defaultMask = (sockaddr_in6 *)_defaultMask;
|
||||||
|
sockaddr_in6 *address = (sockaddr_in6 *)_address;
|
||||||
|
sockaddr_in6 *mask = (sockaddr_in6 *)_mask;
|
||||||
|
|
||||||
|
if (address == NULL || defaultMask == NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
defaultMask->sin6_len = sizeof(sockaddr_in);
|
||||||
|
defaultMask->sin6_family = AF_INET6;
|
||||||
|
defaultMask->sin6_port = 0;
|
||||||
|
if (mask != NULL) {
|
||||||
|
memcpy(defaultMask->sin6_addr.s6_addr,
|
||||||
|
mask->sin6_addr.s6_addr, sizeof(in6_addr));
|
||||||
|
} else {
|
||||||
|
// use /128 as the default mask
|
||||||
|
memset(defaultMask->sin6_addr.s6_addr, 0xff, sizeof(in6_addr));
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! Computes a hash-value of the given addresses \a ourAddress
|
||||||
|
and \a peerAddress.
|
||||||
|
\return uint32 representing the hash-value
|
||||||
|
*/
|
||||||
|
static uint32
|
||||||
|
ipv6_hash_address_pair(const sockaddr *ourAddress, const sockaddr *peerAddress)
|
||||||
|
{
|
||||||
|
uint32 result = 0;
|
||||||
|
if (ourAddress) {
|
||||||
|
const sockaddr_in6 *our = (const sockaddr_in6 *)ourAddress;
|
||||||
|
uint32 port = our->sin6_port;
|
||||||
|
|
||||||
|
result = jenkins_hashword((const uint32*)&our->sin6_addr,
|
||||||
|
sizeof(in6_addr) / sizeof(uint32), result);
|
||||||
|
result = jenkins_hashword(&port, 1, result);
|
||||||
|
}
|
||||||
|
if (peerAddress) {
|
||||||
|
const sockaddr_in6 *peer = (const sockaddr_in6 *)peerAddress;
|
||||||
|
uint32 port = peer->sin6_port;
|
||||||
|
|
||||||
|
result = jenkins_hashword((const uint32*)&peer->sin6_addr,
|
||||||
|
sizeof(in6_addr) / sizeof(uint32), result);
|
||||||
|
result = jenkins_hashword(&port, 1, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: also use sin6_flowinfo and sin6_scope_id?
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! Adds the given \a address to the IP-checksum \a checksum.
|
||||||
|
\return B_OK if \a address has been added to the checksum
|
||||||
|
\return B_BAD_VALUE if either \a address or \a checksum is NULL or if
|
||||||
|
the given address is not initialized
|
||||||
|
*/
|
||||||
|
static status_t
|
||||||
|
ipv6_checksum_address(struct Checksum *checksum, const sockaddr *address)
|
||||||
|
{
|
||||||
|
if (checksum == NULL || address == NULL || address->sa_len == 0)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
in6_addr &a = ((sockaddr_in6 *)address)->sin6_addr;
|
||||||
|
for (uint32 i = 0; i < sizeof(in6_addr); i++)
|
||||||
|
(*checksum) << a.s6_addr[i];
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
ipv6_get_loopback_address(sockaddr *_address)
|
||||||
|
{
|
||||||
|
sockaddr_in6 *address = (sockaddr_in6 *)_address;
|
||||||
|
memset(address, 0, sizeof(sockaddr_in6));
|
||||||
|
address->sin6_len = sizeof(sockaddr_in6);
|
||||||
|
address->sin6_family = AF_INET6;
|
||||||
|
memcpy(&address->sin6_addr, &in6addr_loopback, sizeof(in6_addr));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
net_address_module_info gIPv6AddressModule = {
|
||||||
|
{
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
NULL
|
||||||
|
},
|
||||||
|
false, // has_broadcast_address
|
||||||
|
ipv6_copy_address,
|
||||||
|
ipv6_mask_address,
|
||||||
|
ipv6_equal_addresses,
|
||||||
|
ipv6_equal_ports,
|
||||||
|
ipv6_equal_addresses_and_ports,
|
||||||
|
ipv6_equal_masked_addresses,
|
||||||
|
ipv6_is_empty_address,
|
||||||
|
ipv6_is_same_family,
|
||||||
|
ipv6_first_mask_bit,
|
||||||
|
ipv6_check_mask,
|
||||||
|
ipv6_print_address,
|
||||||
|
ipv6_print_address_buffer,
|
||||||
|
ipv6_get_port,
|
||||||
|
ipv6_set_port,
|
||||||
|
ipv6_set_to,
|
||||||
|
ipv6_set_to_empty_address,
|
||||||
|
ipv6_set_to_defaults,
|
||||||
|
ipv6_update_to,
|
||||||
|
ipv6_hash_address_pair,
|
||||||
|
ipv6_checksum_address,
|
||||||
|
ipv6_get_loopback_address
|
||||||
|
};
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, Haiku, Inc. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef IPV6_ADDRESS_H
|
||||||
|
#define IPV6_ADDRESS_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <netinet6/in6.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
|
extern struct net_address_module_info gIPv6AddressModule;
|
||||||
|
|
||||||
|
|
||||||
|
#define NET_IPV6_MODULE_NAME "network/protocols/ipv6/v1"
|
||||||
|
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
operator==(const in6_addr &a1, const in6_addr &a2)
|
||||||
|
{
|
||||||
|
// TODO: optimize
|
||||||
|
return !memcmp(&a1, &a2, sizeof(in6_addr));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif // IPV6_ADDRESS_H
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, Haiku, Inc. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
|
||||||
|
* Copyright (c) 1996-1999 by Internet Software Consortium.
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
||||||
|
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <net_datalink.h>
|
||||||
|
|
||||||
|
#include <ByteOrder.h>
|
||||||
|
#include <KernelExport.h>
|
||||||
|
#include <NetUtilities.h>
|
||||||
|
|
||||||
|
#include <memory.h>
|
||||||
|
#include <netinet6/in6.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "ipv6_utils.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define NS_IN6ADDRSZ 16
|
||||||
|
#define NS_INT16SZ 2
|
||||||
|
|
||||||
|
#define SPRINTF(x) ((size_t)sprintf x)
|
||||||
|
|
||||||
|
|
||||||
|
/*! Convert IPv6 binary address into presentation (printable) format.
|
||||||
|
Author: Paul Vixie, 1996.
|
||||||
|
\return pointer to dst string if address as been printed
|
||||||
|
\return NULL if the buffer is too short
|
||||||
|
*/
|
||||||
|
const char *
|
||||||
|
ip6_sprintf(const in6_addr *srcaddr, char *dst, size_t size)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Note that int32_t and int16_t need only be "at least" large enough
|
||||||
|
* to contain a value of the specified size. On some systems, like
|
||||||
|
* Crays, there is no such thing as an integer variable with 16 bits.
|
||||||
|
* Keep this in mind if you think this function should have been coded
|
||||||
|
* to use pointer overlays. All the world's not a VAX.
|
||||||
|
*/
|
||||||
|
char tmp[INET6_ADDRSTRLEN], *tp;
|
||||||
|
struct { int base, len; } best, cur;
|
||||||
|
uint16 words[NS_IN6ADDRSZ / NS_INT16SZ];
|
||||||
|
int i;
|
||||||
|
const uint8 *src = srcaddr->s6_addr;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Preprocess:
|
||||||
|
* Copy the input (bytewise) array into a wordwise array.
|
||||||
|
* Find the longest run of 0x00's in src[] for :: shorthanding.
|
||||||
|
*/
|
||||||
|
memset(words, '\0', sizeof words);
|
||||||
|
for (i = 0; i < NS_IN6ADDRSZ; i++)
|
||||||
|
words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
|
||||||
|
best.base = -1;
|
||||||
|
best.len = 0;
|
||||||
|
cur.base = -1;
|
||||||
|
cur.len = 0;
|
||||||
|
for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
|
||||||
|
if (words[i] == 0) {
|
||||||
|
if (cur.base == -1)
|
||||||
|
cur.base = i, cur.len = 1;
|
||||||
|
else
|
||||||
|
cur.len++;
|
||||||
|
} else {
|
||||||
|
if (cur.base != -1) {
|
||||||
|
if (best.base == -1 || cur.len > best.len)
|
||||||
|
best = cur;
|
||||||
|
cur.base = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cur.base != -1) {
|
||||||
|
if (best.base == -1 || cur.len > best.len)
|
||||||
|
best = cur;
|
||||||
|
}
|
||||||
|
if (best.base != -1 && best.len < 2)
|
||||||
|
best.base = -1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Format the result.
|
||||||
|
*/
|
||||||
|
tp = tmp;
|
||||||
|
for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
|
||||||
|
/* Are we inside the best run of 0x00's? */
|
||||||
|
if (best.base != -1 && i >= best.base &&
|
||||||
|
i < (best.base + best.len)) {
|
||||||
|
if (i == best.base)
|
||||||
|
*tp++ = ':';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Are we following an initial run of 0x00s or any real hex? */
|
||||||
|
if (i != 0)
|
||||||
|
*tp++ = ':';
|
||||||
|
/* Is this address an encapsulated IPv4? */
|
||||||
|
#if 0
|
||||||
|
if (i == 6 && best.base == 0 && (best.len == 6 ||
|
||||||
|
(best.len == 7 && words[7] != 0x0001) ||
|
||||||
|
(best.len == 5 && words[5] == 0xffff))) {
|
||||||
|
if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp)))
|
||||||
|
return (NULL);
|
||||||
|
tp += strlen(tp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
tp += SPRINTF((tp, "%x", words[i]));
|
||||||
|
}
|
||||||
|
/* Was it a trailing run of 0x00's? */
|
||||||
|
if (best.base != -1 && (best.base + best.len) ==
|
||||||
|
(NS_IN6ADDRSZ / NS_INT16SZ))
|
||||||
|
*tp++ = ':';
|
||||||
|
*tp++ = '\0';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check for overflow, copy, and we're done.
|
||||||
|
*/
|
||||||
|
if ((size_t)(tp - tmp) > size)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
strcpy(dst, tmp);
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, Haiku, Inc. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Atis Elsts, the.kfx@gmail.com
|
||||||
|
*/
|
||||||
|
#ifndef IPV6_UTILS_H
|
||||||
|
#define IPV6_UTILS_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <netinet6/in6.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <net_stack.h>
|
||||||
|
|
||||||
|
|
||||||
|
const char *ip6_sprintf(const in6_addr *addr, char *dst,
|
||||||
|
size_t size = INET6_ADDRSTRLEN);
|
||||||
|
|
||||||
|
|
||||||
|
static inline uint16
|
||||||
|
compute_checksum(uint8* _buffer, size_t length)
|
||||||
|
{
|
||||||
|
uint16* buffer = (uint16*)_buffer;
|
||||||
|
uint32 sum = 0;
|
||||||
|
|
||||||
|
while (length >= 2) {
|
||||||
|
sum += *buffer++;
|
||||||
|
length -= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline uint16
|
||||||
|
ipv6_checksum(const struct in6_addr* source,
|
||||||
|
const struct in6_addr* destination,
|
||||||
|
uint16 length, uint16 protocol,
|
||||||
|
uint16 checksum)
|
||||||
|
{
|
||||||
|
uint32 sum = checksum;
|
||||||
|
|
||||||
|
length = htons(length);
|
||||||
|
protocol = htons(protocol);
|
||||||
|
|
||||||
|
sum += compute_checksum((uint8*)source, sizeof(in6_addr));
|
||||||
|
sum += compute_checksum((uint8*)destination, sizeof(in6_addr));
|
||||||
|
sum += compute_checksum((uint8*)&length, sizeof(uint16));
|
||||||
|
sum += compute_checksum((uint8*)&protocol, sizeof(uint16));
|
||||||
|
|
||||||
|
while (sum >> 16)
|
||||||
|
sum = (sum & 0xffff) + (sum >> 16);
|
||||||
|
|
||||||
|
return ~(uint16)sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif // IPV6_UTILS_H
|
||||||
@@ -0,0 +1,187 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, Haiku, Inc. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Taken from http://burtleburtle.net/bob/c/lookup3.c
|
||||||
|
*/
|
||||||
|
#ifndef LIBKERN_JENKINS_H
|
||||||
|
#define LIBKERN_JENKINS_H
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
lookup3.c, by Bob Jenkins, May 2006, Public Domain.
|
||||||
|
|
||||||
|
These are functions for producing 32-bit hashes for hash table lookup.
|
||||||
|
hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final()
|
||||||
|
are externally useful functions. Routines to test the hash are included
|
||||||
|
if SELF_TEST is defined. You can use this free for any purpose. It's in
|
||||||
|
the public domain. It has no warranty.
|
||||||
|
|
||||||
|
You probably want to use hashlittle(). hashlittle() and hashbig()
|
||||||
|
hash byte arrays. hashlittle() is is faster than hashbig() on
|
||||||
|
little-endian machines. Intel and AMD are little-endian machines.
|
||||||
|
On second thought, you probably want hashlittle2(), which is identical to
|
||||||
|
hashlittle() except it returns two 32-bit hashes for the price of one.
|
||||||
|
You could implement hashbig2() if you wanted but I haven't bothered here.
|
||||||
|
|
||||||
|
If you want to find a hash of, say, exactly 7 integers, do
|
||||||
|
a = i1; b = i2; c = i3;
|
||||||
|
mix(a,b,c);
|
||||||
|
a += i4; b += i5; c += i6;
|
||||||
|
mix(a,b,c);
|
||||||
|
a += i7;
|
||||||
|
final(a,b,c);
|
||||||
|
then use c as the hash value. If you have a variable length array of
|
||||||
|
4-byte integers to hash, use hashword(). If you have a byte array (like
|
||||||
|
a character string), use hashlittle(). If you have several byte arrays, or
|
||||||
|
a mix of things, see the comments above hashlittle().
|
||||||
|
|
||||||
|
Why is this so big? I read 12 bytes at a time into 3 4-byte integers,
|
||||||
|
then mix those integers. This is fast (you can do a lot more thorough
|
||||||
|
mixing with 12*3 instructions on 3 integers than you can with 3 instructions
|
||||||
|
on 1 byte), but shoehorning those bytes into integers efficiently is messy.
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
|
||||||
|
|
||||||
|
/*
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
mix -- mix 3 32-bit values reversibly.
|
||||||
|
|
||||||
|
This is reversible, so any information in (a,b,c) before mix() is
|
||||||
|
still in (a,b,c) after mix().
|
||||||
|
|
||||||
|
If four pairs of (a,b,c) inputs are run through mix(), or through
|
||||||
|
mix() in reverse, there are at least 32 bits of the output that
|
||||||
|
are sometimes the same for one pair and different for another pair.
|
||||||
|
This was tested for:
|
||||||
|
* pairs that differed by one bit, by two bits, in any combination
|
||||||
|
of top bits of (a,b,c), or in any combination of bottom bits of
|
||||||
|
(a,b,c).
|
||||||
|
* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed
|
||||||
|
the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
|
||||||
|
is commonly produced by subtraction) look like a single 1-bit
|
||||||
|
difference.
|
||||||
|
* the base values were pseudorandom, all zero but one bit set, or
|
||||||
|
all zero plus a counter that starts at zero.
|
||||||
|
|
||||||
|
Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that
|
||||||
|
satisfy this are
|
||||||
|
4 6 8 16 19 4
|
||||||
|
9 15 3 18 27 15
|
||||||
|
14 9 3 7 17 3
|
||||||
|
Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing
|
||||||
|
for "differ" defined as + with a one-bit base and a two-bit delta. I
|
||||||
|
used http://burtleburtle.net/bob/hash/avalanche.html to choose
|
||||||
|
the operations, constants, and arrangements of the variables.
|
||||||
|
|
||||||
|
This does not achieve avalanche. There are input bits of (a,b,c)
|
||||||
|
that fail to affect some output bits of (a,b,c), especially of a. The
|
||||||
|
most thoroughly mixed value is c, but it doesn't really even achieve
|
||||||
|
avalanche in c.
|
||||||
|
|
||||||
|
This allows some parallelism. Read-after-writes are good at doubling
|
||||||
|
the number of bits affected, so the goal of mixing pulls in the opposite
|
||||||
|
direction as the goal of parallelism. I did what I could. Rotates
|
||||||
|
seem to cost as much as shifts on every machine I could lay my hands
|
||||||
|
on, and rotates are much kinder to the top and bottom bits, so I used
|
||||||
|
rotates.
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
#define mix(a,b,c) \
|
||||||
|
{ \
|
||||||
|
a -= c; a ^= rot(c, 4); c += b; \
|
||||||
|
b -= a; b ^= rot(a, 6); a += c; \
|
||||||
|
c -= b; c ^= rot(b, 8); b += a; \
|
||||||
|
a -= c; a ^= rot(c,16); c += b; \
|
||||||
|
b -= a; b ^= rot(a,19); a += c; \
|
||||||
|
c -= b; c ^= rot(b, 4); b += a; \
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
final -- final mixing of 3 32-bit values (a,b,c) into c
|
||||||
|
|
||||||
|
Pairs of (a,b,c) values differing in only a few bits will usually
|
||||||
|
produce values of c that look totally different. This was tested for
|
||||||
|
* pairs that differed by one bit, by two bits, in any combination
|
||||||
|
of top bits of (a,b,c), or in any combination of bottom bits of
|
||||||
|
(a,b,c).
|
||||||
|
* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed
|
||||||
|
the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
|
||||||
|
is commonly produced by subtraction) look like a single 1-bit
|
||||||
|
difference.
|
||||||
|
* the base values were pseudorandom, all zero but one bit set, or
|
||||||
|
all zero plus a counter that starts at zero.
|
||||||
|
|
||||||
|
These constants passed:
|
||||||
|
14 11 25 16 4 14 24
|
||||||
|
12 14 25 16 4 14 24
|
||||||
|
and these came close:
|
||||||
|
4 8 15 26 3 22 24
|
||||||
|
10 8 15 26 3 22 24
|
||||||
|
11 8 15 26 3 22 24
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
#define final(a,b,c) \
|
||||||
|
{ \
|
||||||
|
c ^= b; c -= rot(b,14); \
|
||||||
|
a ^= c; a -= rot(c,11); \
|
||||||
|
b ^= a; b -= rot(a,25); \
|
||||||
|
c ^= b; c -= rot(b,16); \
|
||||||
|
a ^= c; a -= rot(c,4); \
|
||||||
|
b ^= a; b -= rot(a,14); \
|
||||||
|
c ^= b; c -= rot(b,24); \
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
This works on all machines. To be useful, it requires
|
||||||
|
-- that the key be an array of uint32's, and
|
||||||
|
-- that the length be the number of uint32's in the key
|
||||||
|
|
||||||
|
The function hashword() is identical to hashlittle() on little-endian
|
||||||
|
machines, and identical to hashbig() on big-endian machines,
|
||||||
|
except that the length has to be measured in uint32s rather than in
|
||||||
|
bytes. hashlittle() is more complicated than hashword() only because
|
||||||
|
hashlittle() has to dance around fitting the key bytes into registers.
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
static uint32
|
||||||
|
jenkins_hashword(const uint32 *k, /* the key, an array of uint32 values */
|
||||||
|
size_t length, /* the length of the key, in uint32s */
|
||||||
|
uint32 initval) /* the previous hash, or an arbitrary value */
|
||||||
|
{
|
||||||
|
uint32 a,b,c;
|
||||||
|
|
||||||
|
/* Set up the internal state */
|
||||||
|
a = b = c = 0xdeadbeef + (((uint32)length)<<2) + initval;
|
||||||
|
|
||||||
|
/*------------------------------------------------- handle most of the key */
|
||||||
|
while (length > 3)
|
||||||
|
{
|
||||||
|
a += k[0];
|
||||||
|
b += k[1];
|
||||||
|
c += k[2];
|
||||||
|
mix(a,b,c);
|
||||||
|
length -= 3;
|
||||||
|
k += 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*------------------------------------------- handle the last 3 uint32's */
|
||||||
|
switch(length) /* all the case statements fall through */
|
||||||
|
{
|
||||||
|
case 3 : c+=k[2];
|
||||||
|
case 2 : b+=k[1];
|
||||||
|
case 1 : a+=k[0];
|
||||||
|
final(a,b,c);
|
||||||
|
case 0: /* case 0: nothing left to add */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/*------------------------------------------------------ report the result */
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,209 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, Haiku, Inc. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Atis Elsts, the.kfx@gmail.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "ipv6_address.h"
|
||||||
|
#include "multicast.h"
|
||||||
|
|
||||||
|
#include <net_buffer.h>
|
||||||
|
|
||||||
|
#include <netinet6/in6.h>
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
|
||||||
|
using std::nothrow;
|
||||||
|
|
||||||
|
|
||||||
|
template<typename Addressing>
|
||||||
|
MulticastGroupInterface<Addressing>::MulticastGroupInterface(Filter *parent,
|
||||||
|
const AddressType &address, net_interface *interface)
|
||||||
|
: fParent(parent), fMulticastAddress(address), fInterface(interface)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename Addressing>
|
||||||
|
MulticastGroupInterface<Addressing>::~MulticastGroupInterface()
|
||||||
|
{
|
||||||
|
Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename Addressing> status_t
|
||||||
|
MulticastGroupInterface<Addressing>::Add()
|
||||||
|
{
|
||||||
|
if (fFilterMode == kInclude && !fAddresses.IsEmpty())
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
|
fFilterMode = kExclude;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename Addressing> status_t
|
||||||
|
MulticastGroupInterface<Addressing>::Drop()
|
||||||
|
{
|
||||||
|
fAddresses.Clear();
|
||||||
|
fFilterMode = kInclude;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename Addressing> status_t
|
||||||
|
MulticastGroupInterface<Addressing>::BlockSource(
|
||||||
|
const AddressType &sourceAddress)
|
||||||
|
{
|
||||||
|
if (fFilterMode != kExclude)
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
|
fAddresses.Add(sourceAddress);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename Addressing> status_t
|
||||||
|
MulticastGroupInterface<Addressing>::UnblockSource(
|
||||||
|
const AddressType &sourceAddress)
|
||||||
|
{
|
||||||
|
if (fFilterMode != kExclude)
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
|
if (!fAddresses.Has(sourceAddress))
|
||||||
|
return EADDRNOTAVAIL;
|
||||||
|
|
||||||
|
fAddresses.Add(sourceAddress);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename Addressing> status_t
|
||||||
|
MulticastGroupInterface<Addressing>::AddSSM(const AddressType &sourceAddress)
|
||||||
|
{
|
||||||
|
if (fFilterMode == kExclude)
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
|
fAddresses.Add(sourceAddress);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename Addressing> status_t
|
||||||
|
MulticastGroupInterface<Addressing>::DropSSM(const AddressType &sourceAddress)
|
||||||
|
{
|
||||||
|
if (fFilterMode == kExclude)
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
|
if (!fAddresses.Has(sourceAddress))
|
||||||
|
return EADDRNOTAVAIL;
|
||||||
|
|
||||||
|
fAddresses.Add(sourceAddress);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename Addressing> bool
|
||||||
|
MulticastGroupInterface<Addressing>::IsEmpty() const
|
||||||
|
{
|
||||||
|
return fFilterMode == kInclude && fAddresses.IsEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename Addressing> void
|
||||||
|
MulticastGroupInterface<Addressing>::Clear()
|
||||||
|
{
|
||||||
|
if (IsEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
fFilterMode = kInclude;
|
||||||
|
fAddresses.Clear();
|
||||||
|
Addressing::LeaveGroup(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename Addressing> bool
|
||||||
|
MulticastGroupInterface<Addressing>::FilterAccepts(net_buffer *buffer) const
|
||||||
|
{
|
||||||
|
bool has = fAddresses.Has(Addressing::AddressFromSockAddr(
|
||||||
|
buffer->source));
|
||||||
|
|
||||||
|
return (has && fFilterMode == kInclude)
|
||||||
|
|| (!has && fFilterMode == kExclude);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename Addressing>
|
||||||
|
MulticastFilter<Addressing>::MulticastFilter(ProtocolType *socket)
|
||||||
|
: fParent(socket), fStates()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename Addressing>
|
||||||
|
MulticastFilter<Addressing>::~MulticastFilter()
|
||||||
|
{
|
||||||
|
while (true) {
|
||||||
|
typename States::Iterator iterator = fStates.GetIterator();
|
||||||
|
if (!iterator.HasNext())
|
||||||
|
return;
|
||||||
|
|
||||||
|
GroupInterface *state = iterator.Next();
|
||||||
|
state->Clear();
|
||||||
|
_ReturnState(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename Addressing> status_t
|
||||||
|
MulticastFilter<Addressing>::GetState(const AddressType &groupAddress,
|
||||||
|
net_interface *interface, GroupInterface* &state, bool create)
|
||||||
|
{
|
||||||
|
state = fStates.Lookup(std::make_pair(&groupAddress, interface->index));
|
||||||
|
|
||||||
|
if (state == NULL && create) {
|
||||||
|
state = new (nothrow) GroupInterface(this, groupAddress, interface);
|
||||||
|
if (state == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
status_t status = fStates.Insert(state);
|
||||||
|
if (status < B_OK) {
|
||||||
|
delete state;
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = Addressing::JoinGroup(state);
|
||||||
|
if (status < B_OK) {
|
||||||
|
fStates.Remove(state);
|
||||||
|
delete state;
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename Addressing> void
|
||||||
|
MulticastFilter<Addressing>::ReturnState(GroupInterface *state)
|
||||||
|
{
|
||||||
|
if (state->IsEmpty())
|
||||||
|
_ReturnState(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename Addressing> void
|
||||||
|
MulticastFilter<Addressing>::_ReturnState(GroupInterface *state)
|
||||||
|
{
|
||||||
|
fStates.Remove(state);
|
||||||
|
delete state;
|
||||||
|
}
|
||||||
|
|
||||||
|
// IPv6 explicit template instantiation
|
||||||
|
template class MulticastFilter<IPv6Multicast>;
|
||||||
|
template class MulticastGroupInterface<IPv6Multicast>;
|
||||||
@@ -0,0 +1,232 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, Haiku, Inc. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Atis Elsts, the.kfx@gmail.com
|
||||||
|
*/
|
||||||
|
#ifndef _IPV6_MULTICAST_H_
|
||||||
|
#define _IPV6_MULTICAST_H_
|
||||||
|
|
||||||
|
|
||||||
|
#include <util/DoublyLinkedList.h>
|
||||||
|
#include <util/OpenHashTable.h>
|
||||||
|
|
||||||
|
#include <net_datalink.h>
|
||||||
|
|
||||||
|
#include <netinet6/in6.h>
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "jenkins.h"
|
||||||
|
|
||||||
|
|
||||||
|
struct net_buffer;
|
||||||
|
struct net_protocol;
|
||||||
|
|
||||||
|
|
||||||
|
template<typename Addressing> class MulticastFilter;
|
||||||
|
template<typename Addressing> class MulticastGroupInterface;
|
||||||
|
|
||||||
|
|
||||||
|
struct IPv6Multicast {
|
||||||
|
typedef struct in6_addr AddressType;
|
||||||
|
typedef struct ipv6_protocol ProtocolType;
|
||||||
|
typedef MulticastGroupInterface<IPv6Multicast> GroupInterface;
|
||||||
|
|
||||||
|
static status_t JoinGroup(GroupInterface *);
|
||||||
|
static status_t LeaveGroup(GroupInterface *);
|
||||||
|
|
||||||
|
static const in6_addr &AddressFromSockAddr(const sockaddr *sockaddr)
|
||||||
|
{ return ((const sockaddr_in6 *)sockaddr)->sin6_addr; }
|
||||||
|
static size_t HashAddress(const in6_addr &address)
|
||||||
|
{ return jenkins_hashword((const uint32*)&address,
|
||||||
|
sizeof(in6_addr) / sizeof(uint32), 0); }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<typename AddressType>
|
||||||
|
class AddressSet {
|
||||||
|
struct ContainedAddress : DoublyLinkedListLinkImpl<ContainedAddress> {
|
||||||
|
AddressType address;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef DoublyLinkedList<ContainedAddress> AddressList;
|
||||||
|
|
||||||
|
public:
|
||||||
|
AddressSet()
|
||||||
|
: fCount(0) {}
|
||||||
|
|
||||||
|
~AddressSet() { Clear(); }
|
||||||
|
|
||||||
|
status_t Add(const AddressType &address)
|
||||||
|
{
|
||||||
|
if (Has(address))
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
ContainedAddress *container = new ContainedAddress();
|
||||||
|
if (container == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
container->address = address;
|
||||||
|
fAddresses.Add(container);
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Remove(const AddressType &address)
|
||||||
|
{
|
||||||
|
ContainedAddress *container = _Get(address);
|
||||||
|
if (container == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
fAddresses.Remove(container);
|
||||||
|
delete container;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Has(const AddressType &address) const
|
||||||
|
{
|
||||||
|
return _Get(address) != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsEmpty() const { return fAddresses.IsEmpty(); }
|
||||||
|
|
||||||
|
void Clear()
|
||||||
|
{
|
||||||
|
while (!fAddresses.IsEmpty())
|
||||||
|
Remove(fAddresses.Head()->address);
|
||||||
|
}
|
||||||
|
|
||||||
|
class Iterator {
|
||||||
|
public:
|
||||||
|
Iterator(const AddressList &addresses)
|
||||||
|
: fBaseIterator(addresses.GetIterator()) {}
|
||||||
|
|
||||||
|
bool HasNext() const { return fBaseIterator.HasNext(); }
|
||||||
|
AddressType &Next() { return fBaseIterator.Next()->address; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
typename AddressList::ConstIterator fBaseIterator;
|
||||||
|
};
|
||||||
|
|
||||||
|
Iterator GetIterator() const { return Iterator(fAddresses); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
ContainedAddress *_Get(const AddressType &address) const
|
||||||
|
{
|
||||||
|
typename AddressList::ConstIterator it = fAddresses.GetIterator();
|
||||||
|
while (it.HasNext()) {
|
||||||
|
ContainedAddress *container = it.Next();
|
||||||
|
if (container->address == address)
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddressList fAddresses;
|
||||||
|
int fCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<typename Addressing>
|
||||||
|
class MulticastGroupInterface {
|
||||||
|
public:
|
||||||
|
typedef MulticastGroupInterface<Addressing> ThisType;
|
||||||
|
typedef typename Addressing::AddressType AddressType;
|
||||||
|
typedef MulticastFilter<Addressing> Filter;
|
||||||
|
typedef ::AddressSet<AddressType> AddressSet;
|
||||||
|
|
||||||
|
enum FilterMode {
|
||||||
|
kInclude,
|
||||||
|
kExclude
|
||||||
|
};
|
||||||
|
|
||||||
|
MulticastGroupInterface(Filter *parent, const AddressType &address,
|
||||||
|
net_interface *interface);
|
||||||
|
~MulticastGroupInterface();
|
||||||
|
|
||||||
|
Filter *Parent() const { return fParent; }
|
||||||
|
|
||||||
|
const AddressType &Address() const { return fMulticastAddress; }
|
||||||
|
net_interface *Interface() const { return fInterface; }
|
||||||
|
|
||||||
|
status_t Add();
|
||||||
|
status_t Drop();
|
||||||
|
status_t BlockSource(const AddressType &sourceAddress);
|
||||||
|
status_t UnblockSource(const AddressType &sourceAddress);
|
||||||
|
status_t AddSSM(const AddressType &sourceAddress);
|
||||||
|
status_t DropSSM(const AddressType &sourceAddress);
|
||||||
|
|
||||||
|
bool IsEmpty() const;
|
||||||
|
void Clear();
|
||||||
|
|
||||||
|
FilterMode Mode() const { return fFilterMode; }
|
||||||
|
const AddressSet &Sources() const { return fAddresses; }
|
||||||
|
|
||||||
|
bool FilterAccepts(net_buffer *buffer) const;
|
||||||
|
|
||||||
|
struct HashDefinition {
|
||||||
|
typedef std::pair<const AddressType *, uint32> KeyType;
|
||||||
|
typedef ThisType ValueType;
|
||||||
|
|
||||||
|
size_t HashKey(const KeyType &key) const
|
||||||
|
{
|
||||||
|
size_t result = 0;
|
||||||
|
result = jenkins_hashword((const uint32*)&key.first,
|
||||||
|
sizeof(in6_addr) / sizeof(uint32), result);
|
||||||
|
result = jenkins_hashword(&key.second, 1, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
size_t Hash(ValueType *value) const
|
||||||
|
{ return HashKey(std::make_pair(&value->Address(),
|
||||||
|
value->Interface()->index)); }
|
||||||
|
bool Compare(const KeyType &key, ValueType *value) const
|
||||||
|
{ return value->Interface()->index == key.second
|
||||||
|
&& value->Address() == *key.first; }
|
||||||
|
MulticastGroupInterface*& GetLink(ValueType *value) const
|
||||||
|
{ return value->HashLink(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
MulticastGroupInterface*& HashLink() { return fLink; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
// for g++ 2.95
|
||||||
|
friend class HashDefinition;
|
||||||
|
|
||||||
|
Filter *fParent;
|
||||||
|
AddressType fMulticastAddress;
|
||||||
|
net_interface *fInterface;
|
||||||
|
FilterMode fFilterMode;
|
||||||
|
AddressSet fAddresses;
|
||||||
|
MulticastGroupInterface* fLink;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<typename Addressing>
|
||||||
|
class MulticastFilter {
|
||||||
|
public:
|
||||||
|
typedef typename Addressing::AddressType AddressType;
|
||||||
|
typedef typename Addressing::ProtocolType ProtocolType;
|
||||||
|
typedef MulticastGroupInterface<Addressing> GroupInterface;
|
||||||
|
|
||||||
|
MulticastFilter(ProtocolType *parent);
|
||||||
|
~MulticastFilter();
|
||||||
|
|
||||||
|
ProtocolType *Socket() const { return fParent; }
|
||||||
|
|
||||||
|
status_t GetState(const AddressType &groupAddress,
|
||||||
|
net_interface *interface, GroupInterface* &state, bool create);
|
||||||
|
void ReturnState(GroupInterface *state);
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef typename GroupInterface::HashDefinition HashDefinition;
|
||||||
|
typedef BOpenHashTable<HashDefinition> States;
|
||||||
|
|
||||||
|
void _ReturnState(GroupInterface *state);
|
||||||
|
|
||||||
|
ProtocolType *fParent;
|
||||||
|
States fStates;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _IPV6_MULTICAST_H_
|
||||||
@@ -413,6 +413,7 @@ net_address_module_info gL2cap4AddressModule = {
|
|||||||
0,
|
0,
|
||||||
NULL
|
NULL
|
||||||
},
|
},
|
||||||
|
true, // has_broadcast_address
|
||||||
l2cap_copy_address,
|
l2cap_copy_address,
|
||||||
l2cap_mask_address,
|
l2cap_mask_address,
|
||||||
l2cap_equal_addresses,
|
l2cap_equal_addresses,
|
||||||
|
|||||||
@@ -1207,17 +1207,34 @@ init_udp()
|
|||||||
NULL);
|
NULL);
|
||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
goto err1;
|
goto err1;
|
||||||
|
status = gStackModule->register_domain_protocols(AF_INET6, SOCK_DGRAM, IPPROTO_IP,
|
||||||
|
"network/protocols/udp/v1",
|
||||||
|
"network/protocols/ipv6/v1",
|
||||||
|
NULL);
|
||||||
|
if (status < B_OK)
|
||||||
|
goto err1;
|
||||||
|
|
||||||
status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM, IPPROTO_UDP,
|
status = gStackModule->register_domain_protocols(AF_INET, SOCK_DGRAM, IPPROTO_UDP,
|
||||||
"network/protocols/udp/v1",
|
"network/protocols/udp/v1",
|
||||||
"network/protocols/ipv4/v1",
|
"network/protocols/ipv4/v1",
|
||||||
NULL);
|
NULL);
|
||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
goto err1;
|
goto err1;
|
||||||
|
status = gStackModule->register_domain_protocols(AF_INET6, SOCK_DGRAM, IPPROTO_UDP,
|
||||||
|
"network/protocols/udp/v1",
|
||||||
|
"network/protocols/ipv6/v1",
|
||||||
|
NULL);
|
||||||
|
if (status < B_OK)
|
||||||
|
goto err1;
|
||||||
|
|
||||||
status = gStackModule->register_domain_receiving_protocol(AF_INET, IPPROTO_UDP,
|
status = gStackModule->register_domain_receiving_protocol(AF_INET, IPPROTO_UDP,
|
||||||
"network/protocols/udp/v1");
|
"network/protocols/udp/v1");
|
||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
goto err1;
|
goto err1;
|
||||||
|
status = gStackModule->register_domain_receiving_protocol(AF_INET6, IPPROTO_UDP,
|
||||||
|
"network/protocols/udp/v1");
|
||||||
|
if (status < B_OK)
|
||||||
|
goto err1;
|
||||||
|
|
||||||
add_debugger_command("udp_endpoints", UdpEndpointManager::DumpEndpoints,
|
add_debugger_command("udp_endpoints", UdpEndpointManager::DumpEndpoints,
|
||||||
"lists all open UDP endpoints");
|
"lists all open UDP endpoints");
|
||||||
@@ -1225,6 +1242,7 @@ init_udp()
|
|||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
||||||
err1:
|
err1:
|
||||||
|
// TODO: shouldn't unregister the protocols here?
|
||||||
delete sUdpEndpointManager;
|
delete sUdpEndpointManager;
|
||||||
|
|
||||||
TRACE_EPM("init_udp() fails with %lx (%s)", status, strerror(status));
|
TRACE_EPM("init_udp() fails with %lx (%s)", status, strerror(status));
|
||||||
|
|||||||
@@ -290,7 +290,7 @@ net_address_module_info gAddressModule = {
|
|||||||
0,
|
0,
|
||||||
NULL
|
NULL
|
||||||
},
|
},
|
||||||
|
true, // has_broadcast_address
|
||||||
unix_copy_address,
|
unix_copy_address,
|
||||||
unix_mask_address,
|
unix_mask_address,
|
||||||
unix_equal_addresses,
|
unix_equal_addresses,
|
||||||
|
|||||||
@@ -30,6 +30,8 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <netinet6/in6.h> // TODO
|
||||||
|
|
||||||
|
|
||||||
struct datalink_protocol : net_protocol {
|
struct datalink_protocol : net_protocol {
|
||||||
struct net_domain_private* domain;
|
struct net_domain_private* domain;
|
||||||
@@ -134,6 +136,21 @@ remove_default_routes(net_interface_private* interface, int32 option)
|
|||||||
route.flags = RTF_LOCAL | RTF_HOST;
|
route.flags = RTF_LOCAL | RTF_HOST;
|
||||||
remove_route(interface->domain, &route);
|
remove_route(interface->domain, &route);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// for IPv6 remove multicast route (ff00::/8)
|
||||||
|
// TODO: move this code
|
||||||
|
if (interface->address->sa_family == AF_INET6) {
|
||||||
|
sockaddr_in6 address;
|
||||||
|
memset(&address, 0, sizeof(sockaddr_in6));
|
||||||
|
address.sin6_family = AF_INET6;
|
||||||
|
address.sin6_len = sizeof(sockaddr_in6);
|
||||||
|
address.sin6_addr.s6_addr[0] = 0xff;
|
||||||
|
|
||||||
|
route.destination = (sockaddr*)&address;
|
||||||
|
route.mask = (sockaddr*)&address;
|
||||||
|
route.flags = 0;
|
||||||
|
remove_route(interface->domain, &route);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -160,6 +177,21 @@ add_default_routes(net_interface_private* interface, int32 option)
|
|||||||
route.flags = RTF_LOCAL | RTF_HOST;
|
route.flags = RTF_LOCAL | RTF_HOST;
|
||||||
add_route(interface->domain, &route);
|
add_route(interface->domain, &route);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// for IPv6 add multicast route (ff00::/8)
|
||||||
|
// TODO: move this code
|
||||||
|
if (interface->address->sa_family == AF_INET6) {
|
||||||
|
sockaddr_in6 address;
|
||||||
|
memset(&address, 0, sizeof(sockaddr_in6));
|
||||||
|
address.sin6_family = AF_INET6;
|
||||||
|
address.sin6_len = sizeof(sockaddr_in6);
|
||||||
|
address.sin6_addr.s6_addr[0] = 0xff;
|
||||||
|
|
||||||
|
route.destination = (sockaddr*)&address;
|
||||||
|
route.mask = (sockaddr*)&address;
|
||||||
|
route.flags = 0;
|
||||||
|
add_route(interface->domain, &route);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -183,6 +215,14 @@ reallocate_address(sockaddr** _address, uint32 size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
free_address(sockaddr** _address)
|
||||||
|
{
|
||||||
|
free(*_address);
|
||||||
|
*_address = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
datalink_control_interface(net_domain_private* domain, int32 option,
|
datalink_control_interface(net_domain_private* domain, int32 option,
|
||||||
void* value, size_t* _length, size_t expected, bool getByName)
|
void* value, size_t* _length, size_t expected, bool getByName)
|
||||||
@@ -386,7 +426,8 @@ datalink_send_datagram(net_protocol* protocol, net_domain* domain,
|
|||||||
|
|
||||||
net_route* route = NULL;
|
net_route* route = NULL;
|
||||||
status_t status;
|
status_t status;
|
||||||
if (protocol != NULL && protocol->socket->bound_to_device > 0) {
|
if (protocol != NULL && protocol->socket != NULL
|
||||||
|
&& protocol->socket->bound_to_device > 0) {
|
||||||
status = get_device_route(domain, protocol->socket->bound_to_device,
|
status = get_device_route(domain, protocol->socket->bound_to_device,
|
||||||
&route);
|
&route);
|
||||||
} else
|
} else
|
||||||
@@ -709,8 +750,15 @@ interface_protocol_control(net_datalink_protocol* _protocol, int32 option,
|
|||||||
} else
|
} else
|
||||||
oldNetmask = address;
|
oldNetmask = address;
|
||||||
|
|
||||||
sockaddr* broadcast = reallocate_address(
|
// reset the broadcast address if the address family has such
|
||||||
&interface->destination, request.ifr_addr.sa_len);
|
sockaddr* broadcast;
|
||||||
|
if (interface->domain->address_module->has_broadcast_address) {
|
||||||
|
broadcast = reallocate_address(&interface->destination,
|
||||||
|
request.ifr_addr.sa_len);
|
||||||
|
} else {
|
||||||
|
broadcast = NULL;
|
||||||
|
free_address(&interface->destination);
|
||||||
|
}
|
||||||
|
|
||||||
interface->domain->address_module->set_to_defaults(
|
interface->domain->address_module->set_to_defaults(
|
||||||
netmask, broadcast, interface->address, oldNetmask);
|
netmask, broadcast, interface->address, oldNetmask);
|
||||||
@@ -923,6 +971,7 @@ net_datalink_protocol_module_info gDatalinkInterfaceProtocolModule = {
|
|||||||
interface_protocol_init,
|
interface_protocol_init,
|
||||||
interface_protocol_uninit,
|
interface_protocol_uninit,
|
||||||
interface_protocol_send_data,
|
interface_protocol_send_data,
|
||||||
|
NULL, // receive_data
|
||||||
interface_protocol_up,
|
interface_protocol_up,
|
||||||
interface_protocol_down,
|
interface_protocol_down,
|
||||||
interface_protocol_control,
|
interface_protocol_control,
|
||||||
|
|||||||
@@ -1038,6 +1038,7 @@ copy_metadata(net_buffer* destination, const net_buffer* source)
|
|||||||
destination->interface = source->interface;
|
destination->interface = source->interface;
|
||||||
destination->offset = source->offset;
|
destination->offset = source->offset;
|
||||||
destination->protocol = source->protocol;
|
destination->protocol = source->protocol;
|
||||||
|
destination->hoplimit = source->hoplimit;
|
||||||
destination->type = source->type;
|
destination->type = source->type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -813,11 +813,17 @@ init_stack()
|
|||||||
// TODO: for now!
|
// TODO: for now!
|
||||||
register_domain_datalink_protocols(AF_INET, IFT_LOOP,
|
register_domain_datalink_protocols(AF_INET, IFT_LOOP,
|
||||||
"network/datalink_protocols/loopback_frame/v1", NULL);
|
"network/datalink_protocols/loopback_frame/v1", NULL);
|
||||||
|
register_domain_datalink_protocols(AF_INET6, IFT_LOOP,
|
||||||
|
"network/datalink_protocols/loopback_frame/v1", NULL);
|
||||||
register_domain_datalink_protocols(AF_INET, IFT_ETHER,
|
register_domain_datalink_protocols(AF_INET, IFT_ETHER,
|
||||||
"network/datalink_protocols/ipv4_datagram/v1",
|
"network/datalink_protocols/ipv4_datagram/v1",
|
||||||
"network/datalink_protocols/arp/v1",
|
"network/datalink_protocols/arp/v1",
|
||||||
"network/datalink_protocols/ethernet_frame/v1",
|
"network/datalink_protocols/ethernet_frame/v1",
|
||||||
NULL);
|
NULL);
|
||||||
|
register_domain_datalink_protocols(AF_INET6, IFT_ETHER,
|
||||||
|
"network/datalink_protocols/ipv6_datagram/v1",
|
||||||
|
"network/datalink_protocols/ethernet_frame/v1",
|
||||||
|
NULL);
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user