glued the multicast filter handling to the receive path: we are now capable of receiving multicast frames in datagram sockets.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20695 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -55,8 +55,9 @@ struct net_protocol_module_info {
|
|||||||
size_t (*get_mtu)(net_protocol *self, const struct sockaddr *address);
|
size_t (*get_mtu)(net_protocol *self, const struct sockaddr *address);
|
||||||
|
|
||||||
status_t (*receive_data)(net_buffer *data);
|
status_t (*receive_data)(net_buffer *data);
|
||||||
status_t (*error)(uint32 code, net_buffer *data);
|
status_t (*deliver_data)(net_protocol *protocol, net_buffer *data);
|
||||||
|
|
||||||
|
status_t (*error)(uint32 code, net_buffer *data);
|
||||||
status_t (*error_reply)(net_protocol *self, net_buffer *causedError,
|
status_t (*error_reply)(net_protocol *self, net_buffer *causedError,
|
||||||
uint32 code, void *errorData);
|
uint32 code, void *errorData);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -342,6 +342,7 @@ net_protocol_module_info sICMPModule = {
|
|||||||
icmp_get_domain,
|
icmp_get_domain,
|
||||||
icmp_get_mtu,
|
icmp_get_mtu,
|
||||||
icmp_receive_data,
|
icmp_receive_data,
|
||||||
|
NULL,
|
||||||
icmp_error,
|
icmp_error,
|
||||||
icmp_error_reply,
|
icmp_error_reply,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -117,9 +117,15 @@ class FragmentPacket {
|
|||||||
|
|
||||||
class MulticastGroup {
|
class MulticastGroup {
|
||||||
public:
|
public:
|
||||||
|
typedef MulticastGroupLink<IPv4Multicast> Link;
|
||||||
|
|
||||||
MulticastGroup(const in_addr &address);
|
MulticastGroup(const in_addr &address);
|
||||||
|
|
||||||
status_t Deliver(net_buffer *buffer);
|
status_t Deliver(net_protocol_module_info *module, net_buffer *buffer);
|
||||||
|
|
||||||
|
void Add(Link *link);
|
||||||
|
void Remove(Link *link);
|
||||||
|
bool IsEmpty() const { return fLinks.IsEmpty(); }
|
||||||
|
|
||||||
static uint32 Hash(void *address, const void *key, uint32 range);
|
static uint32 Hash(void *address, const void *key, uint32 range);
|
||||||
static int Compare(void *address, const void *key);
|
static int Compare(void *address, const void *key);
|
||||||
@@ -128,8 +134,12 @@ public:
|
|||||||
static const int kMaxGroups = 64;
|
static const int kMaxGroups = 64;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
typedef DoublyLinkedListCLink<Link> LinkLink;
|
||||||
|
typedef DoublyLinkedList<Link, LinkLink> Links;
|
||||||
|
|
||||||
MulticastGroup *fNext;
|
MulticastGroup *fNext;
|
||||||
in_addr fMulticastAddress;
|
in_addr fMulticastAddress;
|
||||||
|
Links fLinks;
|
||||||
};
|
};
|
||||||
|
|
||||||
class RawSocket : public DoublyLinkedListLinkImpl<RawSocket>, public DatagramSocket<> {
|
class RawSocket : public DoublyLinkedListLinkImpl<RawSocket>, public DatagramSocket<> {
|
||||||
@@ -139,9 +149,11 @@ class RawSocket : public DoublyLinkedListLinkImpl<RawSocket>, public DatagramSoc
|
|||||||
|
|
||||||
typedef DoublyLinkedList<RawSocket> RawSocketList;
|
typedef DoublyLinkedList<RawSocket> RawSocketList;
|
||||||
|
|
||||||
|
typedef MulticastFilter<IPv4Multicast> IPv4MulticastFilter;
|
||||||
|
|
||||||
struct ipv4_protocol : net_protocol {
|
struct ipv4_protocol : net_protocol {
|
||||||
ipv4_protocol(net_socket *socket)
|
ipv4_protocol()
|
||||||
: multicast_filter(socket) {}
|
: multicast_filter(this) {}
|
||||||
|
|
||||||
RawSocket *raw;
|
RawSocket *raw;
|
||||||
uint8 service_type;
|
uint8 service_type;
|
||||||
@@ -149,7 +161,7 @@ struct ipv4_protocol : net_protocol {
|
|||||||
uint8 multicast_time_to_live;
|
uint8 multicast_time_to_live;
|
||||||
uint32 flags;
|
uint32 flags;
|
||||||
|
|
||||||
MulticastFilter<in_addr> multicast_filter;
|
IPv4MulticastFilter multicast_filter;
|
||||||
};
|
};
|
||||||
|
|
||||||
// protocol flags
|
// protocol flags
|
||||||
@@ -424,9 +436,35 @@ MulticastGroup::MulticastGroup(const in_addr &address)
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
MulticastGroup::Deliver(net_buffer *buffer)
|
MulticastGroup::Deliver(net_protocol_module_info *module, net_buffer *buffer)
|
||||||
{
|
{
|
||||||
return B_ERROR;
|
if (module->deliver_data == NULL)
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
Links::Iterator iterator = fLinks.GetIterator();
|
||||||
|
|
||||||
|
while (iterator.HasNext()) {
|
||||||
|
Link *link = iterator.Next();
|
||||||
|
|
||||||
|
if (link->group->FilterAccepts(buffer))
|
||||||
|
module->deliver_data(link->group->Socket(), buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
MulticastGroup::Add(Link *link)
|
||||||
|
{
|
||||||
|
fLinks.Add(link);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
MulticastGroup::Remove(Link *link)
|
||||||
|
{
|
||||||
|
fLinks.Remove(link);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -669,7 +707,7 @@ raw_receive_data(net_buffer *buffer)
|
|||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
deliver_multicast(net_buffer *buffer)
|
deliver_multicast(net_protocol_module_info *module, net_buffer *buffer)
|
||||||
{
|
{
|
||||||
BenaphoreLocker _(sMulticastGroupsLock);
|
BenaphoreLocker _(sMulticastGroupsLock);
|
||||||
|
|
||||||
@@ -678,9 +716,54 @@ deliver_multicast(net_buffer *buffer)
|
|||||||
if (group == NULL)
|
if (group == NULL)
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
||||||
// RAW sockets will be registered just like any other
|
// TODO fix sending multicast to RAW sockets, right now
|
||||||
|
// they are receiving the frames without the IP header
|
||||||
|
|
||||||
return group->Deliver(buffer);
|
return group->Deliver(module, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
IPv4Multicast::JoinGroup(const in_addr &groupAddr, MulticastGroup::Link *link)
|
||||||
|
{
|
||||||
|
BenaphoreLocker _(sMulticastGroupsLock);
|
||||||
|
|
||||||
|
MulticastGroup *group = (MulticastGroup *)hash_lookup(sMulticastGroups,
|
||||||
|
&groupAddr);
|
||||||
|
if (group == NULL) {
|
||||||
|
group = new (std::nothrow) MulticastGroup(groupAddr);
|
||||||
|
if (group == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
status_t status = hash_insert(sMulticastGroups, group);
|
||||||
|
if (status < B_OK) {
|
||||||
|
delete group;
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
group->Add(link);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
IPv4Multicast::LeaveGroup(const in_addr &groupAddr, MulticastGroup::Link *link)
|
||||||
|
{
|
||||||
|
BenaphoreLocker _(sMulticastGroupsLock);
|
||||||
|
|
||||||
|
MulticastGroup *group = (MulticastGroup *)hash_lookup(sMulticastGroups,
|
||||||
|
&groupAddr);
|
||||||
|
if (group == NULL)
|
||||||
|
return ENOENT;
|
||||||
|
|
||||||
|
group->Remove(link);
|
||||||
|
if (group->IsEmpty()) {
|
||||||
|
hash_remove(sMulticastGroups, group);
|
||||||
|
delete group;
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -715,7 +798,7 @@ fill_sockaddr_in(sockaddr_in *target, in_addr_t address)
|
|||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
ipv4_delta_group(MulticastFilter<in_addr>::GroupState *group, int option,
|
ipv4_delta_group(IPv4MulticastFilter::GroupState *group, int option,
|
||||||
net_interface *interface, const in_addr *sourceAddr)
|
net_interface *interface, const in_addr *sourceAddr)
|
||||||
{
|
{
|
||||||
switch (option) {
|
switch (option) {
|
||||||
@@ -742,8 +825,8 @@ ipv4_delta_membership(ipv4_protocol *protocol, int option,
|
|||||||
net_interface *interface, const in_addr *groupAddr,
|
net_interface *interface, const in_addr *groupAddr,
|
||||||
const in_addr *sourceAddr)
|
const in_addr *sourceAddr)
|
||||||
{
|
{
|
||||||
MulticastFilter<in_addr> &filter = protocol->multicast_filter;
|
IPv4MulticastFilter &filter = protocol->multicast_filter;
|
||||||
MulticastFilter<in_addr>::GroupState *group = NULL;
|
IPv4MulticastFilter::GroupState *group = NULL;
|
||||||
|
|
||||||
switch (option) {
|
switch (option) {
|
||||||
case IP_ADD_MEMBERSHIP:
|
case IP_ADD_MEMBERSHIP:
|
||||||
@@ -833,7 +916,7 @@ ipv4_generic_delta_membership(ipv4_protocol *protocol, int option,
|
|||||||
net_protocol *
|
net_protocol *
|
||||||
ipv4_init_protocol(net_socket *socket)
|
ipv4_init_protocol(net_socket *socket)
|
||||||
{
|
{
|
||||||
ipv4_protocol *protocol = new (std::nothrow) ipv4_protocol(socket);
|
ipv4_protocol *protocol = new (std::nothrow) ipv4_protocol();
|
||||||
if (protocol == NULL)
|
if (protocol == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@@ -1412,19 +1495,12 @@ ipv4_receive_data(net_buffer *buffer)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buffer->flags & MSG_MCAST) {
|
|
||||||
// Unfortunely historical reasons dictate that the IP multicast
|
|
||||||
// model be a little different from the unicast one. We deliver
|
|
||||||
// this frame directly to all sockets registered with interest
|
|
||||||
// for this multicast group.
|
|
||||||
return deliver_multicast(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Since the buffer might have been changed (reassembled fragment)
|
// Since the buffer might have been changed (reassembled fragment)
|
||||||
// we must no longer access bufferHeader or header anymore after
|
// we must no longer access bufferHeader or header anymore after
|
||||||
// this point
|
// this point
|
||||||
|
|
||||||
raw_receive_data(buffer);
|
if (!(buffer->flags & MSG_MCAST))
|
||||||
|
raw_receive_data(buffer);
|
||||||
|
|
||||||
gBufferModule->remove_header(buffer, headerLength);
|
gBufferModule->remove_header(buffer, headerLength);
|
||||||
// the header is of variable size and may include IP options
|
// the header is of variable size and may include IP options
|
||||||
@@ -1436,10 +1512,30 @@ ipv4_receive_data(net_buffer *buffer)
|
|||||||
return EAFNOSUPPORT;
|
return EAFNOSUPPORT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (buffer->flags & MSG_MCAST) {
|
||||||
|
// Unfortunely historical reasons dictate that the IP multicast
|
||||||
|
// model be a little different from the unicast one. We deliver
|
||||||
|
// this frame directly to all sockets registered with interest
|
||||||
|
// for this multicast group.
|
||||||
|
return deliver_multicast(module, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
return module->receive_data(buffer);
|
return module->receive_data(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
ipv4_deliver_data(net_protocol *_protocol, net_buffer *buffer)
|
||||||
|
{
|
||||||
|
ipv4_protocol *protocol = (ipv4_protocol *)_protocol;
|
||||||
|
|
||||||
|
if (protocol->raw == NULL)
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
|
return protocol->raw->SocketEnqueue(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
ipv4_error(uint32 code, net_buffer *data)
|
ipv4_error(uint32 code, net_buffer *data)
|
||||||
{
|
{
|
||||||
@@ -1591,6 +1687,7 @@ net_protocol_module_info gIPv4Module = {
|
|||||||
ipv4_get_domain,
|
ipv4_get_domain,
|
||||||
ipv4_get_mtu,
|
ipv4_get_mtu,
|
||||||
ipv4_receive_data,
|
ipv4_receive_data,
|
||||||
|
ipv4_deliver_data,
|
||||||
ipv4_error,
|
ipv4_error,
|
||||||
ipv4_error_reply,
|
ipv4_error_reply,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,12 +8,14 @@
|
|||||||
|
|
||||||
#include "multicast.h"
|
#include "multicast.h"
|
||||||
|
|
||||||
|
#include <net_buffer.h>
|
||||||
|
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
|
|
||||||
#include <new>
|
#include <new>
|
||||||
|
|
||||||
template class MulticastFilter<in_addr>;
|
template class MulticastFilter<IPv4Multicast>;
|
||||||
template class MulticastGroupState<in_addr>;
|
template class MulticastGroupState<IPv4Multicast>;
|
||||||
template class MulticastGroupInterfaceState<in_addr>;
|
template class MulticastGroupInterfaceState<in_addr>;
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
@@ -94,25 +96,23 @@ MulticastGroupInterfaceState<AddressType>::_Remove(Source *state)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<typename AddressType>
|
template<typename Addressing>
|
||||||
MulticastGroupState<AddressType>::MulticastGroupState(
|
MulticastGroupState<Addressing>::MulticastGroupState(net_protocol *socket,
|
||||||
MulticastFilter<AddressType> *parent, const AddressType &address)
|
const AddressType &address)
|
||||||
: fParent(parent), fMulticastAddress(address), fFilterMode(kInclude)
|
: fSocket(socket), fMulticastAddress(address), fFilterMode(kInclude)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<typename AddressType>
|
template<typename Addressing>
|
||||||
MulticastGroupState<AddressType>::~MulticastGroupState()
|
MulticastGroupState<Addressing>::~MulticastGroupState()
|
||||||
{
|
{
|
||||||
InterfaceList::Iterator iterator = fInterfaces.GetIterator();
|
Clear();
|
||||||
while (iterator.HasNext())
|
|
||||||
_RemoveInterface(iterator.Next());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<typename AddressType> status_t
|
template<typename Addressing> status_t
|
||||||
MulticastGroupState<AddressType>::Add(net_interface *interface)
|
MulticastGroupState<Addressing>::Add(net_interface *interface)
|
||||||
{
|
{
|
||||||
if (fFilterMode == kInclude && !fInterfaces.IsEmpty())
|
if (fFilterMode == kInclude && !fInterfaces.IsEmpty())
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
@@ -123,8 +123,8 @@ MulticastGroupState<AddressType>::Add(net_interface *interface)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<typename AddressType> status_t
|
template<typename Addressing> status_t
|
||||||
MulticastGroupState<AddressType>::Drop(net_interface *interface)
|
MulticastGroupState<Addressing>::Drop(net_interface *interface)
|
||||||
{
|
{
|
||||||
InterfaceState *state = _GetInterface(interface, false);
|
InterfaceState *state = _GetInterface(interface, false);
|
||||||
if (state == NULL)
|
if (state == NULL)
|
||||||
@@ -139,8 +139,8 @@ MulticastGroupState<AddressType>::Drop(net_interface *interface)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<typename AddressType> status_t
|
template<typename Addressing> status_t
|
||||||
MulticastGroupState<AddressType>::BlockSource(net_interface *interface,
|
MulticastGroupState<Addressing>::BlockSource(net_interface *interface,
|
||||||
const AddressType &sourceAddress)
|
const AddressType &sourceAddress)
|
||||||
{
|
{
|
||||||
if (fFilterMode != kExclude)
|
if (fFilterMode != kExclude)
|
||||||
@@ -154,8 +154,8 @@ MulticastGroupState<AddressType>::BlockSource(net_interface *interface,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<typename AddressType> status_t
|
template<typename Addressing> status_t
|
||||||
MulticastGroupState<AddressType>::UnblockSource(net_interface *interface,
|
MulticastGroupState<Addressing>::UnblockSource(net_interface *interface,
|
||||||
const AddressType &sourceAddress)
|
const AddressType &sourceAddress)
|
||||||
{
|
{
|
||||||
if (fFilterMode != kExclude)
|
if (fFilterMode != kExclude)
|
||||||
@@ -168,8 +168,8 @@ MulticastGroupState<AddressType>::UnblockSource(net_interface *interface,
|
|||||||
return state->Remove(sourceAddress);
|
return state->Remove(sourceAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename AddressType> status_t
|
template<typename Addressing> status_t
|
||||||
MulticastGroupState<AddressType>::AddSSM(net_interface *interface,
|
MulticastGroupState<Addressing>::AddSSM(net_interface *interface,
|
||||||
const AddressType &sourceAddress)
|
const AddressType &sourceAddress)
|
||||||
{
|
{
|
||||||
if (fFilterMode == kExclude)
|
if (fFilterMode == kExclude)
|
||||||
@@ -183,8 +183,8 @@ MulticastGroupState<AddressType>::AddSSM(net_interface *interface,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<typename AddressType> status_t
|
template<typename Addressing> status_t
|
||||||
MulticastGroupState<AddressType>::DropSSM(net_interface *interface,
|
MulticastGroupState<Addressing>::DropSSM(net_interface *interface,
|
||||||
const AddressType &sourceAddress)
|
const AddressType &sourceAddress)
|
||||||
{
|
{
|
||||||
if (fFilterMode == kExclude)
|
if (fFilterMode == kExclude)
|
||||||
@@ -198,8 +198,31 @@ MulticastGroupState<AddressType>::DropSSM(net_interface *interface,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<typename AddressType> MulticastGroupState<AddressType>::InterfaceState *
|
template<typename Addressing> void
|
||||||
MulticastGroupState<AddressType>::_GetInterface(net_interface *interface,
|
MulticastGroupState<Addressing>::Clear()
|
||||||
|
{
|
||||||
|
InterfaceList::Iterator iterator = fInterfaces.GetIterator();
|
||||||
|
while (iterator.HasNext())
|
||||||
|
_RemoveInterface(iterator.Next());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename Addressing> bool
|
||||||
|
MulticastGroupState<Addressing>::FilterAccepts(net_buffer *buffer)
|
||||||
|
{
|
||||||
|
InterfaceState *state = _GetInterface(buffer->interface, false);
|
||||||
|
if (state == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool has = state->Contains(*Addressing::AddressFromSockAddr(
|
||||||
|
(sockaddr *)&buffer->source));
|
||||||
|
|
||||||
|
return (has && fFilterMode == kInclude) || (!has && fFilterMode == kExclude);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename Addressing> MulticastGroupState<Addressing>::InterfaceState *
|
||||||
|
MulticastGroupState<Addressing>::_GetInterface(net_interface *interface,
|
||||||
bool create)
|
bool create)
|
||||||
{
|
{
|
||||||
InterfaceList::Iterator iterator = fInterfaces.GetIterator();
|
InterfaceList::Iterator iterator = fInterfaces.GetIterator();
|
||||||
@@ -220,35 +243,35 @@ MulticastGroupState<AddressType>::_GetInterface(net_interface *interface,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<typename AddressType> void
|
template<typename Addressing> void
|
||||||
MulticastGroupState<AddressType>::_RemoveInterface(InterfaceState *state)
|
MulticastGroupState<Addressing>::_RemoveInterface(InterfaceState *state)
|
||||||
{
|
{
|
||||||
fInterfaces.Remove(state);
|
fInterfaces.Remove(state);
|
||||||
delete state;
|
delete state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<typename AddressType>
|
template<typename Addressing>
|
||||||
MulticastFilter<AddressType>::MulticastFilter(net_socket *socket)
|
MulticastFilter<Addressing>::MulticastFilter(net_protocol *socket)
|
||||||
: fParent(socket)
|
: fParent(socket)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<typename AddressType>
|
template<typename Addressing>
|
||||||
MulticastFilter<AddressType>::~MulticastFilter()
|
MulticastFilter<Addressing>::~MulticastFilter()
|
||||||
{
|
{
|
||||||
States::Iterator iterator = fStates.GetIterator();
|
States::Iterator iterator = fStates.GetIterator();
|
||||||
while (iterator.HasNext()) {
|
while (iterator.HasNext()) {
|
||||||
GroupState *state = iterator.Next();
|
GroupState *state = iterator.Next();
|
||||||
fStates.Remove(state);
|
state->Clear();
|
||||||
delete state;
|
ReturnGroup(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<typename AddressType> MulticastFilter<AddressType>::GroupState *
|
template<typename Addressing> MulticastFilter<Addressing>::GroupState *
|
||||||
MulticastFilter<AddressType>::GetGroup(const AddressType &groupAddress,
|
MulticastFilter<Addressing>::GetGroup(const AddressType &groupAddress,
|
||||||
bool create)
|
bool create)
|
||||||
{
|
{
|
||||||
States::Iterator iterator = fStates.GetIterator();
|
States::Iterator iterator = fStates.GetIterator();
|
||||||
@@ -262,17 +285,26 @@ MulticastFilter<AddressType>::GetGroup(const AddressType &groupAddress,
|
|||||||
if (!create)
|
if (!create)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
GroupState *state = new (nothrow) GroupState(this, groupAddress);
|
GroupState *state = new (nothrow) GroupState(fParent, groupAddress);
|
||||||
if (state)
|
if (state) {
|
||||||
|
if (Addressing::JoinGroup(groupAddress, state->ProtocolLink()) < B_OK) {
|
||||||
|
delete state;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
fStates.Add(state);
|
fStates.Add(state);
|
||||||
|
}
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<typename AddressType> void
|
template<typename Addressing> void
|
||||||
MulticastFilter<AddressType>::ReturnGroup(GroupState *group)
|
MulticastFilter<Addressing>::ReturnGroup(GroupState *group)
|
||||||
{
|
{
|
||||||
if (group->IsEmpty()) {
|
if (group->IsEmpty()) {
|
||||||
|
Addressing::LeaveGroup(group->Address(), group->ProtocolLink());
|
||||||
|
|
||||||
fStates.Remove(group);
|
fStates.Remove(group);
|
||||||
delete group;
|
delete group;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,10 +12,30 @@
|
|||||||
#include <util/DoublyLinkedList.h>
|
#include <util/DoublyLinkedList.h>
|
||||||
#include <util/list.h>
|
#include <util/list.h>
|
||||||
|
|
||||||
struct net_interface;
|
#include <netinet/in.h>
|
||||||
struct net_socket;
|
|
||||||
|
|
||||||
template<typename AddressType> class MulticastFilter;
|
struct net_buffer;
|
||||||
|
struct net_interface;
|
||||||
|
struct net_protocol;
|
||||||
|
|
||||||
|
// This code is template'ized as it is reusable for IPv6
|
||||||
|
|
||||||
|
template<typename Addressing> class MulticastFilter;
|
||||||
|
template<typename Addressing> struct MulticastGroupLink;
|
||||||
|
template<typename Addressing> class MulticastGroupState;
|
||||||
|
|
||||||
|
// TODO move this elsewhere...
|
||||||
|
struct IPv4Multicast {
|
||||||
|
typedef struct in_addr AddressType;
|
||||||
|
|
||||||
|
static status_t JoinGroup(const in_addr &, MulticastGroupLink<IPv4Multicast> *);
|
||||||
|
static status_t LeaveGroup(const in_addr &, MulticastGroupLink<IPv4Multicast> *);
|
||||||
|
|
||||||
|
static in_addr *AddressFromSockAddr(sockaddr *sockaddr)
|
||||||
|
{
|
||||||
|
return &((sockaddr_in *)sockaddr)->sin_addr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template<typename AddressType>
|
template<typename AddressType>
|
||||||
struct MulticastSource {
|
struct MulticastSource {
|
||||||
@@ -34,6 +54,9 @@ public:
|
|||||||
status_t Add(const AddressType &address);
|
status_t Add(const AddressType &address);
|
||||||
status_t Remove(const AddressType &address);
|
status_t Remove(const AddressType &address);
|
||||||
|
|
||||||
|
bool Contains(const AddressType &address)
|
||||||
|
{ return _Get(address, false) != NULL; }
|
||||||
|
|
||||||
list_link link;
|
list_link link;
|
||||||
private:
|
private:
|
||||||
typedef MulticastSource<AddressType> Source;
|
typedef MulticastSource<AddressType> Source;
|
||||||
@@ -48,13 +71,22 @@ private:
|
|||||||
SourceList fSources;
|
SourceList fSources;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename AddressType>
|
template<typename Addressing>
|
||||||
|
struct MulticastGroupLink {
|
||||||
|
MulticastGroupState<Addressing> *group;
|
||||||
|
list_link link;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Addressing>
|
||||||
class MulticastGroupState {
|
class MulticastGroupState {
|
||||||
public:
|
public:
|
||||||
MulticastGroupState(MulticastFilter<AddressType> *parent,
|
typedef typename Addressing::AddressType AddressType;
|
||||||
const AddressType &address);
|
|
||||||
|
MulticastGroupState(net_protocol *parent, const AddressType &address);
|
||||||
~MulticastGroupState();
|
~MulticastGroupState();
|
||||||
|
|
||||||
|
net_protocol *Socket() const { return fSocket; }
|
||||||
|
|
||||||
const AddressType &Address() const { return fMulticastAddress; }
|
const AddressType &Address() const { return fMulticastAddress; }
|
||||||
bool IsEmpty() const
|
bool IsEmpty() const
|
||||||
{ return fFilterMode == kInclude && fInterfaces.IsEmpty(); }
|
{ return fFilterMode == kInclude && fInterfaces.IsEmpty(); }
|
||||||
@@ -70,6 +102,12 @@ public:
|
|||||||
status_t DropSSM(net_interface *interface,
|
status_t DropSSM(net_interface *interface,
|
||||||
const AddressType &sourceAddress);
|
const AddressType &sourceAddress);
|
||||||
|
|
||||||
|
void Clear();
|
||||||
|
|
||||||
|
bool FilterAccepts(net_buffer *buffer);
|
||||||
|
|
||||||
|
MulticastGroupLink<Addressing> *ProtocolLink() { return &fInternalLink; }
|
||||||
|
|
||||||
list_link link;
|
list_link link;
|
||||||
private:
|
private:
|
||||||
typedef MulticastGroupInterfaceState<AddressType> InterfaceState;
|
typedef MulticastGroupInterfaceState<AddressType> InterfaceState;
|
||||||
@@ -84,21 +122,23 @@ private:
|
|||||||
kExclude
|
kExclude
|
||||||
};
|
};
|
||||||
|
|
||||||
MulticastFilter<AddressType> *fParent;
|
net_protocol *fSocket;
|
||||||
AddressType fMulticastAddress;
|
AddressType fMulticastAddress;
|
||||||
FilterMode fFilterMode;
|
FilterMode fFilterMode;
|
||||||
InterfaceList fInterfaces;
|
InterfaceList fInterfaces;
|
||||||
|
MulticastGroupLink<Addressing> fInternalLink;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename AddressType>
|
template<typename Addressing>
|
||||||
class MulticastFilter {
|
class MulticastFilter {
|
||||||
public:
|
public:
|
||||||
typedef MulticastGroupState<AddressType> GroupState;
|
typedef typename Addressing::AddressType AddressType;
|
||||||
|
typedef MulticastGroupState<Addressing> GroupState;
|
||||||
|
|
||||||
MulticastFilter(net_socket *parent);
|
MulticastFilter(net_protocol *parent);
|
||||||
~MulticastFilter();
|
~MulticastFilter();
|
||||||
|
|
||||||
net_socket *Parent() const { return fParent; }
|
net_protocol *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);
|
||||||
@@ -107,7 +147,7 @@ private:
|
|||||||
typedef DoublyLinkedListCLink<GroupState> GroupStateLink;
|
typedef DoublyLinkedListCLink<GroupState> GroupStateLink;
|
||||||
typedef DoublyLinkedList<GroupState, GroupStateLink> States;
|
typedef DoublyLinkedList<GroupState, GroupStateLink> States;
|
||||||
|
|
||||||
net_socket *fParent;
|
net_protocol *fParent;
|
||||||
|
|
||||||
// TODO change this into an hash table or tree
|
// TODO change this into an hash table or tree
|
||||||
States fStates;
|
States fStates;
|
||||||
|
|||||||
@@ -718,6 +718,7 @@ net_protocol_module_info sTCPModule = {
|
|||||||
tcp_get_domain,
|
tcp_get_domain,
|
||||||
tcp_get_mtu,
|
tcp_get_mtu,
|
||||||
tcp_receive_data,
|
tcp_receive_data,
|
||||||
|
NULL,
|
||||||
tcp_error,
|
tcp_error,
|
||||||
tcp_error_reply,
|
tcp_error_reply,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -82,6 +82,7 @@ public:
|
|||||||
net_buffer **_buffer);
|
net_buffer **_buffer);
|
||||||
|
|
||||||
status_t StoreData(net_buffer *buffer);
|
status_t StoreData(net_buffer *buffer);
|
||||||
|
status_t DeliverData(net_buffer *buffer);
|
||||||
|
|
||||||
net_domain * Domain() const
|
net_domain * Domain() const
|
||||||
{
|
{
|
||||||
@@ -179,6 +180,7 @@ public:
|
|||||||
~UdpEndpointManager();
|
~UdpEndpointManager();
|
||||||
|
|
||||||
status_t ReceiveData(net_buffer *buffer);
|
status_t ReceiveData(net_buffer *buffer);
|
||||||
|
status_t Deframe(net_buffer *buffer);
|
||||||
|
|
||||||
UdpDomainSupport *OpenEndpoint(UdpEndpoint *endpoint);
|
UdpDomainSupport *OpenEndpoint(UdpEndpoint *endpoint);
|
||||||
status_t FreeEndpoint(UdpDomainSupport *domain);
|
status_t FreeEndpoint(UdpDomainSupport *domain);
|
||||||
@@ -544,8 +546,40 @@ UdpEndpointManager::InitCheck() const
|
|||||||
status_t
|
status_t
|
||||||
UdpEndpointManager::ReceiveData(net_buffer *buffer)
|
UdpEndpointManager::ReceiveData(net_buffer *buffer)
|
||||||
{
|
{
|
||||||
|
status_t status = Deframe(buffer);
|
||||||
|
if (status < B_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
TRACE_EPM("ReceiveData(%p [%ld bytes])", buffer, buffer->size);
|
TRACE_EPM("ReceiveData(%p [%ld bytes])", buffer, buffer->size);
|
||||||
|
|
||||||
|
net_domain *domain = buffer->interface->domain;
|
||||||
|
|
||||||
|
BenaphoreLocker _(fLock);
|
||||||
|
|
||||||
|
UdpDomainSupport *domainSupport = _GetDomain(domain, false);
|
||||||
|
if (domainSupport == NULL) {
|
||||||
|
// we don't instantiate domain supports in the
|
||||||
|
// RX path as we are only interested in delivering
|
||||||
|
// data to existing sockets.
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = domainSupport->DemuxIncomingBuffer(buffer);
|
||||||
|
if (status < B_OK) {
|
||||||
|
TRACE_EPM(" ReceiveData(): no endpoint.");
|
||||||
|
// TODO: send ICMP-error
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
UdpEndpointManager::Deframe(net_buffer *buffer)
|
||||||
|
{
|
||||||
|
TRACE_EPM("Deframe(%p [%ld bytes])", buffer, buffer->size);
|
||||||
|
|
||||||
NetBufferHeaderReader<udp_header> bufferHeader(buffer);
|
NetBufferHeaderReader<udp_header> bufferHeader(buffer);
|
||||||
if (bufferHeader.Status() < B_OK)
|
if (bufferHeader.Status() < B_OK)
|
||||||
return bufferHeader.Status();
|
return bufferHeader.Status();
|
||||||
@@ -556,7 +590,7 @@ UdpEndpointManager::ReceiveData(net_buffer *buffer)
|
|||||||
struct sockaddr *destination = (struct sockaddr *)&buffer->destination;
|
struct sockaddr *destination = (struct sockaddr *)&buffer->destination;
|
||||||
|
|
||||||
if (buffer->interface == NULL || buffer->interface->domain == NULL) {
|
if (buffer->interface == NULL || buffer->interface->domain == NULL) {
|
||||||
TRACE_EPM(" ReceiveData(): UDP packed dropped as there was no domain "
|
TRACE_EPM(" Deframe(): UDP packed dropped as there was no domain "
|
||||||
"specified (interface %p).", buffer->interface);
|
"specified (interface %p).", buffer->interface);
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
}
|
}
|
||||||
@@ -564,18 +598,16 @@ UdpEndpointManager::ReceiveData(net_buffer *buffer)
|
|||||||
net_domain *domain = buffer->interface->domain;
|
net_domain *domain = buffer->interface->domain;
|
||||||
net_address_module_info *addressModule = domain->address_module;
|
net_address_module_info *addressModule = domain->address_module;
|
||||||
|
|
||||||
BenaphoreLocker _(fLock);
|
|
||||||
|
|
||||||
addressModule->set_port(source, header.source_port);
|
addressModule->set_port(source, header.source_port);
|
||||||
addressModule->set_port(destination, header.destination_port);
|
addressModule->set_port(destination, header.destination_port);
|
||||||
|
|
||||||
TRACE_EPM(" ReceiveData(): data from %s to %s",
|
TRACE_EPM(" Deframe(): data from %s to %s",
|
||||||
AddressString(domain, source, true).Data(),
|
AddressString(domain, source, true).Data(),
|
||||||
AddressString(domain, destination, true).Data());
|
AddressString(domain, destination, true).Data());
|
||||||
|
|
||||||
uint16 udpLength = ntohs(header.udp_length);
|
uint16 udpLength = ntohs(header.udp_length);
|
||||||
if (udpLength > buffer->size) {
|
if (udpLength > buffer->size) {
|
||||||
TRACE_EPM(" ReceiveData(): buffer is too short, expected %hu.",
|
TRACE_EPM(" Deframe(): buffer is too short, expected %hu.",
|
||||||
udpLength);
|
udpLength);
|
||||||
return B_MISMATCHED_VALUES;
|
return B_MISMATCHED_VALUES;
|
||||||
}
|
}
|
||||||
@@ -596,7 +628,7 @@ UdpEndpointManager::ReceiveData(net_buffer *buffer)
|
|||||||
<< Checksum::BufferHelper(buffer, gBufferModule);
|
<< Checksum::BufferHelper(buffer, gBufferModule);
|
||||||
uint16 sum = udpChecksum;
|
uint16 sum = udpChecksum;
|
||||||
if (sum != 0) {
|
if (sum != 0) {
|
||||||
TRACE_EPM(" ReceiveData(): bad checksum 0x%hx.", sum);
|
TRACE_EPM(" Deframe(): bad checksum 0x%hx.", sum);
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -604,22 +636,7 @@ UdpEndpointManager::ReceiveData(net_buffer *buffer)
|
|||||||
bufferHeader.Remove();
|
bufferHeader.Remove();
|
||||||
// remove UDP-header from buffer before passing it on
|
// remove UDP-header from buffer before passing it on
|
||||||
|
|
||||||
UdpDomainSupport *domainSupport = _GetDomain(domain, false);
|
return B_OK;
|
||||||
if (domainSupport == NULL) {
|
|
||||||
// we don't instantiate domain supports in the
|
|
||||||
// RX path as we are only interested in delivering
|
|
||||||
// data to existing sockets.
|
|
||||||
return B_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
status_t status = domainSupport->DemuxIncomingBuffer(buffer);
|
|
||||||
if (status < B_OK) {
|
|
||||||
TRACE_EPM(" ReceiveData(): no endpoint.");
|
|
||||||
// TODO: send ICMP-error
|
|
||||||
return B_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
return B_ERROR;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -937,6 +954,25 @@ UdpEndpoint::StoreData(net_buffer *buffer)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
UdpEndpoint::DeliverData(net_buffer *_buffer)
|
||||||
|
{
|
||||||
|
net_buffer *buffer = gBufferModule->clone(_buffer, false);
|
||||||
|
if (buffer == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
status_t status = sUdpEndpointManager->Deframe(buffer);
|
||||||
|
if (status < B_OK) {
|
||||||
|
gBufferModule->free(buffer);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we call Enqueue() instead of SocketEnqueue() as there is
|
||||||
|
// no need to clone the buffer again.
|
||||||
|
return Enqueue(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - protocol interface
|
// #pragma mark - protocol interface
|
||||||
|
|
||||||
|
|
||||||
@@ -1093,6 +1129,13 @@ udp_receive_data(net_buffer *buffer)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
udp_deliver_data(net_protocol *protocol, net_buffer *buffer)
|
||||||
|
{
|
||||||
|
return ((UdpEndpoint *)protocol)->DeliverData(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
udp_error(uint32 code, net_buffer *data)
|
udp_error(uint32 code, net_buffer *data)
|
||||||
{
|
{
|
||||||
@@ -1204,6 +1247,7 @@ net_protocol_module_info sUDPModule = {
|
|||||||
udp_get_domain,
|
udp_get_domain,
|
||||||
udp_get_mtu,
|
udp_get_mtu,
|
||||||
udp_receive_data,
|
udp_receive_data,
|
||||||
|
udp_deliver_data,
|
||||||
udp_error,
|
udp_error,
|
||||||
udp_error_reply,
|
udp_error_reply,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -510,6 +510,7 @@ net_protocol_module_info gLinkModule = {
|
|||||||
link_get_domain,
|
link_get_domain,
|
||||||
link_get_mtu,
|
link_get_mtu,
|
||||||
link_receive_data,
|
link_receive_data,
|
||||||
|
NULL,
|
||||||
link_error,
|
link_error,
|
||||||
link_error_reply,
|
link_error_reply,
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user