From 44a3d0d1f699d16f8fc4a5443b5bd383d5267146 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Sun, 15 Aug 2010 13:21:42 +0000 Subject: [PATCH] * Spotted a few reference counting bugs that were probably responsible for #6446, although I could not reproduce the exact problem. * net_datalink::is_local_[link_]address() now releases a previous reference if the _interfaceAddress arguments does not point to NULL. * When a buffer is received from a device, it's interface_address should be NULL already. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@38118 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/add-ons/kernel/network/stack/datalink.cpp | 36 +++++++++++++------ .../network/stack/device_interfaces.cpp | 5 +-- 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/src/add-ons/kernel/network/stack/datalink.cpp b/src/add-ons/kernel/network/stack/datalink.cpp index 4939ca15d2..fb8caa57a1 100644 --- a/src/add-ons/kernel/network/stack/datalink.cpp +++ b/src/add-ons/kernel/network/stack/datalink.cpp @@ -164,7 +164,17 @@ get_interface_name_or_index(net_domain* domain, int32 option, void* value, } -status_t +static void +set_interface_address(net_interface_address*& target, InterfaceAddress* address) +{ + if (target != NULL) + static_cast(target)->ReleaseReference(); + + target = address; +} + + +static status_t fill_address(const sockaddr* from, sockaddr* to, size_t maxLength) { if (from != NULL) { @@ -260,7 +270,7 @@ datalink_control(net_domain* _domain, int32 option, void* value, return status; } - + case SIOCGIFCOUNT: { // count number of interfaces @@ -340,7 +350,7 @@ datalink_send_routed_data(struct net_route* route, net_buffer* buffer) { TRACE("%s(route %p, buffer %p)\n", __FUNCTION__, route, buffer); - net_interface_address* address = route->interface_address; + InterfaceAddress* address = (InterfaceAddress*)route->interface_address; Interface* interface = (Interface*)address->interface; //dprintf("send buffer (%ld bytes) to interface %s (route flags %lx)\n", @@ -356,7 +366,8 @@ datalink_send_routed_data(struct net_route* route, net_buffer* buffer) // We set the interface address here, so the buffer is delivered // directly to the domain in interfaces.cpp:device_consumer_thread() - buffer->interface_address = address; + address->AcquireReference(); + set_interface_address(buffer->interface_address, address); // this one goes back to the domain directly return fifo_enqueue_buffer( @@ -408,7 +419,7 @@ datalink_send_data(net_protocol* protocol, net_domain* domain, &route); } else status = get_buffer_route(domain, buffer, &route); - + TRACE(" route status: %s\n", strerror(status)); if (status != B_OK) @@ -422,8 +433,10 @@ datalink_send_data(net_protocol* protocol, net_domain* domain, /*! 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 _interfaceAddress will be set to the interface address belonging to + that address if non-NULL. If the address \a _interfaceAddress points to + is not NULL, it is assumed that it already points to an address, which + is then released before the new address is assigned. \param _matchedType will be set to either zero or MSG_BCAST if non-NULL. */ static bool @@ -457,7 +470,7 @@ datalink_is_local_address(net_domain* domain, const struct sockaddr* address, TRACE(" it is, interface address %p\n", interfaceAddress); if (_interfaceAddress != NULL) - *_interfaceAddress = interfaceAddress; + set_interface_address(*_interfaceAddress, interfaceAddress); else interfaceAddress->ReleaseReference(); @@ -472,7 +485,10 @@ datalink_is_local_address(net_domain* domain, const struct sockaddr* address, \param unconfiguredOnly only unconfigured interfaces are taken into account. \param _interfaceAddress will be set to the first address of the interface - and domain belonging to that address if non-NULL. + and domain belonging to that address if non-NULL. If the address + \a _interfaceAddress points to is not NULL, it is assumed that it + already points to an address, which is then released before the new + address is assigned. */ static bool datalink_is_local_link_address(net_domain* domain, bool unconfiguredOnly, @@ -496,7 +512,7 @@ datalink_is_local_link_address(net_domain* domain, bool unconfiguredOnly, } if (_interfaceAddress != NULL) - *_interfaceAddress = interfaceAddress; + set_interface_address(*_interfaceAddress, interfaceAddress); else interfaceAddress->ReleaseReference(); diff --git a/src/add-ons/kernel/network/stack/device_interfaces.cpp b/src/add-ons/kernel/network/stack/device_interfaces.cpp index dc794c7b86..d7a861d0ca 100644 --- a/src/add-ons/kernel/network/stack/device_interfaces.cpp +++ b/src/add-ons/kernel/network/stack/device_interfaces.cpp @@ -59,7 +59,8 @@ device_reader_thread(void* _interface) if (atomic_get(&interface->monitor_count) > 0) device_interface_monitor_receive(interface, buffer); - buffer->interface_address = NULL; + ASSERT(buffer->interface_address == NULL); + if (interface->deframe_func(interface->device, buffer) != B_OK) { gNetBufferModule.free(buffer); continue; @@ -307,7 +308,7 @@ get_device_interface_address(net_device_interface* interface, address.sdl_alen = interface->device->address.length; memcpy(LLADDR(&address), interface->device->address.data, address.sdl_alen); - address.sdl_len = sizeof(sockaddr_dl) - sizeof(address.sdl_data) + address.sdl_len = sizeof(sockaddr_dl) - sizeof(address.sdl_data) + address.sdl_nlen + address.sdl_alen; }