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:
parent
46527f6806
commit
6c501a4085
@ -71,6 +71,7 @@ struct net_datalink_module_info {
|
||||
const struct sockaddr *address,
|
||||
net_interface **_interface,
|
||||
uint32 *_matchedType);
|
||||
net_interface *(*get_interface)(struct net_domain *domain, uint32 index);
|
||||
net_interface *(*get_interface_with_address)(struct net_domain *domain,
|
||||
const struct sockaddr *address);
|
||||
|
||||
|
@ -123,6 +123,9 @@ class RawSocket : public DoublyLinkedListLinkImpl<RawSocket>, public DatagramSoc
|
||||
};
|
||||
|
||||
struct ipv4_protocol : net_protocol {
|
||||
ipv4_protocol(net_socket *socket)
|
||||
: multicast_filter(socket) {}
|
||||
|
||||
RawSocket *raw;
|
||||
uint8 service_type;
|
||||
uint8 time_to_live;
|
||||
@ -623,7 +626,7 @@ receiving_protocol(uint8 protocol)
|
||||
|
||||
static status_t
|
||||
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) {
|
||||
case IP_ADD_MEMBERSHIP:
|
||||
@ -646,27 +649,9 @@ ipv4_delta_group(MulticastFilter<in_addr>::GroupState *group, 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, 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>::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 -
|
||||
|
||||
|
||||
net_protocol *
|
||||
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)
|
||||
return NULL;
|
||||
|
||||
@ -845,6 +885,12 @@ ipv4_control(net_protocol *_protocol, int level, int option, void *value,
|
||||
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().''
|
||||
@ -926,6 +972,34 @@ ipv4_control(net_protocol *_protocol, int level, int option, void *value,
|
||||
&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:
|
||||
dprintf("IPv4::control(): set unknown option: %d\n", option);
|
||||
return ENOPROTOOPT;
|
||||
|
@ -95,8 +95,9 @@ MulticastGroupInterfaceState<AddressType>::_Remove(Source *state)
|
||||
|
||||
|
||||
template<typename AddressType>
|
||||
MulticastGroupState<AddressType>::MulticastGroupState(const AddressType &address)
|
||||
: fMulticastAddress(address), fFilterMode(kInclude)
|
||||
MulticastGroupState<AddressType>::MulticastGroupState(
|
||||
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>
|
||||
MulticastFilter<AddressType>::~MulticastFilter()
|
||||
{
|
||||
@ -254,7 +262,7 @@ MulticastFilter<AddressType>::GetGroup(const AddressType &groupAddress,
|
||||
if (!create)
|
||||
return NULL;
|
||||
|
||||
GroupState *state = new (nothrow) GroupState(groupAddress);
|
||||
GroupState *state = new (nothrow) GroupState(this, groupAddress);
|
||||
if (state)
|
||||
fStates.Add(state);
|
||||
return state;
|
||||
|
@ -13,6 +13,9 @@
|
||||
#include <util/list.h>
|
||||
|
||||
struct net_interface;
|
||||
struct net_socket;
|
||||
|
||||
template<typename AddressType> class MulticastFilter;
|
||||
|
||||
template<typename AddressType>
|
||||
struct MulticastSource {
|
||||
@ -48,7 +51,8 @@ private:
|
||||
template<typename AddressType>
|
||||
class MulticastGroupState {
|
||||
public:
|
||||
MulticastGroupState(const AddressType &address);
|
||||
MulticastGroupState(MulticastFilter<AddressType> *parent,
|
||||
const AddressType &address);
|
||||
~MulticastGroupState();
|
||||
|
||||
const AddressType &Address() const { return fMulticastAddress; }
|
||||
@ -80,6 +84,7 @@ private:
|
||||
kExclude
|
||||
};
|
||||
|
||||
MulticastFilter<AddressType> *fParent;
|
||||
AddressType fMulticastAddress;
|
||||
FilterMode fFilterMode;
|
||||
InterfaceList fInterfaces;
|
||||
@ -90,8 +95,11 @@ class MulticastFilter {
|
||||
public:
|
||||
typedef MulticastGroupState<AddressType> GroupState;
|
||||
|
||||
MulticastFilter(net_socket *parent);
|
||||
~MulticastFilter();
|
||||
|
||||
net_socket *Parent() const { return fParent; }
|
||||
|
||||
GroupState *GetGroup(const AddressType &groupAddress, bool create);
|
||||
void ReturnGroup(GroupState *group);
|
||||
|
||||
@ -99,6 +107,8 @@ private:
|
||||
typedef DoublyLinkedListCLink<GroupState> GroupStateLink;
|
||||
typedef DoublyLinkedList<GroupState, GroupStateLink> States;
|
||||
|
||||
net_socket *fParent;
|
||||
|
||||
// TODO change this into an hash table or tree
|
||||
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
|
||||
datalink_std_ops(int32 op, ...)
|
||||
{
|
||||
@ -775,6 +785,7 @@ net_datalink_module_info gNetDatalinkModule = {
|
||||
datalink_control,
|
||||
datalink_send_data,
|
||||
datalink_is_local_address,
|
||||
datalink_get_interface,
|
||||
datalink_get_interface_with_address,
|
||||
|
||||
add_route,
|
||||
|
Loading…
Reference in New Issue
Block a user