Support getting route information for a specific destination

using SIOCGETRT. Patch by Hugo Santos.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20494 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2007-04-01 12:06:16 +00:00
parent 694e5de9b0
commit 2d55afcdf7
5 changed files with 130 additions and 8 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2006, Haiku, Inc. All Rights Reserved.
* Copyright 2006-2007, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _NET_ROUTE_H
@ -27,6 +27,7 @@ struct route_entry {
struct sockaddr *destination;
struct sockaddr *mask;
struct sockaddr *gateway;
struct sockaddr *source;
uint32_t flags;
uint32_t mtu;
};

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2006, Haiku Inc. All Rights Reserved.
* Copyright 2002-2007, Haiku Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _SYS_SOCKIO_H
@ -36,6 +36,7 @@ enum {
SIOCGRTSIZE, /* get route table size */
SIOCGRTTABLE, /* get route table */
SIOCGETRT, /* get route information for destination */
SIOCGIFSTATS, /* get interface stats */
SIOCGIFPARAM, /* get interface parameter */
@ -53,4 +54,4 @@ enum {
SIOCGPGRP /* get process group */
};
#endif /* _SYS_SOCKIO_H */
#endif /* _SYS_SOCKIO_H */

View File

@ -305,6 +305,8 @@ datalink_control(net_domain *_domain, int32 option, void *value,
return list_routes(domain, config.ifc_buf, config.ifc_len);
}
case SIOCGETRT:
return get_route_information(domain, value, *_length);
default:
{

View File

@ -1,5 +1,5 @@
/*
* Copyright 2006, Haiku, Inc. All Rights Reserved.
* Copyright 2006-2007, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
@ -35,6 +35,51 @@
#endif
class UserRouteBuffer {
public:
UserRouteBuffer(uint8 *buffer, size_t available)
:
fBuffer(buffer),
fAvailable(available),
fStatus(B_OK)
{
}
sockaddr *
Copy(sockaddr *source)
{
sockaddr *target = (sockaddr *)fBuffer;
if (source == NULL || (fStatus = _Copy(source)) != B_OK)
return NULL;
return target;
}
status_t Status() const { return fStatus; }
private:
status_t
_Copy(sockaddr *source)
{
if (fAvailable < source->sa_len)
return ENOBUFS;
if (user_memcpy(fBuffer, source, source->sa_len) < B_OK)
return B_BAD_ADDRESS;
fAvailable -= source->sa_len;
fBuffer += source->sa_len;
return B_OK;
}
uint8 *fBuffer;
size_t fAvailable;
status_t fStatus;
};
net_route_private::net_route_private()
{
destination = mask = gateway = NULL;
@ -78,6 +123,25 @@ user_copy_address(const sockaddr *from, sockaddr **to)
}
static status_t
user_copy_address(const sockaddr *from, sockaddr_storage *to)
{
if (from == NULL)
return B_BAD_ADDRESS;
if (user_memcpy(to, from, sizeof(sockaddr)) < B_OK)
return B_BAD_ADDRESS;
if (to->ss_len > sizeof(sockaddr)) {
if (to->ss_len > sizeof(sockaddr_storage))
return B_BAD_VALUE;
if (user_memcpy(to, from, to->ss_len) < B_OK)
return B_BAD_ADDRESS;
}
return B_OK;
}
static net_route_private *
find_route(struct net_domain *_domain, const net_route *description)
{
@ -415,6 +479,55 @@ remove_route(struct net_domain *_domain, const struct net_route *removeRoute)
}
static status_t
fill_route_entry(route_entry *target, void *_buffer, size_t bufferSize,
net_route *route)
{
UserRouteBuffer buffer(((uint8 *)_buffer) + sizeof(route_entry),
bufferSize - sizeof(route_entry));
target->destination = buffer.Copy(route->destination);
target->mask = buffer.Copy(route->mask);
target->gateway = buffer.Copy(route->gateway);
target->source = buffer.Copy(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)
{
struct net_domain_private *domain = (net_domain_private *)_domain;
if (length < sizeof(route_entry))
return B_BAD_VALUE;
route_entry entry;
if (user_memcpy(&entry, value, sizeof(route_entry)) < B_OK)
return B_BAD_ADDRESS;
sockaddr_storage destination;
status_t status = user_copy_address(entry.destination, &destination);
if (status != B_OK)
return status;
BenaphoreLocker locker(domain->lock);
net_route_private *route = find_route(domain, (sockaddr *)&destination);
if (route == NULL)
return B_ENTRY_NOT_FOUND;
status = fill_route_entry(&entry, value, length, route);
if (status != B_OK)
return status;
return user_memcpy(value, &entry, sizeof(route_entry));
}
struct net_route *
get_route(struct net_domain *_domain, const struct sockaddr *address)
{

View File

@ -1,5 +1,5 @@
/*
* Copyright 2006, Haiku, Inc. All Rights Reserved.
* Copyright 2006-2007, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
@ -23,11 +23,13 @@ struct net_route_private : net_route, public DoublyLinkedListLinkImpl<net_route_
};
typedef DoublyLinkedList<net_route_private> RouteList;
typedef DoublyLinkedList<net_route_info, DoublyLinkedListCLink<net_route_info> > RouteInfoList;
typedef DoublyLinkedList<net_route_info,
DoublyLinkedListCLink<net_route_info> > RouteInfoList;
uint32 route_table_size(struct net_domain_private *domain);
status_t list_routes(struct net_domain_private *domain, void *buffer, size_t size);
status_t list_routes(struct net_domain_private *domain, void *buffer,
size_t size);
status_t control_routes(struct net_interface *interface,
int32 option, void *argument, size_t length);
@ -35,7 +37,10 @@ status_t add_route(struct net_domain *domain,
const struct net_route *route);
status_t remove_route(struct net_domain *domain,
const struct net_route *route);
struct net_route *get_route(struct net_domain *domain, const struct sockaddr *address);
status_t get_route_information(struct net_domain *domain, void *buffer,
size_t length);
struct net_route *get_route(struct net_domain *domain,
const struct sockaddr *address);
void put_route(struct net_domain *domain, struct net_route *route);
status_t register_route_info(struct net_domain *domain,