Author: axeld Date: 2010-08-02 17:23:19 +0200 (Mon, 02 Aug 2010) New Revision: 37845 Changeset: http://dev.haiku-os.org/changeset/37845 Modified: haiku/trunk/src/add-ons/kernel/network/stack/datalink.cpp haiku/trunk/src/add-ons/kernel/network/stack/device_interfaces.cpp haiku/trunk/src/add-ons/kernel/network/stack/device_interfaces.h haiku/trunk/src/add-ons/kernel/network/stack/link.cpp Log: * Added a dedicated lock for the device monitors. This fixes a locking issue in interface_protocol_send_data() which accessed the monitors unlocked. * Changed SIOCCPACKETCAP to check if the device name matches the one used with SIOCSPACKETCAP. Modified: haiku/trunk/src/add-ons/kernel/network/stack/datalink.cpp =================================================================== --- haiku/trunk/src/add-ons/kernel/network/stack/datalink.cpp 2010-08-02 14:45:44 UTC (rev 37844) +++ haiku/trunk/src/add-ons/kernel/network/stack/datalink.cpp 2010-08-02 15:23:19 UTC (rev 37845) @@ -642,19 +642,9 @@ interface_protocol* protocol = (interface_protocol*)_protocol; Interface* interface = (Interface*)protocol->interface; - // TODO: Need to think about this locking. We can't obtain the - // RX Lock here (nor would it make sense) as the ARP - // module calls send_data() with it's lock held (similiar - // to the domain lock, which would violate the locking - // protocol). + if (atomic_get(&interface->DeviceInterface()->monitor_count) > 0) + device_interface_monitor_receive(interface->DeviceInterface(), buffer); - DeviceMonitorList::Iterator iterator = - interface->DeviceInterface()->monitor_funcs.GetIterator(); - while (iterator.HasNext()) { - net_device_monitor* monitor = iterator.Next(); - monitor->receive(monitor, buffer); - } - return protocol->device_module->send_data(protocol->device, buffer); } Modified: haiku/trunk/src/add-ons/kernel/network/stack/device_interfaces.cpp =================================================================== --- haiku/trunk/src/add-ons/kernel/network/stack/device_interfaces.cpp 2010-08-02 14:45:44 UTC (rev 37844) +++ haiku/trunk/src/add-ons/kernel/network/stack/device_interfaces.cpp 2010-08-02 15:23:19 UTC (rev 37845) @@ -63,11 +63,8 @@ if (status == B_OK) { // feed device monitors - DeviceMonitorList::Iterator iterator = - interface->monitor_funcs.GetIterator(); - while (net_device_monitor* monitor = iterator.Next()) { - monitor->receive(monitor, buffer); - } + if (atomic_get(&interface->monitor_count) > 0) + device_interface_monitor_receive(interface, buffer); buffer->interface_address = NULL; buffer->type = interface->deframe_func(interface->device, buffer); @@ -165,7 +162,8 @@ if (interface == NULL) return NULL; - recursive_lock_init(&interface->receive_lock, "interface receive lock"); + recursive_lock_init(&interface->receive_lock, "device interface receive"); + mutex_init(&interface->monitor_lock, "device interface monitors"); char name[128]; snprintf(name, sizeof(name), "%s receive queue", device->name); @@ -199,6 +197,7 @@ uninit_fifo(&interface->receive_queue); error1: recursive_lock_destroy(&interface->receive_lock); + mutex_destroy(&interface->monitor_lock); delete interface; return NULL; @@ -208,7 +207,7 @@ static void notify_device_monitors(net_device_interface* interface, int32 event) { - RecursiveLocker _(interface->receive_lock); + MutexLocker locker(interface->monitor_lock); DeviceMonitorList::Iterator iterator = interface->monitor_funcs.GetIterator(); @@ -239,17 +238,19 @@ kprintf("ref_count: %" B_PRId32 "\n", interface->ref_count); kprintf("deframe_func: %p\n", interface->deframe_func); kprintf("deframe_ref_count: %" B_PRId32 "\n", interface->ref_count); - kprintf("monitor_funcs:\n"); - kprintf("receive_funcs:\n"); kprintf("consumer_thread: %ld\n", interface->consumer_thread); - kprintf("receive_lock: %p\n", &interface->receive_lock); - kprintf("receive_queue: %p\n", &interface->receive_queue); + kprintf("monitor_count: %" B_PRId32 "\n", interface->monitor_count); + kprintf("monitor_lock: %p\n", &interface->monitor_lock); + kprintf("monitor_funcs:\n"); DeviceMonitorList::Iterator monitorIterator = interface->monitor_funcs.GetIterator(); while (monitorIterator.HasNext()) kprintf(" %p\n", monitorIterator.Next()); + kprintf("receive_lock: %p\n", &interface->receive_lock); + kprintf("receive_queue: %p\n", &interface->receive_queue); + kprintf("receive_funcs:\n"); DeviceHandlerList::Iterator handlerIterator = interface->receive_funcs.GetIterator(); while (handlerIterator.HasNext()) @@ -374,6 +375,7 @@ device->module->uninit_device(device); put_module(moduleName); + mutex_destroy(&interface->monitor_lock); recursive_lock_destroy(&interface->receive_lock); delete interface; } @@ -449,6 +451,25 @@ } +/*! Feeds the device monitors of the \a interface with the specified \a buffer. + You might want to check interface::monitor_count before calling this + function for optimization. +*/ +void +device_interface_monitor_receive(net_device_interface* interface, + net_buffer* buffer) +{ + MutexLocker locker(interface->monitor_lock); + + DeviceMonitorList::Iterator iterator + = interface->monitor_funcs.GetIterator(); + while (iterator.HasNext()) { + net_device_monitor* monitor = iterator.Next(); + monitor->receive(monitor, buffer); + } +} + + status_t up_device_interface(net_device_interface* interface) { @@ -666,8 +687,10 @@ if (interface == NULL) return B_DEVICE_NOT_FOUND; - RecursiveLocker _(interface->receive_lock); + MutexLocker monitorLocker(interface->monitor_lock); interface->monitor_funcs.Add(monitor); + atomic_add(&interface->monitor_count, 1); + return B_OK; } @@ -683,14 +706,16 @@ if (interface == NULL) return B_DEVICE_NOT_FOUND; - RecursiveLocker _(interface->receive_lock); + MutexLocker monitorLocker(interface->monitor_lock); // search for the monitor - DeviceMonitorList::Iterator iterator = interface->monitor_funcs.GetIterator(); + DeviceMonitorList::Iterator iterator + = interface->monitor_funcs.GetIterator(); while (iterator.HasNext()) { if (iterator.Next() == monitor) { iterator.Remove(); + atomic_add(&interface->monitor_count, -1); return B_OK; } } @@ -736,6 +761,7 @@ // By now all of the monitors must have removed themselves. If they // didn't, they'll probably wait forever to be callback'ed again. + mutex_lock(&interface->monitor_lock); interface->monitor_funcs.RemoveAll(); // All of the readers should be gone as well since we are out of Modified: haiku/trunk/src/add-ons/kernel/network/stack/device_interfaces.h =================================================================== --- haiku/trunk/src/add-ons/kernel/network/stack/device_interfaces.h 2010-08-02 14:45:44 UTC (rev 37844) +++ haiku/trunk/src/add-ons/kernel/network/stack/device_interfaces.h 2010-08-02 15:23:19 UTC (rev 37845) @@ -36,9 +36,11 @@ net_deframe_func deframe_func; int32 deframe_ref_count; + int32 monitor_count; + mutex monitor_lock; DeviceMonitorList monitor_funcs; + DeviceHandlerList receive_funcs; - recursive_lock receive_lock; thread_id consumer_thread; @@ -58,12 +60,15 @@ struct net_device_interface* get_device_interface(uint32 index); struct net_device_interface* get_device_interface(const char* name, bool create = true); +void device_interface_monitor_receive(net_device_interface* interface, + net_buffer* buffer); status_t up_device_interface(net_device_interface* interface); void down_device_interface(net_device_interface* interface); // devices status_t unregister_device_deframer(net_device* device); -status_t register_device_deframer(net_device* device, net_deframe_func deframeFunc); +status_t register_device_deframer(net_device* device, + net_deframe_func deframeFunc); status_t register_domain_device_handler(struct net_device* device, int32 type, struct net_domain* domain); status_t register_device_handler(struct net_device* device, int32 type, Modified: haiku/trunk/src/add-ons/kernel/network/stack/link.cpp =================================================================== --- haiku/trunk/src/add-ons/kernel/network/stack/link.cpp 2010-08-02 14:45:44 UTC (rev 37844) +++ haiku/trunk/src/add-ons/kernel/network/stack/link.cpp 2010-08-02 15:23:19 UTC (rev 37845) @@ -46,7 +46,7 @@ virtual ~LinkProtocol(); status_t StartMonitoring(const char* deviceName); - status_t StopMonitoring(); + status_t StopMonitoring(const char* deviceName); protected: status_t SocketStatus(bool peek) const; @@ -92,7 +92,7 @@ { MutexLocker _(fLock); - if (fMonitoredDevice) + if (fMonitoredDevice != NULL) return B_BUSY; net_device_interface* interface = get_device_interface(deviceName); @@ -111,11 +111,14 @@ status_t -LinkProtocol::StopMonitoring() +LinkProtocol::StopMonitoring(const char* deviceName) { MutexLocker _(fLock); - // TODO compare our device with the supplied device name? + if (fMonitoredDevice == NULL + || strcmp(fMonitoredDevice->device->name, deviceName) != 0) + return B_BAD_VALUE; + return _Unregister(); } @@ -351,14 +354,20 @@ return B_NOT_ALLOWED; struct ifreq request; - if (user_memcpy(&request, value, IF_NAMESIZE) < B_OK) + if (user_memcpy(&request, value, IF_NAMESIZE) != B_OK) return B_BAD_ADDRESS; return protocol->StartMonitoring(request.ifr_name); } case SIOCCPACKETCAP: - return protocol->StopMonitoring(); + { + struct ifreq request; + if (user_memcpy(&request, value, IF_NAMESIZE) != B_OK) + return B_BAD_ADDRESS; + + return protocol->StopMonitoring(request.ifr_name); + } } return gNetDatalinkModule.control(sDomain, option, value, _length);