* 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:
parent
207f71773b
commit
751ce9e228
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user