* 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:
@@ -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;
|
||||||
|
|||||||
@@ -208,19 +208,19 @@ datalink_control_interface(net_domain_private *domain, int32 option,
|
|||||||
status_t status = (interface == NULL) ? ENODEV : B_OK;
|
status_t status = (interface == NULL) ? ENODEV : B_OK;
|
||||||
|
|
||||||
switch (option) {
|
switch (option) {
|
||||||
case SIOCGIFINDEX:
|
case SIOCGIFINDEX:
|
||||||
if (interface)
|
if (interface)
|
||||||
request.ifr_index = interface->index;
|
request.ifr_index = interface->index;
|
||||||
else
|
else
|
||||||
request.ifr_index = 0;
|
request.ifr_index = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SIOCGIFNAME:
|
case SIOCGIFNAME:
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
@@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ process_ancillary_data(net_socket *socket, ancillary_data_container* container,
|
|||||||
return bytesWritten;
|
return bytesWritten;
|
||||||
|
|
||||||
dataBuffer += bytesWritten;
|
dataBuffer += bytesWritten;
|
||||||
dataBufferLen -= bytesWritten;
|
dataBufferLen -= bytesWritten;
|
||||||
}
|
}
|
||||||
|
|
||||||
messageHeader->msg_controllen -= dataBufferLen;
|
messageHeader->msg_controllen -= dataBufferLen;
|
||||||
@@ -235,7 +235,7 @@ socket_open(int family, int type, int protocol, net_socket **_socket)
|
|||||||
status_t status = create_socket(family, type, protocol, &socket);
|
status_t status = create_socket(family, type, protocol, &socket);
|
||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
status = socket->first_info->open(socket->first_protocol);
|
status = socket->first_info->open(socket->first_protocol);
|
||||||
if (status < B_OK) {
|
if (status < B_OK) {
|
||||||
socket_delete(socket);
|
socket_delete(socket);
|
||||||
@@ -570,7 +570,7 @@ socket_set_max_backlog(net_socket *_socket, uint32 backlog)
|
|||||||
mutex_lock(&socket->lock);
|
mutex_lock(&socket->lock);
|
||||||
|
|
||||||
// first remove the pending connections, then the already connected
|
// first remove the pending connections, then the already connected
|
||||||
// ones as needed
|
// ones as needed
|
||||||
net_socket_private *child;
|
net_socket_private *child;
|
||||||
while (socket->child_count > backlog
|
while (socket->child_count > backlog
|
||||||
&& (child = (net_socket_private *)list_remove_tail_item(
|
&& (child = (net_socket_private *)list_remove_tail_item(
|
||||||
@@ -764,7 +764,7 @@ socket_bind(net_socket *socket, const struct sockaddr *address,
|
|||||||
|
|
||||||
memcpy(&socket->address, address, sizeof(sockaddr));
|
memcpy(&socket->address, address, sizeof(sockaddr));
|
||||||
|
|
||||||
status_t status = socket->first_info->bind(socket->first_protocol,
|
status_t status = socket->first_info->bind(socket->first_protocol,
|
||||||
(sockaddr *)address);
|
(sockaddr *)address);
|
||||||
if (status < B_OK) {
|
if (status < B_OK) {
|
||||||
// clear address again, as binding failed
|
// clear address again, as binding failed
|
||||||
@@ -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;
|
||||||
}
|
}
|
||||||
@@ -1373,7 +1388,7 @@ socket_socketpair(int family, int type, int protocol, net_socket* sockets[2])
|
|||||||
if (error == B_OK)
|
if (error == B_OK)
|
||||||
error = socket_listen(sockets[0], 1);
|
error = socket_listen(sockets[0], 1);
|
||||||
|
|
||||||
// connect them
|
// connect them
|
||||||
if (error == B_OK) {
|
if (error == B_OK) {
|
||||||
error = socket_connect(sockets[1], (sockaddr*)&sockets[0]->address,
|
error = socket_connect(sockets[1], (sockaddr*)&sockets[0]->address,
|
||||||
sockets[0]->address.ss_len);
|
sockets[0]->address.ss_len);
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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,8 +42,10 @@ 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);
|
||||||
|
|
||||||
status_t register_route_info(struct net_domain *domain,
|
status_t register_route_info(struct net_domain *domain,
|
||||||
|
|||||||
Reference in New Issue
Block a user