started some work to properly handle device_removed() and setting interfaces down in general.
- remove all routes that use interfaces going down. - when a device is going down, remove associated domain interfaces. - interfaces weren't getting a properly referenced device interface, fixed. - down call down_device_interface when deleting a interface, instead set it down and let the upcounts do its job. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20600 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
0b10ed0573
commit
c64fecca78
@ -332,10 +332,7 @@ datalink_control(net_domain *_domain, int32 option, void *value,
|
||||
if (((uint32)request.ifr_flags & IFF_UP)
|
||||
!= (interface->flags & IFF_UP)) {
|
||||
if ((interface->flags & IFF_UP) != 0) {
|
||||
// bring the interface down
|
||||
interface->flags &= ~(IFF_UP | IFF_LINK);
|
||||
interface->first_info->interface_down(
|
||||
interface->first_protocol);
|
||||
interface_set_down(interface);
|
||||
} else {
|
||||
// bring it up
|
||||
status = interface->first_info->interface_up(
|
||||
@ -564,6 +561,8 @@ interface_protocol_down(net_datalink_protocol *_protocol)
|
||||
|
||||
deviceInterface->up_count--;
|
||||
|
||||
domain_interface_went_down(protocol->interface);
|
||||
|
||||
if (deviceInterface->up_count > 0)
|
||||
return;
|
||||
|
||||
|
@ -225,6 +225,49 @@ domain_interfaces_link_changed(net_device *device)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
domain_interface_went_down(net_interface *interface)
|
||||
{
|
||||
// the domain should be locked here. always check
|
||||
// all callers to be sure. We get here via
|
||||
// interface_set_down().
|
||||
|
||||
dprintf("domain_interface_went_down(%i, %s)\n",
|
||||
interface->domain->family, interface->name);
|
||||
|
||||
// domain might have been locked by:
|
||||
// - domain_removed_device_interface() <--- here
|
||||
// remove_interface_from_domain()
|
||||
// delete_interface()
|
||||
// interface_set_down()
|
||||
// - datalink_control() <--- here
|
||||
// interface_set_down()
|
||||
invalidate_routes(interface->domain, interface);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
domain_removed_device_interface(net_device_interface *interface)
|
||||
{
|
||||
BenaphoreLocker locker(sDomainLock);
|
||||
|
||||
net_domain_private *domain = NULL;
|
||||
while (true) {
|
||||
domain = (net_domain_private *)list_get_next_item(&sDomains, domain);
|
||||
if (domain == NULL)
|
||||
break;
|
||||
|
||||
BenaphoreLocker locker(domain->lock);
|
||||
|
||||
net_interface_private *priv = find_interface(domain, interface->name);
|
||||
if (priv == NULL)
|
||||
continue;
|
||||
|
||||
remove_interface_from_domain(priv);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
register_domain(int family, const char *name,
|
||||
struct net_protocol_module_info *module,
|
||||
|
@ -16,6 +16,9 @@
|
||||
#include <util/DoublyLinkedList.h>
|
||||
|
||||
|
||||
struct net_device_interface;
|
||||
|
||||
|
||||
struct net_domain_private : net_domain {
|
||||
struct list_link link;
|
||||
|
||||
@ -34,6 +37,8 @@ status_t list_domain_interfaces(void *buffer, size_t *_bufferSize);
|
||||
status_t add_interface_to_domain(net_domain *domain, struct ifreq& request);
|
||||
status_t remove_interface_from_domain(net_interface *interface);
|
||||
void domain_interfaces_link_changed(net_device *device);
|
||||
void domain_interface_went_down(net_interface *);
|
||||
void domain_removed_device_interface(net_device_interface *);
|
||||
|
||||
net_domain *get_domain(int family);
|
||||
status_t register_domain(int family, const char *name,
|
||||
|
@ -63,6 +63,16 @@ domain_receive_adapter(void *cookie, net_buffer *buffer)
|
||||
}
|
||||
|
||||
|
||||
net_device_interface *
|
||||
grab_device_interface(net_device_interface *interface)
|
||||
{
|
||||
if (interface == NULL || atomic_add(&interface->ref_count, 1) == 0)
|
||||
return NULL;
|
||||
|
||||
return interface;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - interfaces
|
||||
|
||||
|
||||
@ -135,7 +145,7 @@ create_interface(net_domain *domain, const char *name, const char *baseName,
|
||||
interface->type = 0;
|
||||
interface->mtu = deviceInterface->device->mtu;
|
||||
interface->metric = 0;
|
||||
interface->device_interface = deviceInterface;
|
||||
interface->device_interface = grab_device_interface(deviceInterface);
|
||||
|
||||
status_t status = get_domain_datalink_protocols(interface);
|
||||
if (status < B_OK) {
|
||||
@ -153,14 +163,33 @@ create_interface(net_domain *domain, const char *name, const char *baseName,
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
interface_set_down(net_interface *interface)
|
||||
{
|
||||
if ((interface->flags & IFF_UP) == 0)
|
||||
return;
|
||||
|
||||
// TODO: IFF_LINK should belong in device only
|
||||
interface->flags &= ~(IFF_UP | IFF_LINK);
|
||||
interface->first_info->interface_down(interface->first_protocol);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
delete_interface(net_interface_private *interface)
|
||||
{
|
||||
if ((interface->flags & IFF_UP) != 0) {
|
||||
// the interface is still up - we need to change that before deleting it
|
||||
interface->flags &= ~IFF_UP;
|
||||
down_device_interface(interface->device_interface);
|
||||
}
|
||||
// deleting an interface is fairly complex as we need
|
||||
// to clear all references to it throughout the stack
|
||||
|
||||
// this will possibly call (if IFF_UP):
|
||||
// interface_protocol_down()
|
||||
// domain_interface_went_down()
|
||||
// invalidate_routes()
|
||||
// remove_route()
|
||||
// update_route_infos()
|
||||
// get_route_internal()
|
||||
// down_device_interface() -- if upcount reaches 0
|
||||
interface_set_down(interface);
|
||||
|
||||
put_device_interface(interface->device_interface);
|
||||
|
||||
@ -388,9 +417,15 @@ down_device_interface(net_device_interface *interface)
|
||||
{
|
||||
net_device *device = interface->device;
|
||||
|
||||
dprintf("down_device_interface(%s)\n", interface->name);
|
||||
|
||||
device->flags &= ~IFF_UP;
|
||||
interface->module->down(device);
|
||||
|
||||
// TODO: there is a race condition between the previous
|
||||
// ->down and device->module->receive_data which
|
||||
// locks us here waiting for the reader_thread
|
||||
|
||||
// make sure the reader thread is gone before shutting down the interface
|
||||
status_t status;
|
||||
wait_for_thread(interface->reader_thread, &status);
|
||||
@ -600,7 +635,25 @@ status_t
|
||||
device_removed(net_device *device)
|
||||
{
|
||||
BenaphoreLocker locker(sInterfaceLock);
|
||||
// TODO: all what this function should do is to clear the IFF_UP flag of the interfaces.
|
||||
|
||||
net_device_interface *interface = find_device_interface(device->name);
|
||||
if (interface == NULL)
|
||||
return ENODEV;
|
||||
|
||||
// Propagate the loss of the device throughout the stack.
|
||||
// This is very complex, refer to delete_interface() for
|
||||
// further details.
|
||||
|
||||
// this will possibly call:
|
||||
// remove_interface_from_domain() [domain gets locked]
|
||||
// delete_interface()
|
||||
// ... [see delete_interface()]
|
||||
domain_removed_device_interface(interface);
|
||||
|
||||
// TODO: make sure all readers are gone
|
||||
// make sure all watchers are gone
|
||||
// remove device interface
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
@ -69,6 +69,7 @@ status_t create_interface(net_domain *domain, const char *name,
|
||||
const char *baseName, net_device_interface *deviceInterface,
|
||||
struct net_interface_private **_interface);
|
||||
void delete_interface(net_interface_private *interface);
|
||||
void interface_set_down(net_interface *);
|
||||
|
||||
// device interfaces
|
||||
void get_device_interface_address(net_device_interface *interface,
|
||||
|
@ -493,6 +493,28 @@ get_route_information(struct net_domain *_domain, void *value, size_t length)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
invalidate_routes(net_domain *_domain, net_interface *interface)
|
||||
{
|
||||
// this function is called with the domain locked
|
||||
// (see domain_interface_went_down)
|
||||
net_domain_private *domain = (net_domain_private *)_domain;
|
||||
|
||||
dprintf("invalidate_routes(%i, %s)\n", domain->family, interface->name);
|
||||
|
||||
RouteList::Iterator iterator = domain->routes.GetIterator();
|
||||
while (iterator.HasNext()) {
|
||||
net_route *route = iterator.Next();
|
||||
|
||||
// TODO handle refcounting, if the route needs to linger
|
||||
// for some reason we should set interface or
|
||||
// something of the sorts that invalidates it's reference
|
||||
if (route->interface == interface)
|
||||
remove_route(domain, route);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct net_route *
|
||||
get_route(struct net_domain *_domain, const struct sockaddr *address)
|
||||
{
|
||||
|
@ -39,6 +39,7 @@ status_t remove_route(struct net_domain *domain,
|
||||
const struct net_route *route);
|
||||
status_t get_route_information(struct net_domain *domain, void *buffer,
|
||||
size_t length);
|
||||
void invalidate_routes(net_domain *, net_interface *);
|
||||
struct net_route *get_route(struct net_domain *domain,
|
||||
const struct sockaddr *address);
|
||||
void put_route(struct net_domain *domain, struct net_route *route);
|
||||
|
Loading…
x
Reference in New Issue
Block a user