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,
|
||||
net_buffer **_buffer);
|
||||
|
||||
status_t (*get_option)(net_socket *socket, int option, void *value,
|
||||
int *_length);
|
||||
status_t (*set_option)(net_socket *socket, int option,
|
||||
status_t (*get_option)(net_socket *socket, int level, int option,
|
||||
void *value, int *_length);
|
||||
status_t (*set_option)(net_socket *socket, int level, int option,
|
||||
const void *value, int length);
|
||||
|
||||
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)
|
||||
return status;
|
||||
|
||||
char valueBuffer[128];
|
||||
char valueBuffer[256];
|
||||
if (args.length > (int)sizeof(valueBuffer))
|
||||
args.length = (int)sizeof(valueBuffer);
|
||||
return ENOBUFS;
|
||||
|
||||
status = sSocket->getsockopt(cookie->socket, args.level, args.option,
|
||||
valueBuffer, &args.length);
|
||||
@@ -451,9 +451,9 @@ net_stack_control(void *_cookie, uint32 op, void *data, size_t length)
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
char valueBuffer[128];
|
||||
char valueBuffer[256];
|
||||
if (args.length > (int)sizeof(valueBuffer))
|
||||
return B_BAD_VALUE;
|
||||
return ENOBUFS;
|
||||
if (user_memcpy(valueBuffer, args.value, args.length) < B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
|
||||
|
||||
@@ -882,7 +882,7 @@ ipv4_delta_membership(ipv4_protocol *protocol, int option,
|
||||
case IP_DROP_SOURCE_MEMBERSHIP:
|
||||
group = filter.GetGroup(*groupAddr, false);
|
||||
if (group == NULL) {
|
||||
if (option == IP_DROP_SOURCE_MEMBERSHIP
|
||||
if (option == IP_DROP_MEMBERSHIP
|
||||
|| option == IP_DROP_SOURCE_MEMBERSHIP)
|
||||
return EADDRNOTAVAIL;
|
||||
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
|
||||
ipv4_delta_membership(ipv4_protocol *protocol, int option,
|
||||
in_addr *interfaceAddr, in_addr *groupAddr, in_addr *sourceAddr)
|
||||
@@ -918,8 +940,8 @@ ipv4_delta_membership(ipv4_protocol *protocol, int option,
|
||||
if (interface == NULL)
|
||||
return ENODEV;
|
||||
|
||||
return ipv4_delta_membership(protocol, option, interface, groupAddr,
|
||||
sourceAddr);
|
||||
return ipv4_delta_membership(protocol, option, interface,
|
||||
groupAddr, sourceAddr);
|
||||
}
|
||||
|
||||
|
||||
@@ -945,8 +967,8 @@ ipv4_generic_delta_membership(ipv4_protocol *protocol, int option,
|
||||
if (_sourceAddr)
|
||||
sourceAddr = &((const sockaddr_in *)_sourceAddr)->sin_addr;
|
||||
|
||||
return ipv4_delta_membership(protocol, option, interface, groupAddr,
|
||||
sourceAddr);
|
||||
return ipv4_delta_membership(protocol, generic_to_ipv4(option), interface,
|
||||
groupAddr, sourceAddr);
|
||||
}
|
||||
|
||||
|
||||
@@ -1092,50 +1114,41 @@ ipv4_getsockopt(net_protocol *_protocol, int level, int option, void *value,
|
||||
{
|
||||
ipv4_protocol *protocol = (ipv4_protocol *)_protocol;
|
||||
|
||||
// as we are the last protocol in the chain (i.e. no socket protocol
|
||||
// below) we must call into the socket module directly.
|
||||
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:
|
||||
if (level == IPPROTO_IP) {
|
||||
if (option == IP_HDRINCL)
|
||||
return get_int_option(value, *_length,
|
||||
(protocol->flags & IP_FLAG_HEADER_INCLUDED) != 0);
|
||||
|
||||
case IP_TTL:
|
||||
else if (option == IP_TTL)
|
||||
return get_int_option(value, *_length, protocol->time_to_live);
|
||||
|
||||
case IP_TOS:
|
||||
else if (option == IP_TOS)
|
||||
return get_int_option(value, *_length, protocol->service_type);
|
||||
|
||||
case IP_MULTICAST_TTL:
|
||||
else if (IP_MULTICAST_TTL)
|
||||
return get_int_option(value, *_length,
|
||||
protocol->multicast_time_to_live);
|
||||
|
||||
case IP_ADD_MEMBERSHIP:
|
||||
case IP_DROP_MEMBERSHIP:
|
||||
case IP_BLOCK_SOURCE:
|
||||
case IP_UNBLOCK_SOURCE:
|
||||
case IP_ADD_SOURCE_MEMBERSHIP:
|
||||
case IP_DROP_SOURCE_MEMBERSHIP:
|
||||
case MCAST_JOIN_GROUP:
|
||||
case MCAST_LEAVE_GROUP:
|
||||
case MCAST_BLOCK_SOURCE:
|
||||
case MCAST_UNBLOCK_SOURCE:
|
||||
case MCAST_JOIN_SOURCE_GROUP:
|
||||
case MCAST_LEAVE_SOURCE_GROUP:
|
||||
// RFC 3678, Section 4.1:
|
||||
// ``An error of EOPNOTSUPP is returned if these options are
|
||||
// used with getsockopt().''
|
||||
return EOPNOTSUPP;
|
||||
|
||||
default:
|
||||
else if (option == IP_ADD_MEMBERSHIP
|
||||
|| option == IP_DROP_MEMBERSHIP
|
||||
|| option == IP_BLOCK_SOURCE
|
||||
|| option == IP_UNBLOCK_SOURCE
|
||||
|| option == IP_ADD_SOURCE_MEMBERSHIP
|
||||
|| option == IP_DROP_SOURCE_MEMBERSHIP
|
||||
|| option == MCAST_JOIN_GROUP
|
||||
|| option == MCAST_LEAVE_GROUP
|
||||
|| option == MCAST_BLOCK_SOURCE
|
||||
|| option == MCAST_UNBLOCK_SOURCE
|
||||
|| option == MCAST_JOIN_SOURCE_GROUP
|
||||
|| option == MCAST_LEAVE_SOURCE_GROUP) {
|
||||
// RFC 3678, Section 4.1:
|
||||
// ``An error of EOPNOTSUPP is returned if these options are
|
||||
// used with getsockopt().''
|
||||
return EOPNOTSUPP;
|
||||
} else {
|
||||
dprintf("IPv4::getsockopt(): get unknown option: %d\n", option);
|
||||
return ENOPROTOOPT;
|
||||
}
|
||||
}
|
||||
|
||||
return sSocketModule->get_option(protocol->socket, level, option, value,
|
||||
_length);
|
||||
}
|
||||
|
||||
|
||||
@@ -1145,15 +1158,8 @@ ipv4_setsockopt(net_protocol *_protocol, int level, int option,
|
||||
{
|
||||
ipv4_protocol *protocol = (ipv4_protocol *)_protocol;
|
||||
|
||||
if (level == SOL_SOCKET)
|
||||
return sSocketModule->set_option(protocol->socket, option, value,
|
||||
length);
|
||||
else if (level != IPPROTO_IP)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
switch (option) {
|
||||
case IP_HDRINCL:
|
||||
{
|
||||
if (level == IPPROTO_IP) {
|
||||
if (option == IP_HDRINCL) {
|
||||
int headerIncluded;
|
||||
if (length != sizeof(int))
|
||||
return B_BAD_VALUE;
|
||||
@@ -1165,21 +1171,15 @@ ipv4_setsockopt(net_protocol *_protocol, int level, int option,
|
||||
else
|
||||
protocol->flags &= ~IP_FLAG_HEADER_INCLUDED;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
case IP_TTL:
|
||||
} else if (option == IP_TTL) {
|
||||
return set_int_option(protocol->time_to_live, value, length);
|
||||
|
||||
case IP_TOS:
|
||||
} else if (option == IP_TOS) {
|
||||
return set_int_option(protocol->service_type, value, length);
|
||||
|
||||
case IP_MULTICAST_TTL:
|
||||
} else if (option == IP_MULTICAST_TTL) {
|
||||
return set_int_option(protocol->multicast_time_to_live, value,
|
||||
length);
|
||||
|
||||
case IP_ADD_MEMBERSHIP:
|
||||
case IP_DROP_MEMBERSHIP:
|
||||
{
|
||||
} else if (option == IP_ADD_MEMBERSHIP
|
||||
|| option == IP_DROP_MEMBERSHIP) {
|
||||
ip_mreq mreq;
|
||||
if (length != sizeof(ip_mreq))
|
||||
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,
|
||||
&mreq.imr_multiaddr, NULL);
|
||||
}
|
||||
|
||||
case IP_BLOCK_SOURCE:
|
||||
case IP_UNBLOCK_SOURCE:
|
||||
case IP_ADD_SOURCE_MEMBERSHIP:
|
||||
case IP_DROP_SOURCE_MEMBERSHIP:
|
||||
{
|
||||
} else if (option == IP_BLOCK_SOURCE
|
||||
|| option == IP_UNBLOCK_SOURCE
|
||||
|| option == IP_ADD_SOURCE_MEMBERSHIP
|
||||
|| option == IP_DROP_SOURCE_MEMBERSHIP) {
|
||||
ip_mreq_source mreq;
|
||||
if (length != sizeof(ip_mreq_source))
|
||||
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,
|
||||
&mreq.imr_multiaddr, &mreq.imr_sourceaddr);
|
||||
}
|
||||
|
||||
case MCAST_JOIN_GROUP:
|
||||
case MCAST_LEAVE_GROUP:
|
||||
{
|
||||
} else if (option == MCAST_LEAVE_GROUP
|
||||
|| option == MCAST_JOIN_GROUP) {
|
||||
group_req greq;
|
||||
if (length != sizeof(group_req))
|
||||
return B_BAD_VALUE;
|
||||
@@ -1216,13 +1210,10 @@ ipv4_setsockopt(net_protocol *_protocol, int level, int option,
|
||||
|
||||
return ipv4_generic_delta_membership(protocol, option,
|
||||
greq.gr_interface, &greq.gr_group, NULL);
|
||||
}
|
||||
|
||||
case MCAST_BLOCK_SOURCE:
|
||||
case MCAST_UNBLOCK_SOURCE:
|
||||
case MCAST_JOIN_SOURCE_GROUP:
|
||||
case MCAST_LEAVE_SOURCE_GROUP:
|
||||
{
|
||||
} else if (option == MCAST_BLOCK_SOURCE
|
||||
|| option == MCAST_UNBLOCK_SOURCE
|
||||
|| option == MCAST_JOIN_SOURCE_GROUP
|
||||
|| option == MCAST_LEAVE_SOURCE_GROUP) {
|
||||
group_source_req greq;
|
||||
if (length != sizeof(group_source_req))
|
||||
return B_BAD_VALUE;
|
||||
@@ -1231,12 +1222,14 @@ ipv4_setsockopt(net_protocol *_protocol, int level, int option,
|
||||
|
||||
return ipv4_generic_delta_membership(protocol, option,
|
||||
greq.gsr_interface, &greq.gsr_group, &greq.gsr_source);
|
||||
}
|
||||
|
||||
default:
|
||||
} else {
|
||||
dprintf("IPv4::setsockopt(): set unknown option: %d\n", option);
|
||||
return ENOPROTOOPT;
|
||||
}
|
||||
}
|
||||
|
||||
return sSocketModule->set_option(protocol->socket, level, option,
|
||||
value, length);
|
||||
}
|
||||
|
||||
|
||||
@@ -1248,6 +1241,7 @@ ipv4_bind(net_protocol *protocol, const struct sockaddr *address)
|
||||
|
||||
// only INADDR_ANY and addresses of local interfaces are accepted:
|
||||
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)) {
|
||||
memcpy(&protocol->socket->address, address, 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
|
||||
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) {
|
||||
case SO_SNDBUF:
|
||||
{
|
||||
@@ -747,20 +751,14 @@ int
|
||||
socket_getsockopt(net_socket *socket, int level, int option, void *value,
|
||||
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;
|
||||
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);
|
||||
return socket_get_option(socket, level, option, value, _length);
|
||||
}
|
||||
|
||||
|
||||
@@ -958,9 +956,12 @@ socket_send(net_socket *socket, msghdr *header, const void *data,
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
if (level != SOL_SOCKET)
|
||||
return ENOPROTOOPT;
|
||||
|
||||
switch (option) {
|
||||
// TODO: implement other options!
|
||||
case SO_LINGER:
|
||||
@@ -1068,20 +1069,14 @@ int
|
||||
socket_setsockopt(net_socket *socket, int level, int option, const void *value,
|
||||
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->setsockopt)
|
||||
return protocol->module->setsockopt(protocol, level, option,
|
||||
value, length);
|
||||
}
|
||||
|
||||
net_protocol *protocol = socket->first_protocol;
|
||||
while (protocol && protocol->module->setsockopt == NULL)
|
||||
protocol = protocol->next;
|
||||
|
||||
if (protocol)
|
||||
status = protocol->module->setsockopt(protocol, level, option,
|
||||
value, length);
|
||||
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
return socket_set_option(socket, option, value, length);
|
||||
return socket_set_option(socket, level, option, value, length);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user