diff --git a/headers/posix/net/route.h b/headers/posix/net/route.h index c024aafb80..fce5524716 100644 --- a/headers/posix/net/route.h +++ b/headers/posix/net/route.h @@ -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; }; diff --git a/headers/posix/sys/sockio.h b/headers/posix/sys/sockio.h index 1508b489c4..6fae7d04d4 100644 --- a/headers/posix/sys/sockio.h +++ b/headers/posix/sys/sockio.h @@ -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 */ diff --git a/src/add-ons/kernel/network/stack/datalink.cpp b/src/add-ons/kernel/network/stack/datalink.cpp index 6688a3d4a9..9b6e45e262 100644 --- a/src/add-ons/kernel/network/stack/datalink.cpp +++ b/src/add-ons/kernel/network/stack/datalink.cpp @@ -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: { diff --git a/src/add-ons/kernel/network/stack/routes.cpp b/src/add-ons/kernel/network/stack/routes.cpp index 8c0558ecfa..b7af98c942 100644 --- a/src/add-ons/kernel/network/stack/routes.cpp +++ b/src/add-ons/kernel/network/stack/routes.cpp @@ -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) { diff --git a/src/add-ons/kernel/network/stack/routes.h b/src/add-ons/kernel/network/stack/routes.h index 2148171191..98f7519830 100644 --- a/src/add-ons/kernel/network/stack/routes.h +++ b/src/add-ons/kernel/network/stack/routes.h @@ -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 RouteList; -typedef DoublyLinkedList > RouteInfoList; +typedef DoublyLinkedList > 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,