* Added an atomic_pointer_set() template function to util/atomic.h.
* Made the pointers const. * Changed how the ARP module maintains its arp_entry::request_buffer: it now uses the atomic_pointer*() functions to make sure there is no race condition, and it's deleted only once. * Getting an ARP entry would return uninitialized data, if the entry hadn't been resolved yet. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25263 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
67e2e88213
commit
801591dbde
@ -14,8 +14,8 @@
|
|||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
||||||
template<typename PointerType> PointerType*
|
template<typename PointerType> PointerType*
|
||||||
atomic_pointer_test_and_set(PointerType** _pointer, PointerType* set,
|
atomic_pointer_test_and_set(PointerType** _pointer, const PointerType* set,
|
||||||
PointerType* test)
|
const PointerType* test)
|
||||||
{
|
{
|
||||||
#if LONG_MAX == INT_MAX
|
#if LONG_MAX == INT_MAX
|
||||||
return (PointerType*)atomic_test_and_set((vint32*)_pointer, (int32)set,
|
return (PointerType*)atomic_test_and_set((vint32*)_pointer, (int32)set,
|
||||||
@ -26,6 +26,17 @@ atomic_pointer_test_and_set(PointerType** _pointer, PointerType* set,
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename PointerType> PointerType*
|
||||||
|
atomic_pointer_set(PointerType** _pointer, const PointerType* set)
|
||||||
|
{
|
||||||
|
#if LONG_MAX == INT_MAX
|
||||||
|
return (PointerType*)atomic_set((vint32*)_pointer, (int32)set);
|
||||||
|
#else
|
||||||
|
return (PointerType*)atomic_set64((vint64*)_pointer, (int64)set);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#endif // __cplusplus
|
#endif // __cplusplus
|
||||||
|
|
||||||
#endif /* _KERNEL_UTIL_ATOMIC_H */
|
#endif /* _KERNEL_UTIL_ATOMIC_H */
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2006-2007, Haiku, Inc. All Rights Reserved.
|
* Copyright 2006-2008, Haiku, Inc. All Rights Reserved.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
* Authors:
|
* Authors:
|
||||||
@ -18,6 +18,7 @@
|
|||||||
#include <NetBufferUtilities.h>
|
#include <NetBufferUtilities.h>
|
||||||
|
|
||||||
#include <generic_syscall.h>
|
#include <generic_syscall.h>
|
||||||
|
#include <util/atomic.h>
|
||||||
#include <util/AutoLock.h>
|
#include <util/AutoLock.h>
|
||||||
#include <util/DoublyLinkedList.h>
|
#include <util/DoublyLinkedList.h>
|
||||||
#include <util/khash.h>
|
#include <util/khash.h>
|
||||||
@ -68,7 +69,6 @@ struct arp_entry {
|
|||||||
sockaddr_dl hardware_address;
|
sockaddr_dl hardware_address;
|
||||||
uint32 flags;
|
uint32 flags;
|
||||||
net_buffer *request_buffer;
|
net_buffer *request_buffer;
|
||||||
int32 request_buffer_ref_count;
|
|
||||||
net_timer timer;
|
net_timer timer;
|
||||||
uint32 timer_state;
|
uint32 timer_state;
|
||||||
bigtime_t timestamp;
|
bigtime_t timestamp;
|
||||||
@ -110,6 +110,8 @@ struct arp_protocol : net_datalink_protocol {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static const net_buffer* kDeletedBuffer = (net_buffer*)~0;
|
||||||
|
|
||||||
static void arp_timer(struct net_timer *timer, void *data);
|
static void arp_timer(struct net_timer *timer, void *data);
|
||||||
|
|
||||||
net_buffer_module_info *gBufferModule;
|
net_buffer_module_info *gBufferModule;
|
||||||
@ -120,24 +122,40 @@ static bool sIgnoreReplies;
|
|||||||
|
|
||||||
|
|
||||||
static net_buffer*
|
static net_buffer*
|
||||||
get_request_buffer_reference(arp_entry* entry)
|
get_request_buffer(arp_entry* entry)
|
||||||
{
|
{
|
||||||
if (atomic_test_and_set(&entry->request_buffer_ref_count, 2, 1) == 1)
|
net_buffer* buffer = entry->request_buffer;
|
||||||
return entry->request_buffer;
|
if (buffer == NULL || buffer == kDeletedBuffer)
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
buffer = atomic_pointer_test_and_set(&entry->request_buffer,
|
||||||
|
(net_buffer*)NULL, buffer);
|
||||||
|
if (buffer == kDeletedBuffer)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
put_request_buffer_reference(arp_entry* entry)
|
put_request_buffer(arp_entry* entry, net_buffer* buffer)
|
||||||
{
|
{
|
||||||
if (atomic_add(&entry->request_buffer_ref_count, -1) == 0) {
|
net_buffer* requestBuffer = atomic_pointer_test_and_set(
|
||||||
if (entry->request_buffer != NULL) {
|
&entry->request_buffer, buffer, (net_buffer*)NULL);
|
||||||
gBufferModule->free(entry->request_buffer);
|
if (requestBuffer != NULL) {
|
||||||
entry->request_buffer = NULL;
|
// someone else took over ownership of the request buffer
|
||||||
|
gBufferModule->free(buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
delete_request_buffer(arp_entry* entry)
|
||||||
|
{
|
||||||
|
net_buffer* buffer = atomic_pointer_set(&entry->request_buffer,
|
||||||
|
kDeletedBuffer);
|
||||||
|
if (buffer != NULL && buffer != kDeletedBuffer)
|
||||||
|
gBufferModule->free(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -197,7 +215,6 @@ arp_entry::Add(in_addr_t protocolAddress, sockaddr_dl *hardwareAddress,
|
|||||||
entry->timestamp = system_time();
|
entry->timestamp = system_time();
|
||||||
entry->protocol = NULL;
|
entry->protocol = NULL;
|
||||||
entry->request_buffer = NULL;
|
entry->request_buffer = NULL;
|
||||||
entry->request_buffer_ref_count = 0;
|
|
||||||
entry->timer_state = ARP_NO_STATE;
|
entry->timer_state = ARP_NO_STATE;
|
||||||
sStackModule->init_timer(&entry->timer, arp_timer, entry);
|
sStackModule->init_timer(&entry->timer, arp_timer, entry);
|
||||||
|
|
||||||
@ -344,7 +361,7 @@ arp_update_entry(in_addr_t protocolAddress, sockaddr_dl *hardwareAddress,
|
|||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
put_request_buffer_reference(entry);
|
delete_request_buffer(entry);
|
||||||
|
|
||||||
if ((entry->flags & ARP_FLAG_PERMANENT) == 0) {
|
if ((entry->flags & ARP_FLAG_PERMANENT) == 0) {
|
||||||
// (re)start the stale timer
|
// (re)start the stale timer
|
||||||
@ -559,30 +576,22 @@ arp_timer(struct net_timer *timer, void *data)
|
|||||||
|
|
||||||
TRACE((" send request for ARP entry %p!\n", entry));
|
TRACE((" send request for ARP entry %p!\n", entry));
|
||||||
|
|
||||||
net_buffer *request = get_request_buffer_reference(entry);
|
net_buffer *request = get_request_buffer(entry);
|
||||||
if (request == NULL)
|
if (request == NULL)
|
||||||
break;
|
break;
|
||||||
// TODO: The reference counting does still not solve request_buffer
|
|
||||||
// access problem completely: A duplicate reply between this point
|
|
||||||
// and the "entry->request_buffer = NULL" will release two
|
|
||||||
// references in arp_update_entry() and thus delete the buffer.
|
|
||||||
|
|
||||||
if (entry->timer_state < ARP_STATE_LAST_REQUEST) {
|
if (entry->timer_state < ARP_STATE_LAST_REQUEST) {
|
||||||
// we'll still need our buffer, so in order to prevent it being
|
// we'll still need our buffer, so in order to prevent it being
|
||||||
// freed by a successful send, we need to clone it
|
// freed by a successful send, we need to clone it
|
||||||
request = gBufferModule->clone(request, true);
|
net_buffer* clone = gBufferModule->clone(request, true);
|
||||||
if (request == NULL) {
|
if (clone == NULL) {
|
||||||
// cloning failed - that means we won't be able to send as
|
// cloning failed - that means we won't be able to send as
|
||||||
// many requests as originally planned
|
// many requests as originally planned
|
||||||
request = entry->request_buffer;
|
|
||||||
entry->timer_state = ARP_STATE_LAST_REQUEST;
|
entry->timer_state = ARP_STATE_LAST_REQUEST;
|
||||||
} else
|
} else {
|
||||||
put_request_buffer_reference(entry);
|
put_request_buffer(entry, request);
|
||||||
|
request = clone;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entry->timer_state == ARP_STATE_LAST_REQUEST) {
|
|
||||||
// the request buffer will be deleted, detach it
|
|
||||||
entry->request_buffer = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// we're trying to resolve the address, so keep sending requests
|
// we're trying to resolve the address, so keep sending requests
|
||||||
@ -599,8 +608,7 @@ arp_timer(struct net_timer *timer, void *data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*! Address resolver function: prepares and triggers the ARP request necessary
|
||||||
Address resolver function: prepares and sends the ARP request necessary
|
|
||||||
to retrieve the hardware address for \a address.
|
to retrieve the hardware address for \a address.
|
||||||
You need to have the sCacheLock held when calling this function - but
|
You need to have the sCacheLock held when calling this function - but
|
||||||
note that the lock will be interrupted here if everything goes well.
|
note that the lock will be interrupted here if everything goes well.
|
||||||
@ -621,7 +629,6 @@ arp_start_resolve(net_datalink_protocol *protocol, in_addr_t address,
|
|||||||
// TODO: do something with the entry
|
// TODO: do something with the entry
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
}
|
}
|
||||||
entry->request_buffer_ref_count = 1;
|
|
||||||
|
|
||||||
NetBufferPrepend<arp_header> bufferHeader(entry->request_buffer);
|
NetBufferPrepend<arp_header> bufferHeader(entry->request_buffer);
|
||||||
status_t status = bufferHeader.Status();
|
status_t status = bufferHeader.Status();
|
||||||
@ -642,9 +649,10 @@ arp_start_resolve(net_datalink_protocol *protocol, in_addr_t address,
|
|||||||
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);
|
||||||
if (protocol->interface->address != NULL)
|
if (protocol->interface->address != NULL) {
|
||||||
header.protocol_sender = ((sockaddr_in *)protocol->interface->address)->sin_addr.s_addr;
|
header.protocol_sender
|
||||||
else
|
= ((sockaddr_in *)protocol->interface->address)->sin_addr.s_addr;
|
||||||
|
} else
|
||||||
header.protocol_sender = 0;
|
header.protocol_sender = 0;
|
||||||
// TODO: test if this actually works - maybe we should use INADDR_BROADCAST instead
|
// 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);
|
||||||
@ -714,8 +722,12 @@ arp_control(const char *subsystem, uint32 function, void *buffer,
|
|||||||
if (entry == NULL || !(entry->flags & ARP_FLAG_VALID))
|
if (entry == NULL || !(entry->flags & ARP_FLAG_VALID))
|
||||||
return B_ENTRY_NOT_FOUND;
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
|
||||||
memcpy(control.ethernet_address, entry->hardware_address.sdl_data,
|
if (entry->hardware_address.sdl_alen == ETHER_ADDRESS_LENGTH) {
|
||||||
ETHER_ADDRESS_LENGTH);
|
memcpy(control.ethernet_address,
|
||||||
|
entry->hardware_address.sdl_data, ETHER_ADDRESS_LENGTH);
|
||||||
|
} else
|
||||||
|
memset(control.ethernet_address, 0, ETHER_ADDRESS_LENGTH);
|
||||||
|
|
||||||
control.flags = entry->flags;
|
control.flags = entry->flags;
|
||||||
return user_memcpy(buffer, &control, sizeof(struct arp_control));
|
return user_memcpy(buffer, &control, sizeof(struct arp_control));
|
||||||
}
|
}
|
||||||
@ -738,8 +750,11 @@ arp_control(const char *subsystem, uint32 function, void *buffer,
|
|||||||
|
|
||||||
control.cookie++;
|
control.cookie++;
|
||||||
control.address = entry->protocol_address;
|
control.address = entry->protocol_address;
|
||||||
memcpy(control.ethernet_address, entry->hardware_address.sdl_data,
|
if (entry->hardware_address.sdl_alen == ETHER_ADDRESS_LENGTH) {
|
||||||
ETHER_ADDRESS_LENGTH);
|
memcpy(control.ethernet_address,
|
||||||
|
entry->hardware_address.sdl_data, ETHER_ADDRESS_LENGTH);
|
||||||
|
} else
|
||||||
|
memset(control.ethernet_address, 0, ETHER_ADDRESS_LENGTH);
|
||||||
control.flags = entry->flags;
|
control.flags = entry->flags;
|
||||||
|
|
||||||
return user_memcpy(buffer, &control, sizeof(struct arp_control));
|
return user_memcpy(buffer, &control, sizeof(struct arp_control));
|
||||||
|
Loading…
Reference in New Issue
Block a user