some getsockopt/setsockopt and multicast fixes.
* allow an ipv4 bind() to a multicast address. * bumped getsockopt/setsockopt kernel driver buffers to 256 bytes to at least handle structures which take one sockaddr_storage. * convert generic multicast delta API names to IPv4 ones before handling the specific option. * changed ipv4_getsockopt/ipv4_setsockopt a bit as the code gcc 2.95 was generating was a bit too funky. * properly pass setsockopt/getsockopt to handling protocols. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20939 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -59,9 +59,9 @@ struct net_socket_module_info {
|
|||||||
status_t (*receive_data)(net_socket *socket, size_t length, uint32 flags,
|
status_t (*receive_data)(net_socket *socket, size_t length, uint32 flags,
|
||||||
net_buffer **_buffer);
|
net_buffer **_buffer);
|
||||||
|
|
||||||
status_t (*get_option)(net_socket *socket, int option, void *value,
|
status_t (*get_option)(net_socket *socket, int level, int option,
|
||||||
int *_length);
|
void *value, int *_length);
|
||||||
status_t (*set_option)(net_socket *socket, int option,
|
status_t (*set_option)(net_socket *socket, int level, int option,
|
||||||
const void *value, int length);
|
const void *value, int length);
|
||||||
|
|
||||||
status_t (*get_next_stat)(uint32 *cookie, int family, struct net_stat *stat);
|
status_t (*get_next_stat)(uint32 *cookie, int family, struct net_stat *stat);
|
||||||
|
|||||||
@@ -428,9 +428,9 @@ net_stack_control(void *_cookie, uint32 op, void *data, size_t length)
|
|||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
char valueBuffer[128];
|
char valueBuffer[256];
|
||||||
if (args.length > (int)sizeof(valueBuffer))
|
if (args.length > (int)sizeof(valueBuffer))
|
||||||
args.length = (int)sizeof(valueBuffer);
|
return ENOBUFS;
|
||||||
|
|
||||||
status = sSocket->getsockopt(cookie->socket, args.level, args.option,
|
status = sSocket->getsockopt(cookie->socket, args.level, args.option,
|
||||||
valueBuffer, &args.length);
|
valueBuffer, &args.length);
|
||||||
@@ -451,9 +451,9 @@ net_stack_control(void *_cookie, uint32 op, void *data, size_t length)
|
|||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
char valueBuffer[128];
|
char valueBuffer[256];
|
||||||
if (args.length > (int)sizeof(valueBuffer))
|
if (args.length > (int)sizeof(valueBuffer))
|
||||||
return B_BAD_VALUE;
|
return ENOBUFS;
|
||||||
if (user_memcpy(valueBuffer, args.value, args.length) < B_OK)
|
if (user_memcpy(valueBuffer, args.value, args.length) < B_OK)
|
||||||
return B_BAD_ADDRESS;
|
return B_BAD_ADDRESS;
|
||||||
|
|
||||||
|
|||||||
@@ -882,7 +882,7 @@ ipv4_delta_membership(ipv4_protocol *protocol, int option,
|
|||||||
case IP_DROP_SOURCE_MEMBERSHIP:
|
case IP_DROP_SOURCE_MEMBERSHIP:
|
||||||
group = filter.GetGroup(*groupAddr, false);
|
group = filter.GetGroup(*groupAddr, false);
|
||||||
if (group == NULL) {
|
if (group == NULL) {
|
||||||
if (option == IP_DROP_SOURCE_MEMBERSHIP
|
if (option == IP_DROP_MEMBERSHIP
|
||||||
|| option == IP_DROP_SOURCE_MEMBERSHIP)
|
|| option == IP_DROP_SOURCE_MEMBERSHIP)
|
||||||
return EADDRNOTAVAIL;
|
return EADDRNOTAVAIL;
|
||||||
else
|
else
|
||||||
@@ -899,6 +899,28 @@ ipv4_delta_membership(ipv4_protocol *protocol, int option,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
generic_to_ipv4(int option)
|
||||||
|
{
|
||||||
|
switch (option) {
|
||||||
|
case MCAST_JOIN_GROUP:
|
||||||
|
return IP_ADD_MEMBERSHIP;
|
||||||
|
case MCAST_JOIN_SOURCE_GROUP:
|
||||||
|
return IP_ADD_SOURCE_MEMBERSHIP;
|
||||||
|
case MCAST_LEAVE_GROUP:
|
||||||
|
return IP_DROP_MEMBERSHIP;
|
||||||
|
case MCAST_BLOCK_SOURCE:
|
||||||
|
return IP_BLOCK_SOURCE;
|
||||||
|
case MCAST_UNBLOCK_SOURCE:
|
||||||
|
return IP_UNBLOCK_SOURCE;
|
||||||
|
case MCAST_LEAVE_SOURCE_GROUP:
|
||||||
|
return IP_DROP_SOURCE_MEMBERSHIP;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
ipv4_delta_membership(ipv4_protocol *protocol, int option,
|
ipv4_delta_membership(ipv4_protocol *protocol, int option,
|
||||||
in_addr *interfaceAddr, in_addr *groupAddr, in_addr *sourceAddr)
|
in_addr *interfaceAddr, in_addr *groupAddr, in_addr *sourceAddr)
|
||||||
@@ -918,8 +940,8 @@ ipv4_delta_membership(ipv4_protocol *protocol, int option,
|
|||||||
if (interface == NULL)
|
if (interface == NULL)
|
||||||
return ENODEV;
|
return ENODEV;
|
||||||
|
|
||||||
return ipv4_delta_membership(protocol, option, interface, groupAddr,
|
return ipv4_delta_membership(protocol, option, interface,
|
||||||
sourceAddr);
|
groupAddr, sourceAddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -945,8 +967,8 @@ ipv4_generic_delta_membership(ipv4_protocol *protocol, int option,
|
|||||||
if (_sourceAddr)
|
if (_sourceAddr)
|
||||||
sourceAddr = &((const sockaddr_in *)_sourceAddr)->sin_addr;
|
sourceAddr = &((const sockaddr_in *)_sourceAddr)->sin_addr;
|
||||||
|
|
||||||
return ipv4_delta_membership(protocol, option, interface, groupAddr,
|
return ipv4_delta_membership(protocol, generic_to_ipv4(option), interface,
|
||||||
sourceAddr);
|
groupAddr, sourceAddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1092,52 +1114,43 @@ ipv4_getsockopt(net_protocol *_protocol, int level, int option, void *value,
|
|||||||
{
|
{
|
||||||
ipv4_protocol *protocol = (ipv4_protocol *)_protocol;
|
ipv4_protocol *protocol = (ipv4_protocol *)_protocol;
|
||||||
|
|
||||||
// as we are the last protocol in the chain (i.e. no socket protocol
|
if (level == IPPROTO_IP) {
|
||||||
// below) we must call into the socket module directly.
|
if (option == IP_HDRINCL)
|
||||||
if (level == SOL_SOCKET)
|
|
||||||
return sSocketModule->get_option(protocol->socket, option, value,
|
|
||||||
_length);
|
|
||||||
else if (level != IPPROTO_IP)
|
|
||||||
return B_BAD_VALUE;
|
|
||||||
|
|
||||||
switch (option) {
|
|
||||||
case IP_HDRINCL:
|
|
||||||
return get_int_option(value, *_length,
|
return get_int_option(value, *_length,
|
||||||
(protocol->flags & IP_FLAG_HEADER_INCLUDED) != 0);
|
(protocol->flags & IP_FLAG_HEADER_INCLUDED) != 0);
|
||||||
|
else if (option == IP_TTL)
|
||||||
case IP_TTL:
|
|
||||||
return get_int_option(value, *_length, protocol->time_to_live);
|
return get_int_option(value, *_length, protocol->time_to_live);
|
||||||
|
else if (option == IP_TOS)
|
||||||
case IP_TOS:
|
|
||||||
return get_int_option(value, *_length, protocol->service_type);
|
return get_int_option(value, *_length, protocol->service_type);
|
||||||
|
else if (IP_MULTICAST_TTL)
|
||||||
case IP_MULTICAST_TTL:
|
|
||||||
return get_int_option(value, *_length,
|
return get_int_option(value, *_length,
|
||||||
protocol->multicast_time_to_live);
|
protocol->multicast_time_to_live);
|
||||||
|
else if (option == IP_ADD_MEMBERSHIP
|
||||||
case IP_ADD_MEMBERSHIP:
|
|| option == IP_DROP_MEMBERSHIP
|
||||||
case IP_DROP_MEMBERSHIP:
|
|| option == IP_BLOCK_SOURCE
|
||||||
case IP_BLOCK_SOURCE:
|
|| option == IP_UNBLOCK_SOURCE
|
||||||
case IP_UNBLOCK_SOURCE:
|
|| option == IP_ADD_SOURCE_MEMBERSHIP
|
||||||
case IP_ADD_SOURCE_MEMBERSHIP:
|
|| option == IP_DROP_SOURCE_MEMBERSHIP
|
||||||
case IP_DROP_SOURCE_MEMBERSHIP:
|
|| option == MCAST_JOIN_GROUP
|
||||||
case MCAST_JOIN_GROUP:
|
|| option == MCAST_LEAVE_GROUP
|
||||||
case MCAST_LEAVE_GROUP:
|
|| option == MCAST_BLOCK_SOURCE
|
||||||
case MCAST_BLOCK_SOURCE:
|
|| option == MCAST_UNBLOCK_SOURCE
|
||||||
case MCAST_UNBLOCK_SOURCE:
|
|| option == MCAST_JOIN_SOURCE_GROUP
|
||||||
case MCAST_JOIN_SOURCE_GROUP:
|
|| option == MCAST_LEAVE_SOURCE_GROUP) {
|
||||||
case MCAST_LEAVE_SOURCE_GROUP:
|
|
||||||
// RFC 3678, Section 4.1:
|
// RFC 3678, Section 4.1:
|
||||||
// ``An error of EOPNOTSUPP is returned if these options are
|
// ``An error of EOPNOTSUPP is returned if these options are
|
||||||
// used with getsockopt().''
|
// used with getsockopt().''
|
||||||
return EOPNOTSUPP;
|
return EOPNOTSUPP;
|
||||||
|
} else {
|
||||||
default:
|
|
||||||
dprintf("IPv4::getsockopt(): get unknown option: %d\n", option);
|
dprintf("IPv4::getsockopt(): get unknown option: %d\n", option);
|
||||||
return ENOPROTOOPT;
|
return ENOPROTOOPT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return sSocketModule->get_option(protocol->socket, level, option, value,
|
||||||
|
_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
ipv4_setsockopt(net_protocol *_protocol, int level, int option,
|
ipv4_setsockopt(net_protocol *_protocol, int level, int option,
|
||||||
@@ -1145,15 +1158,8 @@ ipv4_setsockopt(net_protocol *_protocol, int level, int option,
|
|||||||
{
|
{
|
||||||
ipv4_protocol *protocol = (ipv4_protocol *)_protocol;
|
ipv4_protocol *protocol = (ipv4_protocol *)_protocol;
|
||||||
|
|
||||||
if (level == SOL_SOCKET)
|
if (level == IPPROTO_IP) {
|
||||||
return sSocketModule->set_option(protocol->socket, option, value,
|
if (option == IP_HDRINCL) {
|
||||||
length);
|
|
||||||
else if (level != IPPROTO_IP)
|
|
||||||
return B_BAD_VALUE;
|
|
||||||
|
|
||||||
switch (option) {
|
|
||||||
case IP_HDRINCL:
|
|
||||||
{
|
|
||||||
int headerIncluded;
|
int headerIncluded;
|
||||||
if (length != sizeof(int))
|
if (length != sizeof(int))
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
@@ -1165,21 +1171,15 @@ ipv4_setsockopt(net_protocol *_protocol, int level, int option,
|
|||||||
else
|
else
|
||||||
protocol->flags &= ~IP_FLAG_HEADER_INCLUDED;
|
protocol->flags &= ~IP_FLAG_HEADER_INCLUDED;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
} else if (option == IP_TTL) {
|
||||||
|
|
||||||
case IP_TTL:
|
|
||||||
return set_int_option(protocol->time_to_live, value, length);
|
return set_int_option(protocol->time_to_live, value, length);
|
||||||
|
} else if (option == IP_TOS) {
|
||||||
case IP_TOS:
|
|
||||||
return set_int_option(protocol->service_type, value, length);
|
return set_int_option(protocol->service_type, value, length);
|
||||||
|
} else if (option == IP_MULTICAST_TTL) {
|
||||||
case IP_MULTICAST_TTL:
|
|
||||||
return set_int_option(protocol->multicast_time_to_live, value,
|
return set_int_option(protocol->multicast_time_to_live, value,
|
||||||
length);
|
length);
|
||||||
|
} else if (option == IP_ADD_MEMBERSHIP
|
||||||
case IP_ADD_MEMBERSHIP:
|
|| option == IP_DROP_MEMBERSHIP) {
|
||||||
case IP_DROP_MEMBERSHIP:
|
|
||||||
{
|
|
||||||
ip_mreq mreq;
|
ip_mreq mreq;
|
||||||
if (length != sizeof(ip_mreq))
|
if (length != sizeof(ip_mreq))
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
@@ -1188,13 +1188,10 @@ ipv4_setsockopt(net_protocol *_protocol, int level, int option,
|
|||||||
|
|
||||||
return ipv4_delta_membership(protocol, option, &mreq.imr_interface,
|
return ipv4_delta_membership(protocol, option, &mreq.imr_interface,
|
||||||
&mreq.imr_multiaddr, NULL);
|
&mreq.imr_multiaddr, NULL);
|
||||||
}
|
} else if (option == IP_BLOCK_SOURCE
|
||||||
|
|| option == IP_UNBLOCK_SOURCE
|
||||||
case IP_BLOCK_SOURCE:
|
|| option == IP_ADD_SOURCE_MEMBERSHIP
|
||||||
case IP_UNBLOCK_SOURCE:
|
|| option == IP_DROP_SOURCE_MEMBERSHIP) {
|
||||||
case IP_ADD_SOURCE_MEMBERSHIP:
|
|
||||||
case IP_DROP_SOURCE_MEMBERSHIP:
|
|
||||||
{
|
|
||||||
ip_mreq_source mreq;
|
ip_mreq_source mreq;
|
||||||
if (length != sizeof(ip_mreq_source))
|
if (length != sizeof(ip_mreq_source))
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
@@ -1203,11 +1200,8 @@ ipv4_setsockopt(net_protocol *_protocol, int level, int option,
|
|||||||
|
|
||||||
return ipv4_delta_membership(protocol, option, &mreq.imr_interface,
|
return ipv4_delta_membership(protocol, option, &mreq.imr_interface,
|
||||||
&mreq.imr_multiaddr, &mreq.imr_sourceaddr);
|
&mreq.imr_multiaddr, &mreq.imr_sourceaddr);
|
||||||
}
|
} else if (option == MCAST_LEAVE_GROUP
|
||||||
|
|| option == MCAST_JOIN_GROUP) {
|
||||||
case MCAST_JOIN_GROUP:
|
|
||||||
case MCAST_LEAVE_GROUP:
|
|
||||||
{
|
|
||||||
group_req greq;
|
group_req greq;
|
||||||
if (length != sizeof(group_req))
|
if (length != sizeof(group_req))
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
@@ -1216,13 +1210,10 @@ ipv4_setsockopt(net_protocol *_protocol, int level, int option,
|
|||||||
|
|
||||||
return ipv4_generic_delta_membership(protocol, option,
|
return ipv4_generic_delta_membership(protocol, option,
|
||||||
greq.gr_interface, &greq.gr_group, NULL);
|
greq.gr_interface, &greq.gr_group, NULL);
|
||||||
}
|
} else if (option == MCAST_BLOCK_SOURCE
|
||||||
|
|| option == MCAST_UNBLOCK_SOURCE
|
||||||
case MCAST_BLOCK_SOURCE:
|
|| option == MCAST_JOIN_SOURCE_GROUP
|
||||||
case MCAST_UNBLOCK_SOURCE:
|
|| option == MCAST_LEAVE_SOURCE_GROUP) {
|
||||||
case MCAST_JOIN_SOURCE_GROUP:
|
|
||||||
case MCAST_LEAVE_SOURCE_GROUP:
|
|
||||||
{
|
|
||||||
group_source_req greq;
|
group_source_req greq;
|
||||||
if (length != sizeof(group_source_req))
|
if (length != sizeof(group_source_req))
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
@@ -1231,14 +1222,16 @@ ipv4_setsockopt(net_protocol *_protocol, int level, int option,
|
|||||||
|
|
||||||
return ipv4_generic_delta_membership(protocol, option,
|
return ipv4_generic_delta_membership(protocol, option,
|
||||||
greq.gsr_interface, &greq.gsr_group, &greq.gsr_source);
|
greq.gsr_interface, &greq.gsr_group, &greq.gsr_source);
|
||||||
}
|
} else {
|
||||||
|
|
||||||
default:
|
|
||||||
dprintf("IPv4::setsockopt(): set unknown option: %d\n", option);
|
dprintf("IPv4::setsockopt(): set unknown option: %d\n", option);
|
||||||
return ENOPROTOOPT;
|
return ENOPROTOOPT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return sSocketModule->set_option(protocol->socket, level, option,
|
||||||
|
value, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
ipv4_bind(net_protocol *protocol, const struct sockaddr *address)
|
ipv4_bind(net_protocol *protocol, const struct sockaddr *address)
|
||||||
@@ -1248,6 +1241,7 @@ ipv4_bind(net_protocol *protocol, const struct sockaddr *address)
|
|||||||
|
|
||||||
// only INADDR_ANY and addresses of local interfaces are accepted:
|
// only INADDR_ANY and addresses of local interfaces are accepted:
|
||||||
if (((sockaddr_in *)address)->sin_addr.s_addr == INADDR_ANY
|
if (((sockaddr_in *)address)->sin_addr.s_addr == INADDR_ANY
|
||||||
|
|| IN_MULTICAST(((sockaddr_in *)address)->sin_addr.s_addr)
|
||||||
|| sDatalinkModule->is_local_address(sDomain, address, NULL, NULL)) {
|
|| sDatalinkModule->is_local_address(sDomain, address, NULL, NULL)) {
|
||||||
memcpy(&protocol->socket->address, address, sizeof(struct sockaddr_in));
|
memcpy(&protocol->socket->address, address, sizeof(struct sockaddr_in));
|
||||||
protocol->socket->address.ss_len = sizeof(struct sockaddr_in);
|
protocol->socket->address.ss_len = sizeof(struct sockaddr_in);
|
||||||
|
|||||||
@@ -642,8 +642,12 @@ socket_getsockname(net_socket *socket, struct sockaddr *address, socklen_t *_add
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
socket_get_option(net_socket *socket, int option, void *value, int *_length)
|
socket_get_option(net_socket *socket, int level, int option, void *value,
|
||||||
|
int *_length)
|
||||||
{
|
{
|
||||||
|
if (level != SOL_SOCKET)
|
||||||
|
return ENOPROTOOPT;
|
||||||
|
|
||||||
switch (option) {
|
switch (option) {
|
||||||
case SO_SNDBUF:
|
case SO_SNDBUF:
|
||||||
{
|
{
|
||||||
@@ -747,20 +751,14 @@ int
|
|||||||
socket_getsockopt(net_socket *socket, int level, int option, void *value,
|
socket_getsockopt(net_socket *socket, int level, int option, void *value,
|
||||||
int *_length)
|
int *_length)
|
||||||
{
|
{
|
||||||
status_t status = (level == SOL_SOCKET) ? B_OK : B_BAD_VALUE;
|
for (net_protocol *protocol = socket->first_protocol;
|
||||||
|
protocol; protocol = protocol->next) {
|
||||||
|
if (protocol->module->getsockopt)
|
||||||
|
return protocol->module->getsockopt(protocol, level, option,
|
||||||
|
value, _length);
|
||||||
|
}
|
||||||
|
|
||||||
net_protocol *protocol = socket->first_protocol;
|
return socket_get_option(socket, level, option, value, _length);
|
||||||
while (protocol && protocol->module->getsockopt == NULL)
|
|
||||||
protocol = protocol->next;
|
|
||||||
|
|
||||||
if (protocol)
|
|
||||||
status = protocol->module->getsockopt(protocol, level,
|
|
||||||
option, value, _length);
|
|
||||||
|
|
||||||
if (status < B_OK)
|
|
||||||
return status;
|
|
||||||
|
|
||||||
return socket_get_option(socket, option, value, _length);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -958,9 +956,12 @@ socket_send(net_socket *socket, msghdr *header, const void *data,
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
socket_set_option(net_socket *socket, int option, const void *value,
|
socket_set_option(net_socket *socket, int level, int option, const void *value,
|
||||||
int length)
|
int length)
|
||||||
{
|
{
|
||||||
|
if (level != SOL_SOCKET)
|
||||||
|
return ENOPROTOOPT;
|
||||||
|
|
||||||
switch (option) {
|
switch (option) {
|
||||||
// TODO: implement other options!
|
// TODO: implement other options!
|
||||||
case SO_LINGER:
|
case SO_LINGER:
|
||||||
@@ -1068,20 +1069,14 @@ int
|
|||||||
socket_setsockopt(net_socket *socket, int level, int option, const void *value,
|
socket_setsockopt(net_socket *socket, int level, int option, const void *value,
|
||||||
int length)
|
int length)
|
||||||
{
|
{
|
||||||
status_t status = (level == SOL_SOCKET) ? B_OK : B_BAD_VALUE;
|
for (net_protocol *protocol = socket->first_protocol;
|
||||||
|
protocol; protocol = protocol->next) {
|
||||||
net_protocol *protocol = socket->first_protocol;
|
if (protocol->module->setsockopt)
|
||||||
while (protocol && protocol->module->setsockopt == NULL)
|
return protocol->module->setsockopt(protocol, level, option,
|
||||||
protocol = protocol->next;
|
|
||||||
|
|
||||||
if (protocol)
|
|
||||||
status = protocol->module->setsockopt(protocol, level, option,
|
|
||||||
value, length);
|
value, length);
|
||||||
|
}
|
||||||
|
|
||||||
if (status < B_OK)
|
return socket_set_option(socket, level, option, value, length);
|
||||||
return status;
|
|
||||||
|
|
||||||
return socket_set_option(socket, option, value, length);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user