* 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
This commit is contained in:
Axel Dörfler 2009-12-03 14:31:39 +00:00
parent 207f71773b
commit 751ce9e228
3 changed files with 75 additions and 40 deletions

View File

@ -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);

View File

@ -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

View File

@ -20,6 +20,7 @@
#include <util/AutoLock.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_media.h>
#include <net/route.h>
#include <sys/sockio.h>
@ -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,