* Applied Atis latest changes to the IPv6 related modules. This brings them back
into a working state after the latest stack changes. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@38021 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -28,7 +28,7 @@
|
||||
#include <net/if.h>
|
||||
#include <net/if_types.h>
|
||||
#include <net/if_dl.h>
|
||||
|
||||
#include <sys/sockio.h>
|
||||
#include <new>
|
||||
|
||||
#include <ipv6/jenkins.h>
|
||||
@@ -46,6 +46,7 @@
|
||||
|
||||
struct ipv6_datalink_protocol : net_datalink_protocol {
|
||||
sockaddr_dl hardware_address;
|
||||
in6_addr local_address;
|
||||
};
|
||||
|
||||
|
||||
@@ -54,8 +55,9 @@ static void ndp_timer(struct net_timer* timer, void* data);
|
||||
|
||||
net_buffer_module_info* gBufferModule;
|
||||
static net_stack_module_info* sStackModule;
|
||||
static net_datalink_module_info* sDatalinkModule;
|
||||
static net_protocol_module_info* sIPv6Module;
|
||||
net_protocol* sIPv6Protocol;
|
||||
static net_protocol* sIPv6Protocol;
|
||||
static hash_table* sCache;
|
||||
static mutex sCacheLock;
|
||||
static const net_buffer* kDeletedBuffer = (net_buffer*)~0;
|
||||
@@ -75,7 +77,7 @@ struct neighbor_discovery_header {
|
||||
in6_addr target_address;
|
||||
|
||||
// This part is specific for Ethernet;
|
||||
// also, the could be more than one option in theory.
|
||||
// also, theoretically there could be more than one option.
|
||||
uint8 option_type;
|
||||
uint8 option_length;
|
||||
uint8 link_address[ETHER_ADDRESS_LENGTH];
|
||||
@@ -499,25 +501,115 @@ ndp_update_entry(const in6_addr& protocolAddress, sockaddr_dl* hardwareAddress,
|
||||
}
|
||||
|
||||
|
||||
/*! Creates a permanent local entry for the interface belonging to this protocol.
|
||||
You need to hold the cache lock when calling this function.
|
||||
*/
|
||||
static status_t
|
||||
ndp_update_local(ipv6_datalink_protocol* protocol)
|
||||
static void
|
||||
ndp_remove_local_entry(ipv6_datalink_protocol* protocol, const sockaddr* local,
|
||||
bool updateLocalAddress)
|
||||
{
|
||||
ASSERT_LOCKED_MUTEX(&sCacheLock);
|
||||
in6_addr inetAddress;
|
||||
|
||||
if (local == NULL) {
|
||||
// interface has not yet been set
|
||||
memset(&inetAddress, 0, sizeof(in6_addr));
|
||||
} else {
|
||||
memcpy(&inetAddress, &((sockaddr_in6*)local)->sin6_addr,
|
||||
sizeof(in6_addr));
|
||||
|
||||
// leave the NS multicast address
|
||||
sockaddr_in6 multicast;
|
||||
ipv6_to_solicited_multicast(&multicast, inetAddress);
|
||||
|
||||
struct ipv6_mreq mreq;
|
||||
memcpy(&mreq.ipv6mr_multiaddr, &multicast.sin6_addr, sizeof(in6_addr));
|
||||
mreq.ipv6mr_interface = protocol->interface->index;
|
||||
|
||||
if (sIPv6Protocol != NULL) {
|
||||
sIPv6Module->setsockopt(sIPv6Protocol, IPPROTO_IPV6,
|
||||
IPV6_LEAVE_GROUP, &mreq, sizeof(mreq));
|
||||
}
|
||||
}
|
||||
|
||||
// TRACE(("%s(): address %s\n", __FUNCTION__, inet6_to_string(inetAddress)));
|
||||
|
||||
MutexLocker locker(sCacheLock);
|
||||
|
||||
ndp_entry* entry = ndp_entry::Lookup(inetAddress);
|
||||
if (entry != NULL) {
|
||||
hash_remove(sCache, entry);
|
||||
entry->flags |= NDP_FLAG_REMOVED;
|
||||
}
|
||||
|
||||
if (updateLocalAddress && protocol->local_address == inetAddress) {
|
||||
// find new local sender address
|
||||
memset(&protocol->local_address, 0, sizeof(in6_addr));
|
||||
|
||||
net_interface_address* address = NULL;
|
||||
while (sDatalinkModule->get_next_interface_address(protocol->interface,
|
||||
&address)) {
|
||||
if (address->local == NULL || address->local->sa_family != AF_INET6)
|
||||
continue;
|
||||
|
||||
memcpy(&protocol->local_address,
|
||||
&((sockaddr_in6*)address->local)->sin6_addr, sizeof(in6_addr));
|
||||
}
|
||||
}
|
||||
|
||||
locker.Unlock();
|
||||
delete entry;
|
||||
}
|
||||
|
||||
|
||||
/*! Removes all entries belonging to the local interface of the \a procotol
|
||||
given.
|
||||
*/
|
||||
static void
|
||||
ndp_remove_local(ipv6_datalink_protocol* protocol)
|
||||
{
|
||||
net_interface_address* address = NULL;
|
||||
while (sDatalinkModule->get_next_interface_address(protocol->interface,
|
||||
&address)) {
|
||||
if (address->local == NULL || address->local->sa_family != AF_INET6)
|
||||
continue;
|
||||
|
||||
ndp_remove_local_entry(protocol, address->local, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
ndp_set_local_entry(ipv6_datalink_protocol* protocol, const sockaddr* local)
|
||||
{
|
||||
MutexLocker locker(sCacheLock);
|
||||
|
||||
net_interface* interface = protocol->interface;
|
||||
in6_addr inet6Address;
|
||||
in6_addr inetAddress;
|
||||
|
||||
if (interface->address == NULL) {
|
||||
if (local == NULL) {
|
||||
// interface has not yet been set
|
||||
memset(&inet6Address, 0, sizeof(in6_addr));
|
||||
memset(&inetAddress, 0, sizeof(in6_addr));
|
||||
} else {
|
||||
memcpy(&inet6Address,
|
||||
&((sockaddr_in6*)interface->address)->sin6_addr, sizeof(in6_addr));
|
||||
memcpy(&inetAddress,
|
||||
&((sockaddr_in6*)local)->sin6_addr,
|
||||
sizeof(in6_addr));
|
||||
|
||||
// join multicast address for listening to NS packets
|
||||
sockaddr_in6 multicast;
|
||||
ipv6_to_solicited_multicast(&multicast, inetAddress);
|
||||
|
||||
struct ipv6_mreq mreq;
|
||||
memcpy(&mreq.ipv6mr_multiaddr, &multicast.sin6_addr, sizeof(in6_addr));
|
||||
mreq.ipv6mr_interface = protocol->interface->index;
|
||||
|
||||
if (sIPv6Protocol != NULL) {
|
||||
sIPv6Module->setsockopt(sIPv6Protocol, IPPROTO_IPV6,
|
||||
IPV6_JOIN_GROUP, &mreq, sizeof(mreq));
|
||||
}
|
||||
}
|
||||
|
||||
// TRACE(("%s(): address %s\n", __FUNCTION__, inet6_to_string(inetAddress)));
|
||||
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(&protocol->local_address))
|
||||
memcpy(&protocol->local_address, &inetAddress, sizeof(in6_addr));
|
||||
|
||||
sockaddr_dl address;
|
||||
address.sdl_len = sizeof(sockaddr_dl);
|
||||
address.sdl_family = AF_LINK;
|
||||
@@ -532,7 +624,7 @@ ndp_update_local(ipv6_datalink_protocol* protocol)
|
||||
// cache the address in our protocol
|
||||
|
||||
ndp_entry* entry;
|
||||
status_t status = ndp_update_entry(inet6Address, &address,
|
||||
status_t status = ndp_update_entry(inetAddress, &address,
|
||||
NDP_FLAG_LOCAL | NDP_FLAG_PERMANENT, &entry);
|
||||
if (status == B_OK)
|
||||
entry->protocol = protocol;
|
||||
@@ -541,6 +633,35 @@ ndp_update_local(ipv6_datalink_protocol* protocol)
|
||||
}
|
||||
|
||||
|
||||
/*! Creates permanent local entries for all addresses of the interface belonging
|
||||
to this protocol.
|
||||
Returns an error if no entry could be added.
|
||||
*/
|
||||
static status_t
|
||||
ndp_update_local(ipv6_datalink_protocol* protocol)
|
||||
{
|
||||
memset(&protocol->local_address, 0, sizeof(in6_addr));
|
||||
|
||||
ssize_t count = 0;
|
||||
|
||||
net_interface_address* address = NULL;
|
||||
while (sDatalinkModule->get_next_interface_address(protocol->interface,
|
||||
&address)) {
|
||||
if (address->local == NULL || address->local->sa_family != AF_INET6)
|
||||
continue;
|
||||
|
||||
if (ndp_set_local_entry(protocol, address->local) == B_OK) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
return ndp_set_local_entry(protocol, NULL);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
ndp_receive_solicitation(net_buffer* buffer, bool* reuseBuffer)
|
||||
{
|
||||
@@ -778,7 +899,7 @@ ndp_timer(struct net_timer* timer, void* data)
|
||||
|
||||
|
||||
static status_t
|
||||
ndp_start_resolve(net_datalink_protocol* protocol, const in6_addr& address,
|
||||
ndp_start_resolve(ipv6_datalink_protocol* protocol, const in6_addr& address,
|
||||
ndp_entry** _entry)
|
||||
{
|
||||
ASSERT_LOCKED_MUTEX(&sCacheLock);
|
||||
@@ -808,8 +929,9 @@ ndp_start_resolve(net_datalink_protocol* protocol, const in6_addr& address,
|
||||
|
||||
// prepare source and target addresses
|
||||
|
||||
sockaddr_in6* source = (sockaddr_in6*)buffer->source;
|
||||
ipv6_to_sockaddr(source, ((sockaddr_in6*)interface->address)->sin6_addr);
|
||||
sockaddr_in6* source = (sockaddr_in6*)buffer->source;
|
||||
ipv6_to_sockaddr(source, protocol->local_address);
|
||||
// protocol->local_address
|
||||
|
||||
sockaddr_in6* destination = (sockaddr_in6*)buffer->destination;
|
||||
ipv6_to_solicited_multicast(destination, address);
|
||||
@@ -868,30 +990,25 @@ ndp_start_resolve(net_datalink_protocol* protocol, const in6_addr& address,
|
||||
|
||||
|
||||
static status_t
|
||||
ipv6_datalink_init(net_interface* interface, net_datalink_protocol** _protocol)
|
||||
ipv6_datalink_init(net_interface* interface, net_domain* domain,
|
||||
net_datalink_protocol** _protocol)
|
||||
{
|
||||
if (interface->domain->family != AF_INET6)
|
||||
if (domain->family != AF_INET6)
|
||||
return B_BAD_TYPE;
|
||||
|
||||
// While the loopback doesn't get a header to mux protocols,
|
||||
// we let it do all of the registration work.
|
||||
if (interface->device->type == IFT_LOOP)
|
||||
return B_BAD_TYPE;
|
||||
status_t status = sStackModule->register_domain_device_handler(
|
||||
interface->device, B_NET_FRAME_TYPE(IFT_ETHER, ETHER_TYPE_IPV6), domain);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
ipv6_datalink_protocol* protocol = new(std::nothrow) ipv6_datalink_protocol;
|
||||
if (protocol == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
memset(&protocol->hardware_address, 0, sizeof(sockaddr_dl));
|
||||
|
||||
status_t status = sStackModule->register_domain_device_handler(
|
||||
interface->device, B_NET_FRAME_TYPE_IPV6, interface->domain);
|
||||
if (status != B_OK)
|
||||
delete protocol;
|
||||
else
|
||||
*_protocol = protocol;
|
||||
|
||||
return status;
|
||||
memset(&protocol->local_address, 0, sizeof(in6_addr));
|
||||
*_protocol = protocol;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -899,9 +1016,10 @@ static status_t
|
||||
ipv6_datalink_uninit(net_datalink_protocol* protocol)
|
||||
{
|
||||
sStackModule->unregister_device_handler(protocol->interface->device,
|
||||
B_NET_FRAME_TYPE_IPV6);
|
||||
B_NET_FRAME_TYPE(IFT_ETHER, ETHER_TYPE_IPV6));
|
||||
|
||||
delete protocol;
|
||||
return B_OK;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -950,136 +1068,87 @@ ipv6_datalink_send_data(net_datalink_protocol* _protocol, net_buffer* buffer)
|
||||
}
|
||||
|
||||
|
||||
|
||||
static status_t
|
||||
ipv6_datalink_up(net_datalink_protocol* _protocol)
|
||||
{
|
||||
ipv6_datalink_protocol* protocol = (ipv6_datalink_protocol*)_protocol;
|
||||
status_t status = protocol->next->module->interface_up(protocol->next);
|
||||
if (status < B_OK)
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
// join multicast address for listening to NS packets
|
||||
|
||||
// REVIEWME: can I rely on this function being called every time
|
||||
// when interfae address changes?
|
||||
|
||||
if (protocol->interface->address != NULL) {
|
||||
sockaddr_in6& address = *(sockaddr_in6*)protocol->interface->address;
|
||||
sockaddr_in6 multicast;
|
||||
ipv6_to_solicited_multicast(&multicast, address.sin6_addr);
|
||||
|
||||
struct ipv6_mreq mreq;
|
||||
memcpy(&mreq.ipv6mr_multiaddr, &multicast.sin6_addr, sizeof(in6_addr));
|
||||
mreq.ipv6mr_interface = protocol->interface->index;
|
||||
|
||||
if (sIPv6Protocol != NULL) {
|
||||
sIPv6Module->setsockopt(sIPv6Protocol, IPPROTO_IPV6,
|
||||
IPV6_JOIN_GROUP, &mreq, sizeof(mreq));
|
||||
}
|
||||
}
|
||||
|
||||
// cache this device's address for later use
|
||||
|
||||
mutex_lock(&sCacheLock);
|
||||
status = ndp_update_local(protocol);
|
||||
mutex_unlock(&sCacheLock);
|
||||
|
||||
if (status < B_OK) {
|
||||
if (status != B_OK) {
|
||||
protocol->next->module->interface_down(protocol->next);
|
||||
return status;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ipv6_datalink_down(net_datalink_protocol* protocol)
|
||||
ipv6_datalink_down(net_datalink_protocol *protocol)
|
||||
{
|
||||
// leave the NS multicast address
|
||||
|
||||
// REVIEWME: can I rely on this function being called every time
|
||||
// when interface address changes?
|
||||
|
||||
if (protocol->interface->address != NULL) {
|
||||
sockaddr_in6& address = *(sockaddr_in6*)protocol->interface->address;
|
||||
sockaddr_in6 multicast;
|
||||
ipv6_to_solicited_multicast(&multicast, address.sin6_addr);
|
||||
|
||||
struct ipv6_mreq mreq;
|
||||
memcpy(&mreq.ipv6mr_multiaddr, &multicast.sin6_addr, sizeof(in6_addr));
|
||||
mreq.ipv6mr_interface = protocol->interface->index;
|
||||
|
||||
if (sIPv6Protocol != NULL) {
|
||||
sIPv6Module->setsockopt(sIPv6Protocol, IPPROTO_IPV6,
|
||||
IPV6_LEAVE_GROUP, &mreq, sizeof(mreq));
|
||||
}
|
||||
}
|
||||
|
||||
// remove local NDP entry from the cache
|
||||
|
||||
if (protocol->interface->address != NULL) {
|
||||
MutexLocker locker(sCacheLock);
|
||||
|
||||
ndp_entry* entry = ndp_entry::Lookup(
|
||||
((sockaddr_in6*)protocol->interface->address)->sin6_addr);
|
||||
if (entry != NULL) {
|
||||
hash_remove(sCache, entry);
|
||||
entry->flags |= NDP_FLAG_REMOVED;
|
||||
locker.Unlock();
|
||||
|
||||
delete entry;
|
||||
}
|
||||
}
|
||||
// remove local NDP entries from the cache
|
||||
ndp_remove_local((ipv6_datalink_protocol*)protocol);
|
||||
|
||||
protocol->next->module->interface_down(protocol->next);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ipv6_datalink_change_address(net_datalink_protocol* protocol,
|
||||
ipv6_datalink_change_address(net_datalink_protocol* _protocol,
|
||||
net_interface_address* address, int32 option,
|
||||
const struct sockaddr* oldAddress, const struct sockaddr* newAddress)
|
||||
{
|
||||
#if 0
|
||||
ipv6_datalink_protocol* protocol = (ipv6_datalink_protocol*)_protocol;
|
||||
switch (option) {
|
||||
case SIOCSIFADDR:
|
||||
case SIOCAIFADDR:
|
||||
case SIOCDIFADDR:
|
||||
// Those are the options we handle
|
||||
if ((protocol->interface->flags & IFF_UP) != 0) {
|
||||
// Update ARP entry for the local address
|
||||
// Update NDP entry for the local address
|
||||
|
||||
if (newAddress != NULL && newAddress->sa_family == AF_INET6) {
|
||||
status_t status = arp_set_local_entry(protocol, newAddress);
|
||||
status_t status = ndp_set_local_entry(protocol, newAddress);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
// add IPv6 remove multicast route (ff00::/8)
|
||||
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;
|
||||
// add IPv6 multicast route (ff00::/8)
|
||||
sockaddr_in6 socketAddress;
|
||||
memset(&socketAddress, 0, sizeof(sockaddr_in6));
|
||||
socketAddress.sin6_family = AF_INET6;
|
||||
socketAddress.sin6_len = sizeof(sockaddr_in6);
|
||||
socketAddress.sin6_addr.s6_addr[0] = 0xff;
|
||||
|
||||
net_route route;
|
||||
memset(&route, 0, sizeof(net_route));
|
||||
route.destination = (sockaddr*)&socketAddress;
|
||||
route.mask = (sockaddr*)&socketAddress;
|
||||
route.flags = 0;
|
||||
add_route(interface->domain, &route);
|
||||
sDatalinkModule->add_route(address->domain, &route);
|
||||
}
|
||||
|
||||
if (oldAddress != NULL && oldAddress->sa_family == AF_INET6) {
|
||||
arp_remove_local_entry(protocol, oldAddress, true);
|
||||
ndp_remove_local_entry(protocol, oldAddress, true);
|
||||
|
||||
// remove IPv6 remove multicast route (ff00::/8)
|
||||
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;
|
||||
// remove IPv6 multicast route (ff00::/8)
|
||||
sockaddr_in6 socketAddress;
|
||||
memset(&socketAddress, 0, sizeof(sockaddr_in6));
|
||||
socketAddress.sin6_family = AF_INET6;
|
||||
socketAddress.sin6_len = sizeof(sockaddr_in6);
|
||||
socketAddress.sin6_addr.s6_addr[0] = 0xff;
|
||||
|
||||
net_route route;
|
||||
memset(&route, 0, sizeof(net_route));
|
||||
route.destination = (sockaddr*)&socketAddress;
|
||||
route.mask = (sockaddr*)&socketAddress;
|
||||
route.flags = 0;
|
||||
remove_route(interface->domain, &route);
|
||||
sDatalinkModule->remove_route(address->domain, &route);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1087,7 +1156,6 @@ ipv6_datalink_change_address(net_datalink_protocol* protocol,
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
return protocol->next->module->change_address(protocol->next, address,
|
||||
option, oldAddress, newAddress);
|
||||
@@ -1176,6 +1244,7 @@ net_ndp_module_info gIPv6NDPModule = {
|
||||
|
||||
module_dependency module_dependencies[] = {
|
||||
{NET_STACK_MODULE_NAME, (module_info**)&sStackModule},
|
||||
{NET_DATALINK_MODULE_NAME, (module_info**)&sDatalinkModule},
|
||||
{NET_BUFFER_MODULE_NAME, (module_info**)&gBufferModule},
|
||||
{"network/protocols/ipv6/v1", (module_info**)&sIPv6Module},
|
||||
{}
|
||||
|
||||
@@ -199,11 +199,31 @@ icmp6_get_mtu(net_protocol *protocol, const struct sockaddr *address)
|
||||
}
|
||||
|
||||
|
||||
static net_domain*
|
||||
get_domain(struct net_buffer* buffer)
|
||||
{
|
||||
net_domain* domain;
|
||||
if (buffer->interface_address != NULL)
|
||||
domain = buffer->interface_address->domain;
|
||||
else
|
||||
domain = sStackModule->get_domain(buffer->source->sa_family);
|
||||
|
||||
if (domain == NULL || domain->module == NULL)
|
||||
return NULL;
|
||||
|
||||
return domain;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
icmp6_receive_data(net_buffer *buffer)
|
||||
{
|
||||
TRACE(("ICMPv6 received some data, buffer length %lu\n", buffer->size));
|
||||
|
||||
net_domain* domain = get_domain(buffer);
|
||||
if (domain == NULL)
|
||||
return B_ERROR;
|
||||
|
||||
NetBufferHeaderReader<icmp6_hdr> bufferHeader(buffer);
|
||||
if (bufferHeader.Status() < B_OK)
|
||||
return bufferHeader.Status();
|
||||
@@ -213,16 +233,6 @@ icmp6_receive_data(net_buffer *buffer)
|
||||
TRACE((" got type %u, code %u, checksum 0x%x\n", header.icmp6_type,
|
||||
header.icmp6_code, header.icmp6_cksum));
|
||||
|
||||
net_domain* domain;
|
||||
if (buffer->interface != NULL)
|
||||
domain = buffer->interface->domain;
|
||||
else
|
||||
domain = sStackModule->get_domain(buffer->source->sa_family);
|
||||
|
||||
// TODO: possible?
|
||||
if (domain == NULL || domain->module == NULL)
|
||||
return B_ERROR;
|
||||
|
||||
net_address_module_info* addressModule = domain->address_module;
|
||||
|
||||
// compute and check the checksum
|
||||
@@ -236,11 +246,11 @@ icmp6_receive_data(net_buffer *buffer)
|
||||
|
||||
case ICMP6_ECHO_REQUEST:
|
||||
{
|
||||
if (buffer->interface != NULL) {
|
||||
if (buffer->interface_address != NULL) {
|
||||
// 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))
|
||||
buffer->interface_address->local, buffer->destination))
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -288,15 +298,15 @@ icmp6_deliver_data(net_protocol *protocol, net_buffer *buffer)
|
||||
|
||||
|
||||
status_t
|
||||
icmp6_error(uint32 code, net_buffer *data)
|
||||
icmp6_error_received(net_error code, net_buffer* data)
|
||||
{
|
||||
return B_ERROR;
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
icmp6_error_reply(net_protocol *protocol, net_buffer *causedError, uint32 code,
|
||||
void *errorData)
|
||||
icmp6_error_reply(net_protocol* protocol, net_buffer* buffer, net_error error,
|
||||
net_error_data* errorData)
|
||||
{
|
||||
return B_ERROR;
|
||||
}
|
||||
@@ -367,7 +377,7 @@ net_protocol_module_info sICMP6Module = {
|
||||
icmp6_get_mtu,
|
||||
icmp6_receive_data,
|
||||
icmp6_deliver_data,
|
||||
icmp6_error,
|
||||
icmp6_error_received,
|
||||
icmp6_error_reply,
|
||||
NULL, // add_ancillary_data()
|
||||
NULL, // process_ancillary_data()
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#include "ipv6_address.h"
|
||||
#include "ipv6_utils.h"
|
||||
#include "multicast.h"
|
||||
#include "../../stack/domains.h"
|
||||
|
||||
#include <net_datalink.h>
|
||||
#include <net_datalink_protocol.h>
|
||||
@@ -105,7 +104,7 @@ struct ipv6_protocol : net_protocol {
|
||||
uint8 multicast_time_to_live;
|
||||
uint8 receive_hoplimit;
|
||||
uint8 receive_pktinfo;
|
||||
struct sockaddr* interface_address; // for IPV6_MULTICAST_IF
|
||||
struct sockaddr* multicast_address; // for IPV6_MULTICAST_IF
|
||||
|
||||
IPv6MulticastFilter multicast_filter;
|
||||
};
|
||||
@@ -237,11 +236,11 @@ deliver_multicast(net_protocol_module_info* module, net_buffer* buffer,
|
||||
MutexLocker _(sMulticastGroupsLock);
|
||||
|
||||
status_t status = B_OK;
|
||||
if (buffer->interface) {
|
||||
if (buffer->interface_address != NULL) {
|
||||
status = deliver_multicast(module, buffer, deliverToRaw,
|
||||
buffer->interface);
|
||||
buffer->interface_address->interface);
|
||||
} else {
|
||||
// REVIEWME: does this look ok?
|
||||
#if 0 // FIXME: multicast
|
||||
net_domain_private* domain = (net_domain_private*)sDomain;
|
||||
RecursiveLocker locker(domain->lock);
|
||||
|
||||
@@ -256,6 +255,7 @@ deliver_multicast(net_protocol_module_info* module, net_buffer* buffer,
|
||||
if (status < B_OK)
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return status;
|
||||
}
|
||||
@@ -280,7 +280,7 @@ raw_receive_data(net_buffer* buffer)
|
||||
RawSocket* raw = iterator.Next();
|
||||
|
||||
if (raw->Socket()->protocol == buffer->protocol)
|
||||
raw->SocketEnqueue(buffer);
|
||||
raw->EnqueueClone(buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -305,11 +305,8 @@ IPv6Multicast::JoinGroup(IPv6GroupInterface* state)
|
||||
MutexLocker _(sMulticastGroupsLock);
|
||||
|
||||
sockaddr_in6 groupAddr;
|
||||
net_interface* interface = state->Interface();
|
||||
|
||||
status_t status = interface->first_info->join_multicast(
|
||||
interface->first_protocol,
|
||||
fill_sockaddr_in6(&groupAddr, state->Address()));
|
||||
status_t status = sDatalinkModule->join_multicast(state->Interface(),
|
||||
sDomain, fill_sockaddr_in6(&groupAddr, state->Address()));
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
@@ -326,10 +323,7 @@ IPv6Multicast::LeaveGroup(IPv6GroupInterface* state)
|
||||
sMulticastState->Remove(state);
|
||||
|
||||
sockaddr_in6 groupAddr;
|
||||
net_interface* interface = state->Interface();
|
||||
|
||||
return interface->first_protocol->module->join_multicast(
|
||||
interface->first_protocol,
|
||||
return sDatalinkModule->leave_multicast(state->Interface(), sDomain,
|
||||
fill_sockaddr_in6(&groupAddr, state->Address()));
|
||||
}
|
||||
|
||||
@@ -460,7 +454,7 @@ ipv6_init_protocol(net_socket* socket)
|
||||
protocol->multicast_time_to_live = kDefaultMulticastTTL;
|
||||
protocol->receive_hoplimit = 0;
|
||||
protocol->receive_pktinfo = 0;
|
||||
protocol->interface_address = NULL;
|
||||
protocol->multicast_address = NULL;
|
||||
return protocol;
|
||||
}
|
||||
|
||||
@@ -471,7 +465,7 @@ ipv6_uninit_protocol(net_protocol* _protocol)
|
||||
ipv6_protocol* protocol = (ipv6_protocol*)_protocol;
|
||||
|
||||
delete protocol->raw;
|
||||
delete protocol->interface_address;
|
||||
delete protocol->multicast_address;
|
||||
delete protocol;
|
||||
return B_OK;
|
||||
}
|
||||
@@ -618,21 +612,21 @@ ipv6_setsockopt(net_protocol* _protocol, int level, int option,
|
||||
// Using the unspecifed address to remove the previous setting.
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(&address->sin6_addr)) {
|
||||
delete address;
|
||||
delete protocol->interface_address;
|
||||
protocol->interface_address = NULL;
|
||||
delete protocol->multicast_address;
|
||||
protocol->multicast_address = NULL;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
struct net_interface* interface
|
||||
= sDatalinkModule->get_interface_with_address(sDomain,
|
||||
(struct sockaddr*)address);
|
||||
= sDatalinkModule->get_interface_with_address(
|
||||
(sockaddr*)address);
|
||||
if (interface == NULL) {
|
||||
delete address;
|
||||
return EADDRNOTAVAIL;
|
||||
}
|
||||
|
||||
delete protocol->interface_address;
|
||||
protocol->interface_address = (struct sockaddr*)address;
|
||||
delete protocol->multicast_address;
|
||||
protocol->multicast_address = (struct sockaddr*)address;
|
||||
return B_OK;
|
||||
}
|
||||
if (option == IPV6_MULTICAST_HOPS) {
|
||||
@@ -743,7 +737,7 @@ ipv6_send_routed_data(net_protocol* _protocol, struct net_route* route,
|
||||
return B_BAD_VALUE;
|
||||
|
||||
ipv6_protocol* protocol = (ipv6_protocol*)_protocol;
|
||||
net_interface* interface = route->interface;
|
||||
net_interface* interface = route->interface_address->interface;
|
||||
uint8 protocolNumber;
|
||||
if (protocol != NULL && protocol->socket != NULL)
|
||||
protocolNumber = protocol->socket->protocol;
|
||||
@@ -817,12 +811,11 @@ ipv6_send_routed_data(net_protocol* _protocol, struct net_route* route,
|
||||
|
||||
uint32 mtu = route->mtu ? route->mtu : interface->mtu;
|
||||
if (buffer->size > mtu) {
|
||||
// we need to fragment the packet
|
||||
return EMSGSIZE; // TODO
|
||||
//return send_fragments(protocol, route, buffer, mtu);
|
||||
// TODO: we need to fragment the packet
|
||||
return EMSGSIZE;
|
||||
}
|
||||
|
||||
return sDatalinkModule->send_data(route, buffer);
|
||||
return sDatalinkModule->send_routed_data(route, buffer);
|
||||
}
|
||||
|
||||
|
||||
@@ -837,24 +830,26 @@ ipv6_send_data(net_protocol* _protocol, net_buffer* buffer)
|
||||
|
||||
// handle IPV6_MULTICAST_IF
|
||||
if (IN6_IS_ADDR_MULTICAST(&destination->sin6_addr)
|
||||
&& protocol->interface_address != NULL) {
|
||||
net_interface* interface
|
||||
= sDatalinkModule->get_interface_with_address(sDomain,
|
||||
protocol->interface_address);
|
||||
if (interface == NULL || (interface->flags & IFF_UP) == 0)
|
||||
&& protocol->multicast_address != NULL) {
|
||||
net_interface_address* address = sDatalinkModule->get_interface_address(
|
||||
protocol->multicast_address);
|
||||
if (address == NULL || (address->interface->flags & IFF_UP) == 0) {
|
||||
sDatalinkModule->put_interface_address(address);
|
||||
return EADDRNOTAVAIL;
|
||||
}
|
||||
|
||||
buffer->interface = interface;
|
||||
sDatalinkModule->put_interface_address(buffer->interface_address);
|
||||
buffer->interface_address = address;
|
||||
// the buffer takes over ownership of the address
|
||||
|
||||
net_route* route = sDatalinkModule->get_route(sDomain,
|
||||
interface->address);
|
||||
net_route* route = sDatalinkModule->get_route(sDomain, address->local);
|
||||
if (route == NULL)
|
||||
return ENETUNREACH;
|
||||
|
||||
return sDatalinkModule->send_data(route, buffer);
|
||||
return sDatalinkModule->send_routed_data(route, buffer);
|
||||
}
|
||||
|
||||
return sDatalinkModule->send_datagram(protocol, sDomain, buffer);
|
||||
return sDatalinkModule->send_data(protocol, sDomain, buffer);
|
||||
}
|
||||
|
||||
|
||||
@@ -876,7 +871,7 @@ ipv6_read_data(net_protocol* _protocol, size_t numBytes, uint32 flags,
|
||||
|
||||
TRACE_SK(protocol, "ReadData(%lu, 0x%lx)", numBytes, flags);
|
||||
|
||||
return raw->SocketDequeue(flags, _buffer);
|
||||
return raw->Dequeue(flags, _buffer);
|
||||
}
|
||||
|
||||
|
||||
@@ -910,7 +905,7 @@ ipv6_get_mtu(net_protocol* protocol, const struct sockaddr* address)
|
||||
if (route->mtu != 0)
|
||||
mtu = route->mtu;
|
||||
else
|
||||
mtu = route->interface->mtu;
|
||||
mtu = route->interface_address->interface->mtu;
|
||||
|
||||
sDatalinkModule->put_route(sDomain, route);
|
||||
// TODO: what about extension headers?
|
||||
@@ -947,18 +942,25 @@ ipv6_receive_data(net_buffer* buffer)
|
||||
if (IN6_IS_ADDR_MULTICAST(&destination.sin6_addr)) {
|
||||
buffer->flags |= MSG_MCAST;
|
||||
} else {
|
||||
uint32 matchedAddressType = 0;
|
||||
|
||||
// test if the packet is really for us
|
||||
if (!sDatalinkModule->is_local_address(sDomain, (sockaddr*)&destination,
|
||||
&buffer->interface, NULL)
|
||||
&buffer->interface_address, &matchedAddressType)
|
||||
&& !sDatalinkModule->is_local_link_address(sDomain, true,
|
||||
buffer->destination, &buffer->interface)) {
|
||||
buffer->destination, &buffer->interface_address)) {
|
||||
char srcbuf[INET6_ADDRSTRLEN];
|
||||
char dstbuf[INET6_ADDRSTRLEN];
|
||||
TRACE(" ReceiveData(): packet was not for us %s -> %s",
|
||||
TRACE(" ipv4_receive_data(): packet was not for us %s -> %s",
|
||||
ip6_sprintf(&header.Src(), srcbuf),
|
||||
ip6_sprintf(&header.Dst(), dstbuf));
|
||||
|
||||
// TODO: Send ICMPv6 error: Host unreachable
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
// copy over special address types (MSG_BCAST or MSG_MCAST):
|
||||
buffer->flags |= matchedAddressType;
|
||||
}
|
||||
|
||||
// set net_buffer's source/destination address
|
||||
@@ -981,8 +983,6 @@ ipv6_receive_data(net_buffer* buffer)
|
||||
// tell the buffer to preserve removed ipv6 header - may need it later
|
||||
gBufferModule->store_header(buffer);
|
||||
|
||||
TRACE("store_header for %p\n", buffer);
|
||||
|
||||
// remove ipv6 headers for now
|
||||
gBufferModule->remove_header(buffer, transportHeaderOffset);
|
||||
|
||||
@@ -996,7 +996,7 @@ ipv6_receive_data(net_buffer* buffer)
|
||||
}
|
||||
|
||||
if ((buffer->flags & MSG_MCAST) != 0) {
|
||||
// Unfortunely historical reasons dictate that the IP multicast
|
||||
// Unfortunately historical reasons dictate that the IP multicast
|
||||
// model be a little different from the unicast one. We deliver
|
||||
// this frame directly to all sockets registered with interest
|
||||
// for this multicast group.
|
||||
@@ -1015,7 +1015,7 @@ ipv6_deliver_data(net_protocol* _protocol, net_buffer* buffer)
|
||||
if (protocol->raw == NULL)
|
||||
return B_ERROR;
|
||||
|
||||
return protocol->raw->SocketEnqueue(buffer);
|
||||
return protocol->raw->EnqueueClone(buffer);
|
||||
}
|
||||
|
||||
|
||||
@@ -1047,27 +1047,26 @@ ipv6_process_ancillary_data_no_container(net_protocol* _protocol,
|
||||
if (msgControlLen < CMSG_SPACE(sizeof(int)))
|
||||
return B_NO_MEMORY;
|
||||
|
||||
TRACE("restore_header for %p\n", buffer);
|
||||
// '255' is the default value to use when extracting the real one fails
|
||||
int hopLimit = 255;
|
||||
|
||||
if (gBufferModule->stored_header_length(buffer)
|
||||
< (int)sizeof(ip6_hdr))
|
||||
return B_ERROR;
|
||||
|
||||
IPv6Header header;
|
||||
if (gBufferModule->restore_header(buffer, 0, &header, sizeof(ip6_hdr))
|
||||
!= B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
if (header.ProtocolVersion() != IPV6_VERSION)
|
||||
return B_ERROR;
|
||||
>= (int)sizeof(ip6_hdr)) {
|
||||
IPv6Header header;
|
||||
if (gBufferModule->restore_header(buffer, 0,
|
||||
&header, sizeof(ip6_hdr)) == B_OK
|
||||
&& header.ProtocolVersion() != IPV6_VERSION) {
|
||||
// header is OK, take hoplimit from it
|
||||
hopLimit = header.header.ip6_hlim;
|
||||
}
|
||||
}
|
||||
|
||||
cmsghdr* messageHeader = (cmsghdr*)((char*)msgControl + bytesWritten);
|
||||
messageHeader->cmsg_len = CMSG_LEN(sizeof(int));
|
||||
messageHeader->cmsg_level = IPPROTO_IPV6;
|
||||
messageHeader->cmsg_type = IPV6_HOPLIMIT;
|
||||
|
||||
int hoplimit = header.header.ip6_hlim;
|
||||
memcpy(CMSG_DATA(messageHeader), &hoplimit, sizeof(int));
|
||||
memcpy(CMSG_DATA(messageHeader), &hopLimit, sizeof(int));
|
||||
|
||||
bytesWritten += CMSG_SPACE(sizeof(int));
|
||||
msgControlLen -= CMSG_SPACE(sizeof(int));
|
||||
@@ -1088,8 +1087,11 @@ ipv6_process_ancillary_data_no_container(net_protocol* _protocol,
|
||||
memcpy(&pi.ipi6_addr,
|
||||
&((struct sockaddr_in6*)buffer->destination)->sin6_addr,
|
||||
sizeof(struct in6_addr));
|
||||
// REVIEWME: assume buffer->interface cannot be NULL
|
||||
pi.ipi6_ifindex = buffer->interface->index;
|
||||
if (buffer->interface_address != NULL
|
||||
&& buffer->interface_address->interface != NULL)
|
||||
pi.ipi6_ifindex = buffer->interface_address->interface->index;
|
||||
else
|
||||
pi.ipi6_ifindex = 0;
|
||||
memcpy(CMSG_DATA(messageHeader), &pi, sizeof(struct in6_pktinfo));
|
||||
|
||||
bytesWritten += CMSG_SPACE(sizeof(struct in6_pktinfo));
|
||||
@@ -1145,7 +1147,7 @@ err:
|
||||
mutex_destroy(&sReceivingProtocolLock);
|
||||
mutex_destroy(&sMulticastGroupsLock);
|
||||
mutex_destroy(&sRawSocketsLock);
|
||||
TRACE("init_ipv6: error, status=%u\n", status);
|
||||
TRACE("init_ipv6: error %s\n", strerror(status));
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
@@ -455,7 +455,7 @@ ipv6_set_to_empty_address(sockaddr *address)
|
||||
|
||||
static status_t
|
||||
ipv6_set_to_defaults(sockaddr *_defaultMask, sockaddr *_defaultBroadcast,
|
||||
sockaddr *_address, sockaddr *_mask)
|
||||
const sockaddr *_address, const sockaddr *_mask)
|
||||
{
|
||||
sockaddr_in6 *defaultMask = (sockaddr_in6 *)_defaultMask;
|
||||
sockaddr_in6 *address = (sockaddr_in6 *)_address;
|
||||
|
||||
Reference in New Issue
Block a user