* 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:
Axel Dörfler
2010-08-11 12:44:38 +00:00
parent 7ea3a2b029
commit 3794b8e560
4 changed files with 284 additions and 203 deletions
@@ -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;