* 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:
Axel Dörfler 2006-12-11 17:03:08 +00:00
parent 84fcc63a5e
commit c8760b9687
2 changed files with 60 additions and 39 deletions

View File

@ -263,11 +263,13 @@ static status_t
arp_update_local(net_datalink_protocol *protocol)
{
net_interface *interface = protocol->interface;
in_addr_t inetAddress;
if (interface->address == NULL) {
// 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;
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);
arp_entry *entry;
status_t status = arp_update_entry(((sockaddr_in *)interface->address)->sin_addr.s_addr,
&address, ARP_FLAG_LOCAL | ARP_FLAG_PERMANENT, &entry);
status_t status = arp_update_entry(inetAddress, &address,
ARP_FLAG_LOCAL | ARP_FLAG_PERMANENT, &entry);
if (status == B_OK)
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);
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);
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;
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);
// wait for the entry to become resolved
@ -818,6 +821,7 @@ arp_send_data(net_datalink_protocol *protocol,
BenaphoreLocker locker(sCacheLock);
// Lookup source (us)
// TODO: this could be cached - the lookup isn't really needed at all
arp_entry *entry = arp_entry::Lookup(
((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,
entry->hardware_address.sdl_len);
// Lookup destination (we may need to wait for this)
entry = arp_entry::Lookup(
((struct sockaddr_in *)&buffer->destination)->sin_addr.s_addr);
if (entry == NULL) {
// The ARP entry does not yet exist, if we're allowed to wait,
// we'll send an ARP request and try to change that.
if ((buffer->flags & MSG_DONTWAIT) != 0) {
// TODO: implement delaying packet send after ARP response!
return B_ERROR;
if ((buffer->flags & MSG_BCAST) == 0) {
// Lookup destination (we may need to wait for this)
entry = arp_entry::Lookup(
((struct sockaddr_in *)&buffer->destination)->sin_addr.s_addr);
if (entry == NULL) {
// The ARP entry does not yet exist, if we're allowed to wait,
// we'll send an ARP request and try to change that.
if ((buffer->flags & MSG_DONTWAIT) != 0) {
// 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,
((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;
memcpy(&buffer->destination, &entry->hardware_address,
entry->hardware_address.sdl_len);
}
memcpy(&buffer->destination, &entry->hardware_address,
entry->hardware_address.sdl_len);
}
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) {
// The interface may get a new address, so we need to update our
// local entries.
bool hasOldAddress = false;
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;
hasOldAddress = true;
}
status_t status = protocol->next->module->control(protocol->next,
SIOCSIFADDR, argument, length);
@ -917,7 +926,7 @@ arp_control(net_datalink_protocol *protocol,
arp_update_local(protocol);
if (oldAddress == ((sockaddr_in *)protocol->interface->address)->sin_addr.s_addr
|| oldAddress == 0)
|| !hasOldAddress)
return B_OK;
// remove previous address from cache

View File

@ -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
datalink_is_local_address(net_domain *_domain, const struct sockaddr *address,
net_interface **_interface, uint32 *_matchedType)
@ -388,17 +394,20 @@ datalink_is_local_address(net_domain *_domain, const struct sockaddr *address,
BenaphoreLocker locker(domain->lock);
net_interface *interface = NULL;
net_interface *fallback = NULL;
uint32 matchedType = 0;
net_interface *interface = NULL;
while (true) {
interface = (net_interface *)list_get_next_item(
&domain->interfaces, interface);
if (interface == NULL)
break;
if (interface->address == NULL)
if (interface->address == NULL) {
fallback = interface;
continue;
}
// check for matching unicast address first
if (domain->address_module->equal_addresses(interface->address, address))
break;
@ -411,10 +420,13 @@ datalink_is_local_address(net_domain *_domain, const struct sockaddr *address,
break;
}
}
if (interface == NULL)
return false;
if (interface == NULL) {
interface = fallback;
if (interface == NULL)
return false;
}
if (_interface != NULL)
*_interface = interface;
if (_matchedType != NULL)