* We now cache the local hardware address in the protocol object. This allows
us to not have to look it up in arp_send_data(), and also to have more than one uninitialized interface around (ie. set to INADDR_ANY), and still have the ARP layer act correctly. * arp_update_entry() now allows entries that link to INADDR_ANY to be updated at will. This fixes trying to bring more than one uninitialized interface up. * Some cleanup. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23028 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
eac3f1b76d
commit
372952dffc
@ -81,8 +81,8 @@ struct arp_entry {
|
|||||||
static int Compare(void *_entry, const void *_key);
|
static int Compare(void *_entry, const void *_key);
|
||||||
static uint32 Hash(void *_entry, const void *_key, uint32 range);
|
static uint32 Hash(void *_entry, const void *_key, uint32 range);
|
||||||
static arp_entry *Lookup(in_addr_t protocolAddress);
|
static arp_entry *Lookup(in_addr_t protocolAddress);
|
||||||
static arp_entry *Add(in_addr_t protocolAddress, sockaddr_dl *hardwareAddress,
|
static arp_entry *Add(in_addr_t protocolAddress,
|
||||||
uint32 flags);
|
sockaddr_dl *hardwareAddress, uint32 flags);
|
||||||
|
|
||||||
~arp_entry();
|
~arp_entry();
|
||||||
|
|
||||||
@ -105,6 +105,7 @@ struct arp_entry {
|
|||||||
#define ARP_REQUEST_TIMEOUT 1000000LL // 1 second
|
#define ARP_REQUEST_TIMEOUT 1000000LL // 1 second
|
||||||
|
|
||||||
struct arp_protocol : net_datalink_protocol {
|
struct arp_protocol : net_datalink_protocol {
|
||||||
|
sockaddr_dl hardware_address;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -251,6 +252,9 @@ arp_entry::MarkValid()
|
|||||||
static void
|
static void
|
||||||
ipv4_to_ether_multicast(sockaddr_dl *destination, const sockaddr_in *source)
|
ipv4_to_ether_multicast(sockaddr_dl *destination, const sockaddr_in *source)
|
||||||
{
|
{
|
||||||
|
// TODO: this is ethernet specific, and doesn't belong here
|
||||||
|
// (should be moved to the ethernet_frame module)
|
||||||
|
|
||||||
// RFC 1112 - Host extensions for IP multicasting
|
// RFC 1112 - Host extensions for IP multicasting
|
||||||
//
|
//
|
||||||
// ``An IP host group address is mapped to an Ethernet multicast
|
// ``An IP host group address is mapped to an Ethernet multicast
|
||||||
@ -292,14 +296,16 @@ arp_update_entry(in_addr_t protocolAddress, sockaddr_dl *hardwareAddress,
|
|||||||
arp_entry *entry = arp_entry::Lookup(protocolAddress);
|
arp_entry *entry = arp_entry::Lookup(protocolAddress);
|
||||||
if (entry != NULL) {
|
if (entry != NULL) {
|
||||||
// We disallow updating of entries that had been resolved before,
|
// We disallow updating of entries that had been resolved before,
|
||||||
// but to a different address.
|
// but to a different address (only for those that belong to a
|
||||||
|
// specific address - redefining INADDR_ANY is always allowed).
|
||||||
// Right now, you have to manually purge the ARP entries (or wait some
|
// Right now, you have to manually purge the ARP entries (or wait some
|
||||||
// time) to let us switch to the new address.
|
// time) to let us switch to the new address.
|
||||||
if (entry->hardware_address.sdl_alen != 0
|
if (protocolAddress != INADDR_ANY
|
||||||
|
&& entry->hardware_address.sdl_alen != 0
|
||||||
&& memcmp(LLADDR(&entry->hardware_address),
|
&& memcmp(LLADDR(&entry->hardware_address),
|
||||||
LLADDR(hardwareAddress), ETHER_ADDRESS_LENGTH)) {
|
LLADDR(hardwareAddress), ETHER_ADDRESS_LENGTH)) {
|
||||||
dprintf("ARP host %08lx updated with different hardware address %02x:%02x:%02x:%02x:%02x:%02x.\n",
|
dprintf("ARP host %08x updated with different hardware address "
|
||||||
protocolAddress,
|
"%02x:%02x:%02x:%02x:%02x:%02x.\n", protocolAddress,
|
||||||
hardwareAddress->sdl_data[0], hardwareAddress->sdl_data[1],
|
hardwareAddress->sdl_data[0], hardwareAddress->sdl_data[1],
|
||||||
hardwareAddress->sdl_data[2], hardwareAddress->sdl_data[3],
|
hardwareAddress->sdl_data[2], hardwareAddress->sdl_data[3],
|
||||||
hardwareAddress->sdl_data[4], hardwareAddress->sdl_data[5]);
|
hardwareAddress->sdl_data[4], hardwareAddress->sdl_data[5]);
|
||||||
@ -338,7 +344,7 @@ arp_update_entry(in_addr_t protocolAddress, sockaddr_dl *hardwareAddress,
|
|||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
arp_update_local(net_datalink_protocol *protocol)
|
arp_update_local(arp_protocol *protocol)
|
||||||
{
|
{
|
||||||
net_interface *interface = protocol->interface;
|
net_interface *interface = protocol->interface;
|
||||||
in_addr_t inetAddress;
|
in_addr_t inetAddress;
|
||||||
@ -359,6 +365,9 @@ arp_update_local(net_datalink_protocol *protocol)
|
|||||||
address.sdl_alen = interface->device->address.length;
|
address.sdl_alen = interface->device->address.length;
|
||||||
memcpy(LLADDR(&address), interface->device->address.data, address.sdl_alen);
|
memcpy(LLADDR(&address), interface->device->address.data, address.sdl_alen);
|
||||||
|
|
||||||
|
memcpy(&protocol->hardware_address, &address, sizeof(sockaddr_dl));
|
||||||
|
// cache the address in our protocol
|
||||||
|
|
||||||
arp_entry *entry;
|
arp_entry *entry;
|
||||||
status_t status = arp_update_entry(inetAddress, &address,
|
status_t status = arp_update_entry(inetAddress, &address,
|
||||||
ARP_FLAG_LOCAL | ARP_FLAG_PERMANENT, &entry);
|
ARP_FLAG_LOCAL | ARP_FLAG_PERMANENT, &entry);
|
||||||
@ -375,14 +384,16 @@ handle_arp_request(net_buffer *buffer, arp_header &header)
|
|||||||
BenaphoreLocker locker(sCacheLock);
|
BenaphoreLocker locker(sCacheLock);
|
||||||
|
|
||||||
if (!sIgnoreReplies) {
|
if (!sIgnoreReplies) {
|
||||||
arp_update_entry(header.protocol_sender, (sockaddr_dl *)buffer->source, 0);
|
arp_update_entry(header.protocol_sender,
|
||||||
|
(sockaddr_dl *)buffer->source, 0);
|
||||||
// remember the address of the sender as we might need it later
|
// remember the address of the sender as we might need it later
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if this request is for us
|
// check if this request is for us
|
||||||
|
|
||||||
arp_entry *entry = arp_entry::Lookup(header.protocol_target);
|
arp_entry *entry = arp_entry::Lookup(header.protocol_target);
|
||||||
if (entry == NULL || (entry->flags & (ARP_FLAG_LOCAL | ARP_FLAG_PUBLISH)) == 0) {
|
if (entry == NULL
|
||||||
|
|| (entry->flags & (ARP_FLAG_LOCAL | ARP_FLAG_PUBLISH)) == 0) {
|
||||||
// We're not the one to answer this request
|
// We're not the one to answer this request
|
||||||
// TODO: instead of letting the other's request time-out, can we reply
|
// TODO: instead of letting the other's request time-out, can we reply
|
||||||
// failure somehow?
|
// failure somehow?
|
||||||
@ -397,7 +408,8 @@ handle_arp_request(net_buffer *buffer, arp_header &header)
|
|||||||
|
|
||||||
memcpy(header.hardware_target, header.hardware_sender, ETHER_ADDRESS_LENGTH);
|
memcpy(header.hardware_target, header.hardware_sender, ETHER_ADDRESS_LENGTH);
|
||||||
header.protocol_target = header.protocol_sender;
|
header.protocol_target = header.protocol_sender;
|
||||||
memcpy(header.hardware_sender, LLADDR(&entry->hardware_address), ETHER_ADDRESS_LENGTH);
|
memcpy(header.hardware_sender, LLADDR(&entry->hardware_address),
|
||||||
|
ETHER_ADDRESS_LENGTH);
|
||||||
header.protocol_sender = entry->protocol_address;
|
header.protocol_sender = entry->protocol_address;
|
||||||
|
|
||||||
// exchange source and destination address
|
// exchange source and destination address
|
||||||
@ -409,7 +421,8 @@ handle_arp_request(net_buffer *buffer, arp_header &header)
|
|||||||
buffer->flags = 0;
|
buffer->flags = 0;
|
||||||
// make sure this won't be a broadcast message
|
// make sure this won't be a broadcast message
|
||||||
|
|
||||||
return entry->protocol->next->module->send_data(entry->protocol->next, buffer);
|
return entry->protocol->next->module->send_data(entry->protocol->next,
|
||||||
|
buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -465,7 +478,8 @@ arp_receive(void *cookie, net_device *device, net_buffer *buffer)
|
|||||||
case ARP_OPCODE_REQUEST:
|
case ARP_OPCODE_REQUEST:
|
||||||
TRACE((" got ARP request\n"));
|
TRACE((" got ARP request\n"));
|
||||||
if (handle_arp_request(buffer, header) == B_OK) {
|
if (handle_arp_request(buffer, header) == B_OK) {
|
||||||
// the function will take care of the buffer if everything went well
|
// the function will take care of the buffer if everything
|
||||||
|
// went well
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -496,8 +510,9 @@ arp_timer(struct net_timer *timer, void *data)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case ARP_STATE_REQUEST_FAILED:
|
case ARP_STATE_REQUEST_FAILED:
|
||||||
// requesting the ARP entry failed, we keep it around for a while, though,
|
// Requesting the ARP entry failed, we keep it around for a while,
|
||||||
// so that we won't try to request the same address again too soon.
|
// though, so that we won't try to request the same address again
|
||||||
|
// too soon.
|
||||||
TRACE((" requesting ARP entry %p failed!\n", entry));
|
TRACE((" requesting ARP entry %p failed!\n", entry));
|
||||||
entry->timer_state = ARP_STATE_REMOVE_FAILED;
|
entry->timer_state = ARP_STATE_REMOVE_FAILED;
|
||||||
entry->MarkFailed();
|
entry->MarkFailed();
|
||||||
@ -514,9 +529,10 @@ arp_timer(struct net_timer *timer, void *data)
|
|||||||
benaphore_unlock(&sCacheLock);
|
benaphore_unlock(&sCacheLock);
|
||||||
|
|
||||||
delete entry;
|
delete entry;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
{
|
||||||
if (entry->timer_state > ARP_STATE_LAST_REQUEST)
|
if (entry->timer_state > ARP_STATE_LAST_REQUEST)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -547,6 +563,8 @@ arp_timer(struct net_timer *timer, void *data)
|
|||||||
|
|
||||||
entry->timer_state++;
|
entry->timer_state++;
|
||||||
sStackModule->set_timer(&entry->timer, ARP_REQUEST_TIMEOUT);
|
sStackModule->set_timer(&entry->timer, ARP_REQUEST_TIMEOUT);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -558,7 +576,8 @@ arp_timer(struct net_timer *timer, void *data)
|
|||||||
note that the lock will be interrupted here if everything goes well.
|
note that the lock will be interrupted here if everything goes well.
|
||||||
*/
|
*/
|
||||||
static status_t
|
static status_t
|
||||||
arp_start_resolve(net_datalink_protocol *protocol, in_addr_t address, arp_entry **_entry)
|
arp_start_resolve(net_datalink_protocol *protocol, in_addr_t address,
|
||||||
|
arp_entry **_entry)
|
||||||
{
|
{
|
||||||
// create an unresolved ARP entry as a placeholder
|
// create an unresolved ARP entry as a placeholder
|
||||||
arp_entry *entry = arp_entry::Add(address, NULL, 0);
|
arp_entry *entry = arp_entry::Add(address, NULL, 0);
|
||||||
@ -602,7 +621,8 @@ arp_start_resolve(net_datalink_protocol *protocol, in_addr_t address, arp_entry
|
|||||||
|
|
||||||
// prepare source and target addresses
|
// prepare source and target addresses
|
||||||
|
|
||||||
struct sockaddr_dl &source = *(struct sockaddr_dl *)entry->request_buffer->source;
|
struct sockaddr_dl &source = *(struct sockaddr_dl *)
|
||||||
|
entry->request_buffer->source;
|
||||||
source.sdl_len = sizeof(sockaddr_dl);
|
source.sdl_len = sizeof(sockaddr_dl);
|
||||||
source.sdl_family = AF_DLI;
|
source.sdl_family = AF_DLI;
|
||||||
source.sdl_index = device->index;
|
source.sdl_index = device->index;
|
||||||
@ -626,8 +646,8 @@ arp_start_resolve(net_datalink_protocol *protocol, in_addr_t address, arp_entry
|
|||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
arp_control(const char *subsystem, uint32 function,
|
arp_control(const char *subsystem, uint32 function, void *buffer,
|
||||||
void *buffer, size_t bufferSize)
|
size_t bufferSize)
|
||||||
{
|
{
|
||||||
struct arp_control control;
|
struct arp_control control;
|
||||||
if (bufferSize != sizeof(struct arp_control))
|
if (bufferSize != sizeof(struct arp_control))
|
||||||
@ -639,6 +659,7 @@ arp_control(const char *subsystem, uint32 function,
|
|||||||
|
|
||||||
switch (function) {
|
switch (function) {
|
||||||
case ARP_SET_ENTRY:
|
case ARP_SET_ENTRY:
|
||||||
|
{
|
||||||
sockaddr_dl hardwareAddress;
|
sockaddr_dl hardwareAddress;
|
||||||
|
|
||||||
hardwareAddress.sdl_len = sizeof(sockaddr_dl);
|
hardwareAddress.sdl_len = sizeof(sockaddr_dl);
|
||||||
@ -648,10 +669,13 @@ arp_control(const char *subsystem, uint32 function,
|
|||||||
hardwareAddress.sdl_e_type = ETHER_TYPE_IP;
|
hardwareAddress.sdl_e_type = ETHER_TYPE_IP;
|
||||||
hardwareAddress.sdl_nlen = hardwareAddress.sdl_slen = 0;
|
hardwareAddress.sdl_nlen = hardwareAddress.sdl_slen = 0;
|
||||||
hardwareAddress.sdl_alen = ETHER_ADDRESS_LENGTH;
|
hardwareAddress.sdl_alen = ETHER_ADDRESS_LENGTH;
|
||||||
memcpy(hardwareAddress.sdl_data, control.ethernet_address, ETHER_ADDRESS_LENGTH);
|
memcpy(hardwareAddress.sdl_data, control.ethernet_address,
|
||||||
|
ETHER_ADDRESS_LENGTH);
|
||||||
|
|
||||||
return arp_update_entry(control.address, &hardwareAddress,
|
return arp_update_entry(control.address, &hardwareAddress,
|
||||||
control.flags & (ARP_FLAG_PUBLISH | ARP_FLAG_PERMANENT | ARP_FLAG_REJECT));
|
control.flags & (ARP_FLAG_PUBLISH | ARP_FLAG_PERMANENT
|
||||||
|
| ARP_FLAG_REJECT));
|
||||||
|
}
|
||||||
|
|
||||||
case ARP_GET_ENTRY:
|
case ARP_GET_ENTRY:
|
||||||
{
|
{
|
||||||
@ -763,7 +787,8 @@ arp_uninit()
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
arp_init_protocol(struct net_interface *interface, net_datalink_protocol **_protocol)
|
arp_init_protocol(struct net_interface *interface,
|
||||||
|
net_datalink_protocol **_protocol)
|
||||||
{
|
{
|
||||||
// We currently only support a single family and type!
|
// We currently only support a single family and type!
|
||||||
if (interface->domain->family != AF_INET
|
if (interface->domain->family != AF_INET
|
||||||
@ -780,6 +805,7 @@ arp_init_protocol(struct net_interface *interface, net_datalink_protocol **_prot
|
|||||||
if (protocol == NULL)
|
if (protocol == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
memset(&protocol->hardware_address, 0, sizeof(sockaddr_dl));
|
||||||
*_protocol = protocol;
|
*_protocol = protocol;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
@ -797,22 +823,16 @@ arp_uninit_protocol(net_datalink_protocol *protocol)
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
arp_send_data(net_datalink_protocol *protocol,
|
arp_send_data(net_datalink_protocol *_protocol, net_buffer *buffer)
|
||||||
net_buffer *buffer)
|
|
||||||
{
|
{
|
||||||
|
arp_protocol *protocol = (arp_protocol *)_protocol;
|
||||||
{
|
{
|
||||||
BenaphoreLocker locker(sCacheLock);
|
BenaphoreLocker locker(sCacheLock);
|
||||||
|
|
||||||
// Lookup source (us)
|
// Set buffer target and destination address
|
||||||
// TODO: this could be cached - the lookup isn't really needed at all
|
|
||||||
|
|
||||||
arp_entry *entry = arp_entry::Lookup(
|
memcpy(buffer->source, &protocol->hardware_address,
|
||||||
((struct sockaddr_in *)buffer->source)->sin_addr.s_addr);
|
protocol->hardware_address.sdl_len);
|
||||||
if (entry == NULL)
|
|
||||||
return B_ERROR;
|
|
||||||
|
|
||||||
memcpy(buffer->source, &entry->hardware_address,
|
|
||||||
entry->hardware_address.sdl_len);
|
|
||||||
|
|
||||||
if (buffer->flags & MSG_MCAST) {
|
if (buffer->flags & MSG_MCAST) {
|
||||||
sockaddr_dl multicastDestination;
|
sockaddr_dl multicastDestination;
|
||||||
@ -822,7 +842,7 @@ arp_send_data(net_datalink_protocol *protocol,
|
|||||||
sizeof(multicastDestination));
|
sizeof(multicastDestination));
|
||||||
} else if ((buffer->flags & MSG_BCAST) == 0) {
|
} else if ((buffer->flags & MSG_BCAST) == 0) {
|
||||||
// Lookup destination (we may need to wait for this)
|
// Lookup destination (we may need to wait for this)
|
||||||
entry = arp_entry::Lookup(
|
arp_entry *entry = arp_entry::Lookup(
|
||||||
((struct sockaddr_in *)buffer->destination)->sin_addr.s_addr);
|
((struct sockaddr_in *)buffer->destination)->sin_addr.s_addr);
|
||||||
if (entry == NULL) {
|
if (entry == NULL) {
|
||||||
status_t status = arp_start_resolve(protocol,
|
status_t status = arp_start_resolve(protocol,
|
||||||
@ -891,16 +911,19 @@ arp_down(net_datalink_protocol *protocol)
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
arp_control(net_datalink_protocol *protocol,
|
arp_control(net_datalink_protocol *_protocol, int32 op, void *argument,
|
||||||
int32 op, void *argument, size_t length)
|
size_t length)
|
||||||
{
|
{
|
||||||
|
arp_protocol *protocol = (arp_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;
|
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;
|
hasOldAddress = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -911,7 +934,8 @@ 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
|
||||||
|| !hasOldAddress)
|
|| !hasOldAddress)
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user