* ARP no longer tries to resolve the target address in case of a link-level broadcast
(indicated by MSG_BCAST). * ARP should now be able to resolve addresses with an unconfigured interface as well. * datalink_is_local_address() now uses interfaces without an address as a fallback in case no more specific interface could be found. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@19460 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -263,11 +263,13 @@ static status_t
|
|||||||
arp_update_local(net_datalink_protocol *protocol)
|
arp_update_local(net_datalink_protocol *protocol)
|
||||||
{
|
{
|
||||||
net_interface *interface = protocol->interface;
|
net_interface *interface = protocol->interface;
|
||||||
|
in_addr_t inetAddress;
|
||||||
|
|
||||||
if (interface->address == NULL) {
|
if (interface->address == NULL) {
|
||||||
// interface has not yet been set
|
// interface has not yet been set
|
||||||
return B_OK;
|
inetAddress = INADDR_ANY;
|
||||||
}
|
} else
|
||||||
|
inetAddress = ((sockaddr_in *)interface->address)->sin_addr.s_addr;
|
||||||
|
|
||||||
sockaddr_dl address;
|
sockaddr_dl address;
|
||||||
address.sdl_len = sizeof(sockaddr_dl);
|
address.sdl_len = sizeof(sockaddr_dl);
|
||||||
@@ -280,8 +282,8 @@ arp_update_local(net_datalink_protocol *protocol)
|
|||||||
memcpy(LLADDR(&address), interface->device->address.data, address.sdl_alen);
|
memcpy(LLADDR(&address), interface->device->address.data, address.sdl_alen);
|
||||||
|
|
||||||
arp_entry *entry;
|
arp_entry *entry;
|
||||||
status_t status = arp_update_entry(((sockaddr_in *)interface->address)->sin_addr.s_addr,
|
status_t status = arp_update_entry(inetAddress, &address,
|
||||||
&address, ARP_FLAG_LOCAL | ARP_FLAG_PERMANENT, &entry);
|
ARP_FLAG_LOCAL | ARP_FLAG_PERMANENT, &entry);
|
||||||
if (status == B_OK)
|
if (status == B_OK)
|
||||||
entry->protocol = protocol;
|
entry->protocol = protocol;
|
||||||
|
|
||||||
@@ -560,7 +562,11 @@ arp_resolve(net_datalink_protocol *protocol, in_addr_t address, arp_entry **_ent
|
|||||||
header.opcode = htons(ARP_OPCODE_REQUEST);
|
header.opcode = htons(ARP_OPCODE_REQUEST);
|
||||||
|
|
||||||
memcpy(header.hardware_sender, device->address.data, ETHER_ADDRESS_LENGTH);
|
memcpy(header.hardware_sender, device->address.data, ETHER_ADDRESS_LENGTH);
|
||||||
header.protocol_sender = ((sockaddr_in *)protocol->interface->address)->sin_addr.s_addr;
|
if (protocol->interface->address != NULL)
|
||||||
|
header.protocol_sender = ((sockaddr_in *)protocol->interface->address)->sin_addr.s_addr;
|
||||||
|
else
|
||||||
|
header.protocol_sender = 0;
|
||||||
|
// TODO: test if this actually works - maybe we should use INADDR_BROADCAST instead
|
||||||
memset(header.hardware_target, 0, ETHER_ADDRESS_LENGTH);
|
memset(header.hardware_target, 0, ETHER_ADDRESS_LENGTH);
|
||||||
header.protocol_target = address;
|
header.protocol_target = address;
|
||||||
|
|
||||||
@@ -587,9 +593,6 @@ arp_resolve(net_datalink_protocol *protocol, in_addr_t address, arp_entry **_ent
|
|||||||
sem_id waitSem = entry->resolved_sem;
|
sem_id waitSem = entry->resolved_sem;
|
||||||
benaphore_unlock(&sCacheLock);
|
benaphore_unlock(&sCacheLock);
|
||||||
|
|
||||||
// TODO: resend the request periodically via timer
|
|
||||||
// (and abort it that way, too)
|
|
||||||
|
|
||||||
status = acquire_sem_etc(waitSem, 1, B_RELATIVE_TIMEOUT, 5 * 1000000);
|
status = acquire_sem_etc(waitSem, 1, B_RELATIVE_TIMEOUT, 5 * 1000000);
|
||||||
// wait for the entry to become resolved
|
// wait for the entry to become resolved
|
||||||
|
|
||||||
@@ -818,6 +821,7 @@ arp_send_data(net_datalink_protocol *protocol,
|
|||||||
BenaphoreLocker locker(sCacheLock);
|
BenaphoreLocker locker(sCacheLock);
|
||||||
|
|
||||||
// Lookup source (us)
|
// Lookup source (us)
|
||||||
|
// TODO: this could be cached - the lookup isn't really needed at all
|
||||||
|
|
||||||
arp_entry *entry = arp_entry::Lookup(
|
arp_entry *entry = arp_entry::Lookup(
|
||||||
((struct sockaddr_in *)&buffer->source)->sin_addr.s_addr);
|
((struct sockaddr_in *)&buffer->source)->sin_addr.s_addr);
|
||||||
@@ -827,31 +831,33 @@ arp_send_data(net_datalink_protocol *protocol,
|
|||||||
memcpy(&buffer->source, &entry->hardware_address,
|
memcpy(&buffer->source, &entry->hardware_address,
|
||||||
entry->hardware_address.sdl_len);
|
entry->hardware_address.sdl_len);
|
||||||
|
|
||||||
// Lookup destination (we may need to wait for this)
|
if ((buffer->flags & MSG_BCAST) == 0) {
|
||||||
entry = arp_entry::Lookup(
|
// Lookup destination (we may need to wait for this)
|
||||||
((struct sockaddr_in *)&buffer->destination)->sin_addr.s_addr);
|
entry = arp_entry::Lookup(
|
||||||
if (entry == NULL) {
|
((struct sockaddr_in *)&buffer->destination)->sin_addr.s_addr);
|
||||||
// The ARP entry does not yet exist, if we're allowed to wait,
|
if (entry == NULL) {
|
||||||
// we'll send an ARP request and try to change that.
|
// The ARP entry does not yet exist, if we're allowed to wait,
|
||||||
if ((buffer->flags & MSG_DONTWAIT) != 0) {
|
// we'll send an ARP request and try to change that.
|
||||||
// TODO: implement delaying packet send after ARP response!
|
if ((buffer->flags & MSG_DONTWAIT) != 0) {
|
||||||
return B_ERROR;
|
// TODO: implement delaying packet send after ARP response!
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t status = arp_resolve(protocol,
|
||||||
|
((struct sockaddr_in *)&buffer->destination)->sin_addr.s_addr, &entry);
|
||||||
|
if (status < B_OK)
|
||||||
|
return status;
|
||||||
|
} else {
|
||||||
|
// The entry exists, but we have to check if it has already been
|
||||||
|
// resolved and is valid.
|
||||||
|
status_t status = arp_check_resolved(&entry, buffer->flags);
|
||||||
|
if (status < B_OK)
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
status_t status = arp_resolve(protocol,
|
memcpy(&buffer->destination, &entry->hardware_address,
|
||||||
((struct sockaddr_in *)&buffer->destination)->sin_addr.s_addr, &entry);
|
entry->hardware_address.sdl_len);
|
||||||
if (status < B_OK)
|
|
||||||
return status;
|
|
||||||
} else {
|
|
||||||
// The entry exists, but we have to check if it has already been
|
|
||||||
// resolved and is valid.
|
|
||||||
status_t status = arp_check_resolved(&entry, buffer->flags);
|
|
||||||
if (status < B_OK)
|
|
||||||
return status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(&buffer->destination, &entry->hardware_address,
|
|
||||||
entry->hardware_address.sdl_len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return protocol->next->module->send_data(protocol->next, buffer);
|
return protocol->next->module->send_data(protocol->next, buffer);
|
||||||
@@ -905,9 +911,12 @@ arp_control(net_datalink_protocol *protocol,
|
|||||||
if (op == SIOCSIFADDR && (protocol->interface->flags & IFF_UP) != 0) {
|
if (op == SIOCSIFADDR && (protocol->interface->flags & IFF_UP) != 0) {
|
||||||
// The interface may get a new address, so we need to update our
|
// The interface may get a new address, so we need to update our
|
||||||
// local entries.
|
// local entries.
|
||||||
|
bool hasOldAddress = false;
|
||||||
in_addr_t oldAddress = 0;
|
in_addr_t oldAddress = 0;
|
||||||
if (protocol->interface->address != NULL)
|
if (protocol->interface->address != NULL) {
|
||||||
oldAddress = ((sockaddr_in *)protocol->interface->address)->sin_addr.s_addr;
|
oldAddress = ((sockaddr_in *)protocol->interface->address)->sin_addr.s_addr;
|
||||||
|
hasOldAddress = true;
|
||||||
|
}
|
||||||
|
|
||||||
status_t status = protocol->next->module->control(protocol->next,
|
status_t status = protocol->next->module->control(protocol->next,
|
||||||
SIOCSIFADDR, argument, length);
|
SIOCSIFADDR, argument, length);
|
||||||
@@ -917,7 +926,7 @@ arp_control(net_datalink_protocol *protocol,
|
|||||||
arp_update_local(protocol);
|
arp_update_local(protocol);
|
||||||
|
|
||||||
if (oldAddress == ((sockaddr_in *)protocol->interface->address)->sin_addr.s_addr
|
if (oldAddress == ((sockaddr_in *)protocol->interface->address)->sin_addr.s_addr
|
||||||
|| oldAddress == 0)
|
|| !hasOldAddress)
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
||||||
// remove previous address from cache
|
// remove previous address from cache
|
||||||
|
|||||||
@@ -378,6 +378,12 @@ datalink_send_data(struct net_route *route, net_buffer *buffer)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
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.
|
||||||
|
*/
|
||||||
bool
|
bool
|
||||||
datalink_is_local_address(net_domain *_domain, const struct sockaddr *address,
|
datalink_is_local_address(net_domain *_domain, const struct sockaddr *address,
|
||||||
net_interface **_interface, uint32 *_matchedType)
|
net_interface **_interface, uint32 *_matchedType)
|
||||||
@@ -388,17 +394,20 @@ datalink_is_local_address(net_domain *_domain, const struct sockaddr *address,
|
|||||||
|
|
||||||
BenaphoreLocker locker(domain->lock);
|
BenaphoreLocker locker(domain->lock);
|
||||||
|
|
||||||
|
net_interface *interface = NULL;
|
||||||
|
net_interface *fallback = NULL;
|
||||||
uint32 matchedType = 0;
|
uint32 matchedType = 0;
|
||||||
|
|
||||||
net_interface *interface = NULL;
|
|
||||||
while (true) {
|
while (true) {
|
||||||
interface = (net_interface *)list_get_next_item(
|
interface = (net_interface *)list_get_next_item(
|
||||||
&domain->interfaces, interface);
|
&domain->interfaces, interface);
|
||||||
if (interface == NULL)
|
if (interface == NULL)
|
||||||
break;
|
break;
|
||||||
if (interface->address == NULL)
|
if (interface->address == NULL) {
|
||||||
|
fallback = interface;
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// check for matching unicast address first
|
// check for matching unicast address first
|
||||||
if (domain->address_module->equal_addresses(interface->address, address))
|
if (domain->address_module->equal_addresses(interface->address, address))
|
||||||
break;
|
break;
|
||||||
@@ -411,10 +420,13 @@ datalink_is_local_address(net_domain *_domain, const struct sockaddr *address,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (interface == NULL)
|
if (interface == NULL) {
|
||||||
return false;
|
interface = fallback;
|
||||||
|
if (interface == NULL)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (_interface != NULL)
|
if (_interface != NULL)
|
||||||
*_interface = interface;
|
*_interface = interface;
|
||||||
if (_matchedType != NULL)
|
if (_matchedType != NULL)
|
||||||
|
|||||||
Reference in New Issue
Block a user