From 751ce9e228a278970a492fead1ecedbfab453d2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Thu, 3 Dec 2009 14:31:39 +0000 Subject: [PATCH] * Removed the interface fallback from the datalink module's is_local_address(). * Instead, added a new function is_local_link_address() which returns the interface with the matching link level address, and can additionally test for unconfigured interfaces. * Merged the two versions of fill_sockaddr_in() together in ipv4.cpp. * ipv4 now uses the new is_local_link_address() function to figure out whether the received packet should be processed or not. This should fix a few DHCP issues with multiple and configured interfaces as recently explained on the mailing list. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@34466 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/net/net_datalink.h | 6 +- .../kernel/network/protocols/ipv4/ipv4.cpp | 46 ++++++-------- src/add-ons/kernel/network/stack/datalink.cpp | 63 +++++++++++++++---- 3 files changed, 75 insertions(+), 40 deletions(-) diff --git a/headers/private/net/net_datalink.h b/headers/private/net/net_datalink.h index 196bed4611..b85108eab2 100644 --- a/headers/private/net/net_datalink.h +++ b/headers/private/net/net_datalink.h @@ -70,9 +70,11 @@ struct net_datalink_module_info { struct net_domain *domain, struct net_buffer *buffer); bool (*is_local_address)(struct net_domain *domain, - const struct sockaddr *address, - net_interface **_interface, + const struct sockaddr *address, net_interface **_interface, uint32 *_matchedType); + bool (*is_local_link_address)(struct net_domain *domain, bool unconfigured, + const struct sockaddr *address, net_interface **_interface); + net_interface *(*get_interface)(struct net_domain *domain, uint32 index); net_interface *(*get_interface_with_address)(struct net_domain *domain, const struct sockaddr *address); diff --git a/src/add-ons/kernel/network/protocols/ipv4/ipv4.cpp b/src/add-ons/kernel/network/protocols/ipv4/ipv4.cpp index 2b30a085d5..9c5c8f4a46 100644 --- a/src/add-ons/kernel/network/protocols/ipv4/ipv4.cpp +++ b/src/add-ons/kernel/network/protocols/ipv4/ipv4.cpp @@ -750,13 +750,14 @@ raw_receive_data(net_buffer* buffer) } -static sockaddr* -fill_sockaddr_in(sockaddr_in* destination, const in_addr &source) +static inline sockaddr* +fill_sockaddr_in(sockaddr_in* target, in_addr_t address) { - memset(destination, 0, sizeof(sockaddr_in)); - destination->sin_family = AF_INET; - destination->sin_addr = source; - return (sockaddr*)destination; + target->sin_family = AF_INET; + target->sin_len = sizeof(sockaddr_in); + target->sin_port = 0; + target->sin_addr.s_addr = address; + return (sockaddr*)target; } @@ -770,7 +771,7 @@ IPv4Multicast::JoinGroup(IPv4GroupInterface* state) status_t status = interface->first_info->join_multicast( interface->first_protocol, - fill_sockaddr_in(&groupAddr, state->Address())); + fill_sockaddr_in(&groupAddr, state->Address().s_addr)); if (status != B_OK) return status; @@ -791,7 +792,7 @@ IPv4Multicast::LeaveGroup(IPv4GroupInterface* state) return interface->first_protocol->module->join_multicast( interface->first_protocol, - fill_sockaddr_in(&groupAddr, state->Address())); + fill_sockaddr_in(&groupAddr, state->Address().s_addr)); } @@ -816,17 +817,6 @@ receiving_protocol(uint8 protocol) } -static inline sockaddr* -fill_sockaddr_in(sockaddr_in* target, in_addr_t address) -{ - memset(target, 0, sizeof(sockaddr_in)); - target->sin_family = AF_INET; - target->sin_len = sizeof(sockaddr_in); - target->sin_addr.s_addr = address; - return (sockaddr*)target; -} - - static status_t ipv4_delta_group(IPv4GroupInterface* group, int option, net_interface* interface, const in_addr* sourceAddr) @@ -1572,24 +1562,24 @@ ipv4_receive_data(net_buffer* buffer) if (gBufferModule->checksum(buffer, 0, headerLength, true) != 0) return B_BAD_DATA; - struct sockaddr_in& source = *(struct sockaddr_in*)buffer->source; - struct sockaddr_in& destination = *(struct sockaddr_in*)buffer->destination; - - fill_sockaddr_in(&source, header.source); - fill_sockaddr_in(&destination, header.destination); - // lower layers notion of Broadcast or Multicast have no relevance to us buffer->flags &= ~(MSG_BCAST | MSG_MCAST); + sockaddr_in destination; + fill_sockaddr_in(&destination, header.destination); + if (header.destination == INADDR_BROADCAST) { buffer->flags |= MSG_BCAST; } else if (IN_MULTICAST(ntohl(header.destination))) { 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, &matchedAddressType)) { + &buffer->interface, &matchedAddressType) + && !sDatalinkModule->is_local_link_address(sDomain, true, + buffer->destination, &buffer->interface)) { TRACE(" ReceiveData(): packet was not for us %lx -> %lx", ntohl(header.source), ntohl(header.destination)); return B_ERROR; @@ -1599,6 +1589,10 @@ ipv4_receive_data(net_buffer* buffer) buffer->flags |= matchedAddressType; } + // set net_buffer's source/destination address + fill_sockaddr_in((struct sockaddr_in*)buffer->source, header.source); + memcpy(buffer->destination, &destination, sizeof(sockaddr_in)); + uint8 protocol = buffer->protocol = header.protocol; // remove any trailing/padding data diff --git a/src/add-ons/kernel/network/stack/datalink.cpp b/src/add-ons/kernel/network/stack/datalink.cpp index fc9e20d2e8..e8e6ca5e49 100644 --- a/src/add-ons/kernel/network/stack/datalink.cpp +++ b/src/add-ons/kernel/network/stack/datalink.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -399,8 +400,8 @@ datalink_send_datagram(net_protocol* protocol, net_domain* domain, } -/*! - Tests if \a address is a local address in the domain. +/*! Tests if \a address is a local address in the domain. + \param _interface will be set to the interface belonging to that address if non-NULL. \param _matchedType will be set to either zero or MSG_BCAST if non-NULL. @@ -416,7 +417,6 @@ datalink_is_local_address(net_domain* _domain, const struct sockaddr* address, RecursiveLocker locker(domain->lock); net_interface* interface = NULL; - net_interface* fallback = NULL; uint32 matchedType = 0; while (true) { @@ -424,10 +424,8 @@ datalink_is_local_address(net_domain* _domain, const struct sockaddr* address, &domain->interfaces, interface); if (interface == NULL) break; - if (interface->address == NULL) { - fallback = interface; + if (interface->address == NULL) continue; - } // check for matching unicast address first if (domain->address_module->equal_addresses(interface->address, address)) @@ -436,7 +434,7 @@ datalink_is_local_address(net_domain* _domain, const struct sockaddr* address, // check for matching broadcast address if interface supports // broadcasting (IFF_BROADCAST is a link-level flag, so it is // a property of the device) - if ((interface->device->flags & IFF_BROADCAST) + if ((interface->device->flags & IFF_BROADCAST) != 0 && domain->address_module->equal_addresses(interface->destination, address)) { matchedType = MSG_BCAST; @@ -444,11 +442,8 @@ datalink_is_local_address(net_domain* _domain, const struct sockaddr* address, } } - if (interface == NULL) { - interface = fallback; - if (interface == NULL) - return false; - } + if (interface == NULL) + return false; if (_interface != NULL) *_interface = interface; @@ -458,6 +453,49 @@ datalink_is_local_address(net_domain* _domain, const struct sockaddr* address, } +/*! Tests if \a address is a local link address in the domain. + + \param unconfigured only unconfigured interfaces are taken into account. + \param _interface will be set to the interface belonging to that address + if non-NULL. +*/ +bool +datalink_is_local_link_address(net_domain* _domain, bool unconfigured, + const struct sockaddr* address, net_interface** _interface) +{ + net_domain_private* domain = (net_domain_private*)_domain; + if (domain == NULL || address == NULL || address->sa_family != AF_LINK) + return false; + + RecursiveLocker locker(domain->lock); + + sockaddr_dl& linkAddress = *(sockaddr_dl*)address; + net_interface* interface = NULL; + + while (true) { + interface = (net_interface*)list_get_next_item( + &domain->interfaces, interface); + if (interface == NULL) + break; + + if (unconfigured && interface->address != NULL + && (interface->flags & IFF_CONFIGURING) == 0) + continue; + + if (linkAddress.sdl_alen == interface->device->address.length + && memcmp(LLADDR(&linkAddress), interface->device->address.data, + linkAddress.sdl_alen) == 0) { + // link address matches + if (_interface != NULL) + *_interface = interface; + return true; + } + } + + return false; +} + + net_interface* datalink_get_interface_with_address(net_domain* _domain, const sockaddr* address) @@ -859,6 +897,7 @@ net_datalink_module_info gNetDatalinkModule = { datalink_send_data, datalink_send_datagram, datalink_is_local_address, + datalink_is_local_link_address, datalink_get_interface, datalink_get_interface_with_address,