support RFC 3678's Protocol-Independent setsockopt()s for IPv4 multicast.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20691 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -71,6 +71,7 @@ struct net_datalink_module_info {
|
|||||||
const struct sockaddr *address,
|
const struct sockaddr *address,
|
||||||
net_interface **_interface,
|
net_interface **_interface,
|
||||||
uint32 *_matchedType);
|
uint32 *_matchedType);
|
||||||
|
net_interface *(*get_interface)(struct net_domain *domain, uint32 index);
|
||||||
net_interface *(*get_interface_with_address)(struct net_domain *domain,
|
net_interface *(*get_interface_with_address)(struct net_domain *domain,
|
||||||
const struct sockaddr *address);
|
const struct sockaddr *address);
|
||||||
|
|
||||||
|
|||||||
@@ -123,6 +123,9 @@ class RawSocket : public DoublyLinkedListLinkImpl<RawSocket>, public DatagramSoc
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct ipv4_protocol : net_protocol {
|
struct ipv4_protocol : net_protocol {
|
||||||
|
ipv4_protocol(net_socket *socket)
|
||||||
|
: multicast_filter(socket) {}
|
||||||
|
|
||||||
RawSocket *raw;
|
RawSocket *raw;
|
||||||
uint8 service_type;
|
uint8 service_type;
|
||||||
uint8 time_to_live;
|
uint8 time_to_live;
|
||||||
@@ -623,7 +626,7 @@ receiving_protocol(uint8 protocol)
|
|||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
ipv4_delta_group(MulticastFilter<in_addr>::GroupState *group, int option,
|
ipv4_delta_group(MulticastFilter<in_addr>::GroupState *group, int option,
|
||||||
net_interface *interface, in_addr *sourceAddr)
|
net_interface *interface, const in_addr *sourceAddr)
|
||||||
{
|
{
|
||||||
switch (option) {
|
switch (option) {
|
||||||
case IP_ADD_MEMBERSHIP:
|
case IP_ADD_MEMBERSHIP:
|
||||||
@@ -646,27 +649,9 @@ ipv4_delta_group(MulticastFilter<in_addr>::GroupState *group, int option,
|
|||||||
|
|
||||||
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)
|
net_interface *interface, const in_addr *groupAddr,
|
||||||
|
const in_addr *sourceAddr)
|
||||||
{
|
{
|
||||||
net_interface *interface = NULL;
|
|
||||||
|
|
||||||
if (interfaceAddr->s_addr == INADDR_ANY) {
|
|
||||||
interface = sDatalinkModule->get_interface_with_address(sDomain, NULL);
|
|
||||||
} else {
|
|
||||||
sockaddr_in address;
|
|
||||||
|
|
||||||
memset(&address, 0, sizeof(address));
|
|
||||||
address.sin_family = AF_INET;
|
|
||||||
address.sin_len = sizeof(address);
|
|
||||||
address.sin_addr = *interfaceAddr;
|
|
||||||
|
|
||||||
interface = sDatalinkModule->get_interface_with_address(sDomain,
|
|
||||||
(sockaddr *)&address);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (interface == NULL)
|
|
||||||
return ENODEV;
|
|
||||||
|
|
||||||
MulticastFilter<in_addr> &filter = protocol->multicast_filter;
|
MulticastFilter<in_addr> &filter = protocol->multicast_filter;
|
||||||
MulticastFilter<in_addr>::GroupState *group = NULL;
|
MulticastFilter<in_addr>::GroupState *group = NULL;
|
||||||
|
|
||||||
@@ -701,13 +686,68 @@ ipv4_delta_membership(ipv4_protocol *protocol, int option,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
ipv4_delta_membership(ipv4_protocol *protocol, int option,
|
||||||
|
in_addr *interfaceAddr, in_addr *groupAddr, in_addr *sourceAddr)
|
||||||
|
{
|
||||||
|
net_interface *interface = NULL;
|
||||||
|
|
||||||
|
if (interfaceAddr->s_addr == INADDR_ANY) {
|
||||||
|
interface = sDatalinkModule->get_interface_with_address(sDomain, NULL);
|
||||||
|
} else {
|
||||||
|
sockaddr_in address;
|
||||||
|
|
||||||
|
memset(&address, 0, sizeof(address));
|
||||||
|
address.sin_family = AF_INET;
|
||||||
|
address.sin_len = sizeof(address);
|
||||||
|
address.sin_addr = *interfaceAddr;
|
||||||
|
|
||||||
|
interface = sDatalinkModule->get_interface_with_address(sDomain,
|
||||||
|
(sockaddr *)&address);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (interface == NULL)
|
||||||
|
return ENODEV;
|
||||||
|
|
||||||
|
return ipv4_delta_membership(protocol, option, interface, groupAddr,
|
||||||
|
sourceAddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
ipv4_generic_delta_membership(ipv4_protocol *protocol, int option,
|
||||||
|
uint32 index, const sockaddr_storage *_groupAddr,
|
||||||
|
const sockaddr_storage *_sourceAddr)
|
||||||
|
{
|
||||||
|
if (_groupAddr->ss_family != AF_INET)
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
|
if (_sourceAddr && _sourceAddr->ss_family != AF_INET)
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
|
net_interface *interface = sDatalinkModule->get_interface(sDomain, index);
|
||||||
|
if (interface == NULL)
|
||||||
|
return ENODEV;
|
||||||
|
|
||||||
|
const in_addr *groupAddr, *sourceAddr = NULL;
|
||||||
|
|
||||||
|
groupAddr = &((const sockaddr_in *)_groupAddr)->sin_addr;
|
||||||
|
|
||||||
|
if (_sourceAddr)
|
||||||
|
sourceAddr = &((const sockaddr_in *)_sourceAddr)->sin_addr;
|
||||||
|
|
||||||
|
return ipv4_delta_membership(protocol, option, interface, groupAddr,
|
||||||
|
sourceAddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
net_protocol *
|
net_protocol *
|
||||||
ipv4_init_protocol(net_socket *socket)
|
ipv4_init_protocol(net_socket *socket)
|
||||||
{
|
{
|
||||||
ipv4_protocol *protocol = new (std::nothrow) ipv4_protocol;
|
ipv4_protocol *protocol = new (std::nothrow) ipv4_protocol(socket);
|
||||||
if (protocol == NULL)
|
if (protocol == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@@ -845,6 +885,12 @@ ipv4_control(net_protocol *_protocol, int level, int option, void *value,
|
|||||||
case IP_UNBLOCK_SOURCE:
|
case IP_UNBLOCK_SOURCE:
|
||||||
case IP_ADD_SOURCE_MEMBERSHIP:
|
case IP_ADD_SOURCE_MEMBERSHIP:
|
||||||
case IP_DROP_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:
|
// 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().''
|
||||||
@@ -926,6 +972,34 @@ ipv4_control(net_protocol *_protocol, int level, int option, void *value,
|
|||||||
&mreq.imr_multiaddr, &mreq.imr_sourceaddr);
|
&mreq.imr_multiaddr, &mreq.imr_sourceaddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case MCAST_JOIN_GROUP:
|
||||||
|
case MCAST_LEAVE_GROUP:
|
||||||
|
{
|
||||||
|
group_req greq;
|
||||||
|
if (*_length != sizeof(group_req))
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
if (user_memcpy(&greq, value, sizeof(group_req)) < B_OK)
|
||||||
|
return B_BAD_ADDRESS;
|
||||||
|
|
||||||
|
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:
|
||||||
|
{
|
||||||
|
group_source_req greq;
|
||||||
|
if (*_length != sizeof(group_source_req))
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
if (user_memcpy(&greq, value, sizeof(group_source_req)) < B_OK)
|
||||||
|
return B_BAD_ADDRESS;
|
||||||
|
|
||||||
|
return ipv4_generic_delta_membership(protocol, option,
|
||||||
|
greq.gsr_interface, &greq.gsr_group, &greq.gsr_source);
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
dprintf("IPv4::control(): set unknown option: %d\n", option);
|
dprintf("IPv4::control(): set unknown option: %d\n", option);
|
||||||
return ENOPROTOOPT;
|
return ENOPROTOOPT;
|
||||||
|
|||||||
@@ -95,8 +95,9 @@ MulticastGroupInterfaceState<AddressType>::_Remove(Source *state)
|
|||||||
|
|
||||||
|
|
||||||
template<typename AddressType>
|
template<typename AddressType>
|
||||||
MulticastGroupState<AddressType>::MulticastGroupState(const AddressType &address)
|
MulticastGroupState<AddressType>::MulticastGroupState(
|
||||||
: fMulticastAddress(address), fFilterMode(kInclude)
|
MulticastFilter<AddressType> *parent, const AddressType &address)
|
||||||
|
: fParent(parent), fMulticastAddress(address), fFilterMode(kInclude)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -227,6 +228,13 @@ MulticastGroupState<AddressType>::_RemoveInterface(InterfaceState *state)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename AddressType>
|
||||||
|
MulticastFilter<AddressType>::MulticastFilter(net_socket *socket)
|
||||||
|
: fParent(socket)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
template<typename AddressType>
|
template<typename AddressType>
|
||||||
MulticastFilter<AddressType>::~MulticastFilter()
|
MulticastFilter<AddressType>::~MulticastFilter()
|
||||||
{
|
{
|
||||||
@@ -254,7 +262,7 @@ MulticastFilter<AddressType>::GetGroup(const AddressType &groupAddress,
|
|||||||
if (!create)
|
if (!create)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
GroupState *state = new (nothrow) GroupState(groupAddress);
|
GroupState *state = new (nothrow) GroupState(this, groupAddress);
|
||||||
if (state)
|
if (state)
|
||||||
fStates.Add(state);
|
fStates.Add(state);
|
||||||
return state;
|
return state;
|
||||||
|
|||||||
@@ -13,6 +13,9 @@
|
|||||||
#include <util/list.h>
|
#include <util/list.h>
|
||||||
|
|
||||||
struct net_interface;
|
struct net_interface;
|
||||||
|
struct net_socket;
|
||||||
|
|
||||||
|
template<typename AddressType> class MulticastFilter;
|
||||||
|
|
||||||
template<typename AddressType>
|
template<typename AddressType>
|
||||||
struct MulticastSource {
|
struct MulticastSource {
|
||||||
@@ -48,7 +51,8 @@ private:
|
|||||||
template<typename AddressType>
|
template<typename AddressType>
|
||||||
class MulticastGroupState {
|
class MulticastGroupState {
|
||||||
public:
|
public:
|
||||||
MulticastGroupState(const AddressType &address);
|
MulticastGroupState(MulticastFilter<AddressType> *parent,
|
||||||
|
const AddressType &address);
|
||||||
~MulticastGroupState();
|
~MulticastGroupState();
|
||||||
|
|
||||||
const AddressType &Address() const { return fMulticastAddress; }
|
const AddressType &Address() const { return fMulticastAddress; }
|
||||||
@@ -80,6 +84,7 @@ private:
|
|||||||
kExclude
|
kExclude
|
||||||
};
|
};
|
||||||
|
|
||||||
|
MulticastFilter<AddressType> *fParent;
|
||||||
AddressType fMulticastAddress;
|
AddressType fMulticastAddress;
|
||||||
FilterMode fFilterMode;
|
FilterMode fFilterMode;
|
||||||
InterfaceList fInterfaces;
|
InterfaceList fInterfaces;
|
||||||
@@ -90,8 +95,11 @@ class MulticastFilter {
|
|||||||
public:
|
public:
|
||||||
typedef MulticastGroupState<AddressType> GroupState;
|
typedef MulticastGroupState<AddressType> GroupState;
|
||||||
|
|
||||||
|
MulticastFilter(net_socket *parent);
|
||||||
~MulticastFilter();
|
~MulticastFilter();
|
||||||
|
|
||||||
|
net_socket *Parent() const { return fParent; }
|
||||||
|
|
||||||
GroupState *GetGroup(const AddressType &groupAddress, bool create);
|
GroupState *GetGroup(const AddressType &groupAddress, bool create);
|
||||||
void ReturnGroup(GroupState *group);
|
void ReturnGroup(GroupState *group);
|
||||||
|
|
||||||
@@ -99,6 +107,8 @@ private:
|
|||||||
typedef DoublyLinkedListCLink<GroupState> GroupStateLink;
|
typedef DoublyLinkedListCLink<GroupState> GroupStateLink;
|
||||||
typedef DoublyLinkedList<GroupState, GroupStateLink> States;
|
typedef DoublyLinkedList<GroupState, GroupStateLink> States;
|
||||||
|
|
||||||
|
net_socket *fParent;
|
||||||
|
|
||||||
// TODO change this into an hash table or tree
|
// TODO change this into an hash table or tree
|
||||||
States fStates;
|
States fStates;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -449,6 +449,16 @@ datalink_get_interface_with_address(net_domain *_domain,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
net_interface *
|
||||||
|
datalink_get_interface(net_domain *domain, uint32 index)
|
||||||
|
{
|
||||||
|
if (index == 0)
|
||||||
|
return datalink_get_interface_with_address(domain, NULL);
|
||||||
|
|
||||||
|
return find_interface(domain, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
datalink_std_ops(int32 op, ...)
|
datalink_std_ops(int32 op, ...)
|
||||||
{
|
{
|
||||||
@@ -775,6 +785,7 @@ net_datalink_module_info gNetDatalinkModule = {
|
|||||||
datalink_control,
|
datalink_control,
|
||||||
datalink_send_data,
|
datalink_send_data,
|
||||||
datalink_is_local_address,
|
datalink_is_local_address,
|
||||||
|
datalink_get_interface,
|
||||||
datalink_get_interface_with_address,
|
datalink_get_interface_with_address,
|
||||||
|
|
||||||
add_route,
|
add_route,
|
||||||
|
|||||||
Reference in New Issue
Block a user