From 3794b8e560f691d50598e0dccf2b6aeba8e178eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Wed, 11 Aug 2010 12:44:38 +0000 Subject: [PATCH] * 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 --- .../ipv6_datagram/ipv6_datagram.cpp | 313 +++++++++++------- .../kernel/network/protocols/icmp6/icmp6.cpp | 44 ++- .../kernel/network/protocols/ipv6/ipv6.cpp | 128 +++---- .../network/protocols/ipv6/ipv6_address.cpp | 2 +- 4 files changed, 284 insertions(+), 203 deletions(-) diff --git a/src/add-ons/kernel/network/datalink_protocols/ipv6_datagram/ipv6_datagram.cpp b/src/add-ons/kernel/network/datalink_protocols/ipv6_datagram/ipv6_datagram.cpp index 23713e34bf..be8556aef9 100644 --- a/src/add-ons/kernel/network/datalink_protocols/ipv6_datagram/ipv6_datagram.cpp +++ b/src/add-ons/kernel/network/datalink_protocols/ipv6_datagram/ipv6_datagram.cpp @@ -28,7 +28,7 @@ #include #include #include - +#include #include #include @@ -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}, {} diff --git a/src/add-ons/kernel/network/protocols/icmp6/icmp6.cpp b/src/add-ons/kernel/network/protocols/icmp6/icmp6.cpp index 9e2221c761..d800811b31 100644 --- a/src/add-ons/kernel/network/protocols/icmp6/icmp6.cpp +++ b/src/add-ons/kernel/network/protocols/icmp6/icmp6.cpp @@ -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 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() diff --git a/src/add-ons/kernel/network/protocols/ipv6/ipv6.cpp b/src/add-ons/kernel/network/protocols/ipv6/ipv6.cpp index a3fb913de3..b76bc6badc 100644 --- a/src/add-ons/kernel/network/protocols/ipv6/ipv6.cpp +++ b/src/add-ons/kernel/network/protocols/ipv6/ipv6.cpp @@ -11,7 +11,6 @@ #include "ipv6_address.h" #include "ipv6_utils.h" #include "multicast.h" -#include "../../stack/domains.h" #include #include @@ -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; } diff --git a/src/add-ons/kernel/network/protocols/ipv6/ipv6_address.cpp b/src/add-ons/kernel/network/protocols/ipv6/ipv6_address.cpp index 32cefd7dc3..cf13dc39dc 100644 --- a/src/add-ons/kernel/network/protocols/ipv6/ipv6_address.cpp +++ b/src/add-ons/kernel/network/protocols/ipv6/ipv6_address.cpp @@ -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;