* There can now be one default route per interface, not just one
default route in the whole stack. The default routes are ordered by link speed, so faster interfaces are preferred. * find_route() by net_route now also checks for the equality of the RTF_DEFAULT flag * find_route() by address now ignores routes that point to interfaces that have no link; if you have more than one configured interface in your system, the one with a link is now always chosen. * get_route_internal() now recognizes AF_LINK addresses, and allows one to specify a route by interface this way. * Implemented update_route_info(). * Minor cleanup, moved copy_address(), and fill_route_entry() into the private part of the file. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@24423 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -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.
|
||||
*
|
||||
* Authors:
|
||||
@@ -50,7 +50,7 @@ net_route_private::~net_route_private()
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
// #pragma mark - private functions
|
||||
|
||||
|
||||
#if 0
|
||||
@@ -118,6 +118,7 @@ user_copy_address(const sockaddr *from, sockaddr_storage *to)
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static net_route_private *
|
||||
find_route(struct net_domain *_domain, const net_route *description)
|
||||
{
|
||||
@@ -129,14 +130,18 @@ find_route(struct net_domain *_domain, const net_route *description)
|
||||
|
||||
if ((route->flags & RTF_DEFAULT) != 0
|
||||
&& (description->flags & RTF_DEFAULT) != 0) {
|
||||
// there can only be one default route
|
||||
return route;
|
||||
// there can only be one default route per interface
|
||||
if (route->interface == description->interface)
|
||||
return route;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((route->flags & (RTF_GATEWAY | RTF_HOST | RTF_LOCAL)) ==
|
||||
(description->flags & (RTF_GATEWAY | RTF_HOST | RTF_LOCAL))
|
||||
&& domain->address_module->equal_masked_addresses(route->destination,
|
||||
description->destination, description->mask)
|
||||
if ((route->flags & (RTF_GATEWAY | RTF_HOST | RTF_LOCAL | RTF_DEFAULT))
|
||||
== (description->flags
|
||||
& (RTF_GATEWAY | RTF_HOST | RTF_LOCAL | RTF_DEFAULT))
|
||||
&& domain->address_module->equal_masked_addresses(
|
||||
route->destination, description->destination, description->mask)
|
||||
&& domain->address_module->equal_addresses(route->mask,
|
||||
description->mask)
|
||||
&& domain->address_module->equal_addresses(route->gateway,
|
||||
@@ -158,9 +163,15 @@ find_route(net_domain *_domain, const sockaddr *address)
|
||||
RouteList::Iterator iterator = domain->routes.GetIterator();
|
||||
TRACE(("test address %s for routes...\n", AddressString(domain, address).Data()));
|
||||
|
||||
// TODO: alternate equal default routes
|
||||
|
||||
while (iterator.HasNext()) {
|
||||
net_route_private *route = iterator.Next();
|
||||
|
||||
// ignore routes that point to devices that have no link
|
||||
if ((route->interface->device->flags & IFF_LINK) == 0)
|
||||
continue;
|
||||
|
||||
if (route->mask) {
|
||||
sockaddr maskedAddress;
|
||||
domain->address_module->mask_address(address, route->mask,
|
||||
@@ -171,7 +182,7 @@ find_route(net_domain *_domain, const sockaddr *address)
|
||||
} else if (!domain->address_module->equal_addresses(address,
|
||||
route->destination))
|
||||
continue;
|
||||
|
||||
|
||||
TRACE((" found route: %s, flags %lx\n",
|
||||
AddressString(domain, route->destination).Data(), route->flags));
|
||||
|
||||
@@ -200,7 +211,29 @@ static struct net_route *
|
||||
get_route_internal(struct net_domain_private *domain,
|
||||
const struct sockaddr *address)
|
||||
{
|
||||
net_route_private *route = find_route(domain, address);
|
||||
net_route_private *route = NULL;
|
||||
|
||||
if (address->sa_family == AF_LINK) {
|
||||
// special address to find an interface directly
|
||||
RouteList::Iterator iterator = domain->routes.GetIterator();
|
||||
const sockaddr_dl* link = (const sockaddr_dl*)address;
|
||||
|
||||
while (iterator.HasNext()) {
|
||||
route = iterator.Next();
|
||||
|
||||
net_device* device = route->interface->device;
|
||||
|
||||
if ((link->sdl_nlen > 0
|
||||
&& !strncmp(device->name, (const char*)link->sdl_data,
|
||||
IF_NAMESIZE))
|
||||
|| (link->sdl_nlen == 0 && link->sdl_alen > 0
|
||||
&& !memcmp(LLADDR(link), device->address.data,
|
||||
device->address.length)))
|
||||
break;
|
||||
}
|
||||
} else
|
||||
route = find_route(domain, address);
|
||||
|
||||
if (route != NULL && atomic_add(&route->ref_count, 1) == 0) {
|
||||
// route has been deleted already
|
||||
route = NULL;
|
||||
@@ -224,7 +257,35 @@ update_route_infos(struct net_domain_private *domain)
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
static sockaddr *
|
||||
copy_address(UserBuffer &buffer, sockaddr *address)
|
||||
{
|
||||
if (address == NULL)
|
||||
return NULL;
|
||||
|
||||
return (sockaddr *)buffer.Copy(address, address->sa_len);
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
fill_route_entry(route_entry *target, void *_buffer, size_t bufferSize,
|
||||
net_route *route)
|
||||
{
|
||||
UserBuffer buffer(((uint8 *)_buffer) + sizeof(route_entry),
|
||||
bufferSize - sizeof(route_entry));
|
||||
|
||||
target->destination = copy_address(buffer, route->destination);
|
||||
target->mask = copy_address(buffer, route->mask);
|
||||
target->gateway = copy_address(buffer, route->gateway);
|
||||
target->source = copy_address(buffer, route->interface->address);
|
||||
target->flags = route->flags;
|
||||
target->mtu = route->mtu;
|
||||
|
||||
return buffer.Status();
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - exported functions
|
||||
|
||||
|
||||
/*!
|
||||
@@ -307,10 +368,15 @@ list_routes(net_domain_private *domain, void *buffer, size_t size)
|
||||
request.ifr_route.mtu = route->mtu;
|
||||
request.ifr_route.flags = route->flags;
|
||||
|
||||
// copy data into userland buffer
|
||||
if (user_memcpy(buffer, &request, size) < B_OK
|
||||
|| (route->destination != NULL && user_memcpy(request.ifr_route.destination, route->destination, route->destination->sa_len) < B_OK)
|
||||
|| (route->mask != NULL && user_memcpy(request.ifr_route.mask, route->mask, route->mask->sa_len) < B_OK)
|
||||
|| (route->gateway != NULL && user_memcpy(request.ifr_route.gateway, route->gateway, route->gateway->sa_len) < B_OK))
|
||||
|| (route->destination != NULL
|
||||
&& user_memcpy(request.ifr_route.destination,
|
||||
route->destination, route->destination->sa_len) < B_OK)
|
||||
|| (route->mask != NULL && user_memcpy(request.ifr_route.mask,
|
||||
route->mask, route->mask->sa_len) < B_OK)
|
||||
|| (route->gateway != NULL && user_memcpy(request.ifr_route.gateway,
|
||||
route->gateway, route->gateway->sa_len) < B_OK))
|
||||
return B_BAD_ADDRESS;
|
||||
|
||||
buffer = (void *)next;
|
||||
@@ -322,7 +388,8 @@ list_routes(net_domain_private *domain, void *buffer, size_t size)
|
||||
|
||||
|
||||
status_t
|
||||
control_routes(struct net_interface *interface, int32 option, void *argument, size_t length)
|
||||
control_routes(struct net_interface *interface, int32 option, void *argument,
|
||||
size_t length)
|
||||
{
|
||||
net_domain_private *domain = (net_domain_private *)interface->domain;
|
||||
|
||||
@@ -335,14 +402,17 @@ control_routes(struct net_interface *interface, int32 option, void *argument, si
|
||||
return B_BAD_VALUE;
|
||||
|
||||
route_entry entry;
|
||||
if (user_memcpy(&entry, &((ifreq *)argument)->ifr_route, sizeof(route_entry)) != B_OK)
|
||||
if (user_memcpy(&entry, &((ifreq *)argument)->ifr_route,
|
||||
sizeof(route_entry)) != B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
|
||||
net_route_private route;
|
||||
status_t status;
|
||||
if ((status = user_copy_address(entry.destination, &route.destination)) != B_OK
|
||||
if ((status = user_copy_address(entry.destination,
|
||||
&route.destination)) != B_OK
|
||||
|| (status = user_copy_address(entry.mask, &route.mask)) != B_OK
|
||||
|| (status = user_copy_address(entry.gateway, &route.gateway)) != B_OK)
|
||||
|| (status = user_copy_address(entry.gateway, &route.gateway))
|
||||
!= B_OK)
|
||||
return status;
|
||||
|
||||
route.mtu = entry.mtu;
|
||||
@@ -416,6 +486,15 @@ add_route(struct net_domain *_domain, const struct net_route *newRoute)
|
||||
if (domain->address_module->first_mask_bit(before->mask)
|
||||
> domain->address_module->first_mask_bit(route->mask))
|
||||
break;
|
||||
|
||||
if ((route->flags & RTF_DEFAULT) != 0
|
||||
&& (before->flags & RTF_DEFAULT) != 0) {
|
||||
// both routes are equal - let the link speed decide the
|
||||
// order
|
||||
if (before->interface->device->link_speed
|
||||
< route->interface->device->link_speed)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
domain->routes.Insert(before, route);
|
||||
@@ -451,33 +530,6 @@ remove_route(struct net_domain *_domain, const struct net_route *removeRoute)
|
||||
}
|
||||
|
||||
|
||||
static sockaddr *
|
||||
copy_address(UserBuffer &buffer, sockaddr *address)
|
||||
{
|
||||
if (address == NULL)
|
||||
return NULL;
|
||||
|
||||
return (sockaddr *)buffer.Copy(address, address->sa_len);
|
||||
}
|
||||
|
||||
static status_t
|
||||
fill_route_entry(route_entry *target, void *_buffer, size_t bufferSize,
|
||||
net_route *route)
|
||||
{
|
||||
UserBuffer buffer(((uint8 *)_buffer) + sizeof(route_entry),
|
||||
bufferSize - sizeof(route_entry));
|
||||
|
||||
target->destination = copy_address(buffer, route->destination);
|
||||
target->mask = copy_address(buffer, route->mask);
|
||||
target->gateway = copy_address(buffer, route->gateway);
|
||||
target->source = copy_address(buffer, route->interface->address);
|
||||
target->flags = route->flags;
|
||||
target->mtu = route->mtu;
|
||||
|
||||
return buffer.Status();
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
get_route_information(struct net_domain *_domain, void *value, size_t length)
|
||||
{
|
||||
@@ -598,8 +650,7 @@ put_route(struct net_domain *_domain, net_route *route)
|
||||
|
||||
|
||||
status_t
|
||||
register_route_info(struct net_domain *_domain,
|
||||
struct net_route_info *info)
|
||||
register_route_info(struct net_domain *_domain, struct net_route_info *info)
|
||||
{
|
||||
struct net_domain_private *domain = (net_domain_private *)_domain;
|
||||
BenaphoreLocker locker(domain->lock);
|
||||
@@ -612,8 +663,7 @@ register_route_info(struct net_domain *_domain,
|
||||
|
||||
|
||||
status_t
|
||||
unregister_route_info(struct net_domain *_domain,
|
||||
struct net_route_info *info)
|
||||
unregister_route_info(struct net_domain *_domain, struct net_route_info *info)
|
||||
{
|
||||
struct net_domain_private *domain = (net_domain_private *)_domain;
|
||||
BenaphoreLocker locker(domain->lock);
|
||||
@@ -627,9 +677,13 @@ unregister_route_info(struct net_domain *_domain,
|
||||
|
||||
|
||||
status_t
|
||||
update_route_info(struct net_domain *domain,
|
||||
struct net_route_info *info)
|
||||
update_route_info(struct net_domain *_domain, struct net_route_info *info)
|
||||
{
|
||||
return B_ERROR;
|
||||
struct net_domain_private *domain = (net_domain_private *)_domain;
|
||||
BenaphoreLocker locker(domain->lock);
|
||||
|
||||
put_route_internal(domain, info->route);
|
||||
info->route = get_route_internal(domain, &info->address);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user