* Actually implemented the SO_BINDTODEVICE socket option I added some time ago.

* This makes it possible to select a specific device, even if no interface
  has been configured for it yet. To make it work, each interface now has a
  private direct route which will be returned if a socket is bound to a device.
* This will be used for example in DHCP to make it work when more than one
  adapter is attached.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27983 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2008-10-11 22:10:31 +00:00
parent 11f2701ecf
commit 27e0dea9f0
7 changed files with 81 additions and 20 deletions
+1
View File
@@ -29,6 +29,7 @@ typedef struct net_socket {
int options; int options;
int linger; int linger;
int bound_to_device;
struct { struct {
uint32 buffer_size; uint32 buffer_size;
@@ -219,7 +219,7 @@ datalink_control_interface(net_domain_private *domain, int32 option,
if (interface) if (interface)
strlcpy(request.ifr_name, interface->name, IF_NAMESIZE); strlcpy(request.ifr_name, interface->name, IF_NAMESIZE);
else else
status = B_BAD_VALUE; // TODO should be ENXIO? status = B_BAD_VALUE; // TODO: should be ENXIO?
break; break;
} }
@@ -386,7 +386,12 @@ datalink_send_datagram(net_protocol *protocol, net_domain *domain,
domain = protocol->module->get_domain(protocol); domain = protocol->module->get_domain(protocol);
net_route *route = NULL; net_route *route = NULL;
status_t status = get_buffer_route(domain, buffer, &route); status_t status;
if (protocol->socket->bound_to_device > 0) {
status = get_device_route(domain, protocol->socket->bound_to_device,
&route);
} else
status = get_buffer_route(domain, buffer, &route);
if (status < B_OK) if (status < B_OK)
return status; return status;
@@ -258,6 +258,16 @@ create_interface(net_domain *domain, const char *name, const char *baseName,
interface->metric = 0; interface->metric = 0;
interface->device_interface = grab_device_interface(deviceInterface); interface->device_interface = grab_device_interface(deviceInterface);
// setup direct route for bound devices
interface->direct_route.destination = NULL;
interface->direct_route.mask = NULL;
interface->direct_route.gateway = NULL;
interface->direct_route.flags = 0;
interface->direct_route.mtu = 0;
interface->direct_route.interface = interface;
interface->direct_route.ref_count = 1;
// make sure this doesn't get deleted accidently
status_t status = get_domain_datalink_protocols(interface); status_t status = get_domain_datalink_protocols(interface);
if (status < B_OK) { if (status < B_OK) {
delete interface; delete interface;
@@ -50,6 +50,7 @@ typedef DoublyLinkedList<net_device_interface> DeviceInterfaceList;
struct net_interface_private : net_interface { struct net_interface_private : net_interface {
char base_name[IF_NAMESIZE]; char base_name[IF_NAMESIZE];
net_device_interface *device_interface; net_device_interface *device_interface;
net_route_private direct_route;
}; };
@@ -1326,6 +1326,21 @@ socket_set_option(net_socket *socket, int level, int option, const void *value,
socket->options &= ~option; socket->options &= ~option;
return B_OK; return B_OK;
case SO_BINDTODEVICE:
{
if (length != sizeof(int32))
return B_BAD_VALUE;
int index = *(const int32 *)value;
if (index < 0)
return B_BAD_VALUE;
// TODO: we might want to check if the device exists at all
// (although it doesn't really harm when we don't)
socket->bound_to_device = index;
return B_OK;
}
default: default:
break; break;
} }
@@ -8,6 +8,7 @@
#include "domains.h" #include "domains.h"
#include "interfaces.h"
#include "routes.h" #include "routes.h"
#include "stack_private.h" #include "stack_private.h"
#include "utility.h" #include "utility.h"
@@ -607,6 +608,32 @@ get_route(struct net_domain *_domain, const struct sockaddr *address)
} }
status_t
get_device_route(struct net_domain *_domain, uint32 index, net_route **_route)
{
net_domain_private *domain = (net_domain_private *)_domain;
MutexLocker _(domain->lock);
net_interface_private *interface = NULL;
while (true) {
interface = (net_interface_private *)list_get_next_item(
&domain->interfaces, interface);
if (interface == NULL)
break;
if (interface->device->index == index) {
atomic_add(&interface->direct_route.ref_count, 1);
*_route = &interface->direct_route;
return B_OK;
}
}
return ENETUNREACH;
}
status_t status_t
get_buffer_route(net_domain *_domain, net_buffer *buffer, net_route **_route) get_buffer_route(net_domain *_domain, net_buffer *buffer, net_route **_route)
{ {
+3 -1
View File
@@ -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. * Distributed under the terms of the MIT License.
* *
* Authors: * Authors:
@@ -42,6 +42,8 @@ status_t get_route_information(struct net_domain *domain, void *buffer,
void invalidate_routes(net_domain *, net_interface *); void invalidate_routes(net_domain *, net_interface *);
struct net_route *get_route(struct net_domain *domain, struct net_route *get_route(struct net_domain *domain,
const struct sockaddr *address); const struct sockaddr *address);
status_t get_device_route(struct net_domain *domain, uint32 index,
struct net_route **_route);
status_t get_buffer_route(struct net_domain *domain, status_t get_buffer_route(struct net_domain *domain,
struct net_buffer *buffer, struct net_route **_route); struct net_buffer *buffer, struct net_route **_route);
void put_route(struct net_domain *domain, struct net_route *route); void put_route(struct net_domain *domain, struct net_route *route);