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:
Hugo Santos
2007-04-15 07:31:04 +00:00
parent 4229d7091e
commit 6a60618094
8 changed files with 313 additions and 96 deletions
+2 -1
View File
@@ -55,8 +55,9 @@ struct net_protocol_module_info {
size_t (*get_mtu)(net_protocol *self, const struct sockaddr *address);
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,
uint32 code, void *errorData);
};
@@ -342,6 +342,7 @@ net_protocol_module_info sICMPModule = {
icmp_get_domain,
icmp_get_mtu,
icmp_receive_data,
NULL,
icmp_error,
icmp_error_reply,
};
@@ -117,9 +117,15 @@ class FragmentPacket {
class MulticastGroup {
public:
typedef MulticastGroupLink<IPv4Multicast> Link;
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 int Compare(void *address, const void *key);
@@ -128,8 +134,12 @@ public:
static const int kMaxGroups = 64;
private:
typedef DoublyLinkedListCLink<Link> LinkLink;
typedef DoublyLinkedList<Link, LinkLink> Links;
MulticastGroup *fNext;
in_addr fMulticastAddress;
Links fLinks;
};
class RawSocket : public DoublyLinkedListLinkImpl<RawSocket>, public DatagramSocket<> {
@@ -139,9 +149,11 @@ class RawSocket : public DoublyLinkedListLinkImpl<RawSocket>, public DatagramSoc
typedef DoublyLinkedList<RawSocket> RawSocketList;
typedef MulticastFilter<IPv4Multicast> IPv4MulticastFilter;
struct ipv4_protocol : net_protocol {
ipv4_protocol(net_socket *socket)
: multicast_filter(socket) {}
ipv4_protocol()
: multicast_filter(this) {}
RawSocket *raw;
uint8 service_type;
@@ -149,7 +161,7 @@ struct ipv4_protocol : net_protocol {
uint8 multicast_time_to_live;
uint32 flags;
MulticastFilter<in_addr> multicast_filter;
IPv4MulticastFilter multicast_filter;
};
// protocol flags
@@ -424,9 +436,35 @@ MulticastGroup::MulticastGroup(const in_addr &address)
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
deliver_multicast(net_buffer *buffer)
deliver_multicast(net_protocol_module_info *module, net_buffer *buffer)
{
BenaphoreLocker _(sMulticastGroupsLock);
@@ -678,9 +716,54 @@ deliver_multicast(net_buffer *buffer)
if (group == NULL)
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
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)
{
switch (option) {
@@ -742,8 +825,8 @@ ipv4_delta_membership(ipv4_protocol *protocol, int option,
net_interface *interface, const in_addr *groupAddr,
const in_addr *sourceAddr)
{
MulticastFilter<in_addr> &filter = protocol->multicast_filter;
MulticastFilter<in_addr>::GroupState *group = NULL;
IPv4MulticastFilter &filter = protocol->multicast_filter;
IPv4MulticastFilter::GroupState *group = NULL;
switch (option) {
case IP_ADD_MEMBERSHIP:
@@ -833,7 +916,7 @@ ipv4_generic_delta_membership(ipv4_protocol *protocol, int option,
net_protocol *
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)
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)
// we must no longer access bufferHeader or header anymore after
// this point
raw_receive_data(buffer);
if (!(buffer->flags & MSG_MCAST))
raw_receive_data(buffer);
gBufferModule->remove_header(buffer, headerLength);
// the header is of variable size and may include IP options
@@ -1436,10 +1512,30 @@ ipv4_receive_data(net_buffer *buffer)
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);
}
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
ipv4_error(uint32 code, net_buffer *data)
{
@@ -1591,6 +1687,7 @@ net_protocol_module_info gIPv4Module = {
ipv4_get_domain,
ipv4_get_mtu,
ipv4_receive_data,
ipv4_deliver_data,
ipv4_error,
ipv4_error_reply,
};
@@ -8,12 +8,14 @@
#include "multicast.h"
#include <net_buffer.h>
#include <netinet/in.h>
#include <new>
template class MulticastFilter<in_addr>;
template class MulticastGroupState<in_addr>;
template class MulticastFilter<IPv4Multicast>;
template class MulticastGroupState<IPv4Multicast>;
template class MulticastGroupInterfaceState<in_addr>;
static inline bool
@@ -94,25 +96,23 @@ MulticastGroupInterfaceState<AddressType>::_Remove(Source *state)
}
template<typename AddressType>
MulticastGroupState<AddressType>::MulticastGroupState(
MulticastFilter<AddressType> *parent, const AddressType &address)
: fParent(parent), fMulticastAddress(address), fFilterMode(kInclude)
template<typename Addressing>
MulticastGroupState<Addressing>::MulticastGroupState(net_protocol *socket,
const AddressType &address)
: fSocket(socket), fMulticastAddress(address), fFilterMode(kInclude)
{
}
template<typename AddressType>
MulticastGroupState<AddressType>::~MulticastGroupState()
template<typename Addressing>
MulticastGroupState<Addressing>::~MulticastGroupState()
{
InterfaceList::Iterator iterator = fInterfaces.GetIterator();
while (iterator.HasNext())
_RemoveInterface(iterator.Next());
Clear();
}
template<typename AddressType> status_t
MulticastGroupState<AddressType>::Add(net_interface *interface)
template<typename Addressing> status_t
MulticastGroupState<Addressing>::Add(net_interface *interface)
{
if (fFilterMode == kInclude && !fInterfaces.IsEmpty())
return EINVAL;
@@ -123,8 +123,8 @@ MulticastGroupState<AddressType>::Add(net_interface *interface)
}
template<typename AddressType> status_t
MulticastGroupState<AddressType>::Drop(net_interface *interface)
template<typename Addressing> status_t
MulticastGroupState<Addressing>::Drop(net_interface *interface)
{
InterfaceState *state = _GetInterface(interface, false);
if (state == NULL)
@@ -139,8 +139,8 @@ MulticastGroupState<AddressType>::Drop(net_interface *interface)
}
template<typename AddressType> status_t
MulticastGroupState<AddressType>::BlockSource(net_interface *interface,
template<typename Addressing> status_t
MulticastGroupState<Addressing>::BlockSource(net_interface *interface,
const AddressType &sourceAddress)
{
if (fFilterMode != kExclude)
@@ -154,8 +154,8 @@ MulticastGroupState<AddressType>::BlockSource(net_interface *interface,
}
template<typename AddressType> status_t
MulticastGroupState<AddressType>::UnblockSource(net_interface *interface,
template<typename Addressing> status_t
MulticastGroupState<Addressing>::UnblockSource(net_interface *interface,
const AddressType &sourceAddress)
{
if (fFilterMode != kExclude)
@@ -168,8 +168,8 @@ MulticastGroupState<AddressType>::UnblockSource(net_interface *interface,
return state->Remove(sourceAddress);
}
template<typename AddressType> status_t
MulticastGroupState<AddressType>::AddSSM(net_interface *interface,
template<typename Addressing> status_t
MulticastGroupState<Addressing>::AddSSM(net_interface *interface,
const AddressType &sourceAddress)
{
if (fFilterMode == kExclude)
@@ -183,8 +183,8 @@ MulticastGroupState<AddressType>::AddSSM(net_interface *interface,
}
template<typename AddressType> status_t
MulticastGroupState<AddressType>::DropSSM(net_interface *interface,
template<typename Addressing> status_t
MulticastGroupState<Addressing>::DropSSM(net_interface *interface,
const AddressType &sourceAddress)
{
if (fFilterMode == kExclude)
@@ -198,8 +198,31 @@ MulticastGroupState<AddressType>::DropSSM(net_interface *interface,
}
template<typename AddressType> MulticastGroupState<AddressType>::InterfaceState *
MulticastGroupState<AddressType>::_GetInterface(net_interface *interface,
template<typename Addressing> void
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)
{
InterfaceList::Iterator iterator = fInterfaces.GetIterator();
@@ -220,35 +243,35 @@ MulticastGroupState<AddressType>::_GetInterface(net_interface *interface,
}
template<typename AddressType> void
MulticastGroupState<AddressType>::_RemoveInterface(InterfaceState *state)
template<typename Addressing> void
MulticastGroupState<Addressing>::_RemoveInterface(InterfaceState *state)
{
fInterfaces.Remove(state);
delete state;
}
template<typename AddressType>
MulticastFilter<AddressType>::MulticastFilter(net_socket *socket)
template<typename Addressing>
MulticastFilter<Addressing>::MulticastFilter(net_protocol *socket)
: fParent(socket)
{
}
template<typename AddressType>
MulticastFilter<AddressType>::~MulticastFilter()
template<typename Addressing>
MulticastFilter<Addressing>::~MulticastFilter()
{
States::Iterator iterator = fStates.GetIterator();
while (iterator.HasNext()) {
GroupState *state = iterator.Next();
fStates.Remove(state);
delete state;
state->Clear();
ReturnGroup(state);
}
}
template<typename AddressType> MulticastFilter<AddressType>::GroupState *
MulticastFilter<AddressType>::GetGroup(const AddressType &groupAddress,
template<typename Addressing> MulticastFilter<Addressing>::GroupState *
MulticastFilter<Addressing>::GetGroup(const AddressType &groupAddress,
bool create)
{
States::Iterator iterator = fStates.GetIterator();
@@ -262,17 +285,26 @@ MulticastFilter<AddressType>::GetGroup(const AddressType &groupAddress,
if (!create)
return NULL;
GroupState *state = new (nothrow) GroupState(this, groupAddress);
if (state)
GroupState *state = new (nothrow) GroupState(fParent, groupAddress);
if (state) {
if (Addressing::JoinGroup(groupAddress, state->ProtocolLink()) < B_OK) {
delete state;
return NULL;
}
fStates.Add(state);
}
return state;
}
template<typename AddressType> void
MulticastFilter<AddressType>::ReturnGroup(GroupState *group)
template<typename Addressing> void
MulticastFilter<Addressing>::ReturnGroup(GroupState *group)
{
if (group->IsEmpty()) {
Addressing::LeaveGroup(group->Address(), group->ProtocolLink());
fStates.Remove(group);
delete group;
}
@@ -12,10 +12,30 @@
#include <util/DoublyLinkedList.h>
#include <util/list.h>
struct net_interface;
struct net_socket;
#include <netinet/in.h>
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>
struct MulticastSource {
@@ -34,6 +54,9 @@ public:
status_t Add(const AddressType &address);
status_t Remove(const AddressType &address);
bool Contains(const AddressType &address)
{ return _Get(address, false) != NULL; }
list_link link;
private:
typedef MulticastSource<AddressType> Source;
@@ -48,13 +71,22 @@ private:
SourceList fSources;
};
template<typename AddressType>
template<typename Addressing>
struct MulticastGroupLink {
MulticastGroupState<Addressing> *group;
list_link link;
};
template<typename Addressing>
class MulticastGroupState {
public:
MulticastGroupState(MulticastFilter<AddressType> *parent,
const AddressType &address);
typedef typename Addressing::AddressType AddressType;
MulticastGroupState(net_protocol *parent, const AddressType &address);
~MulticastGroupState();
net_protocol *Socket() const { return fSocket; }
const AddressType &Address() const { return fMulticastAddress; }
bool IsEmpty() const
{ return fFilterMode == kInclude && fInterfaces.IsEmpty(); }
@@ -70,6 +102,12 @@ public:
status_t DropSSM(net_interface *interface,
const AddressType &sourceAddress);
void Clear();
bool FilterAccepts(net_buffer *buffer);
MulticastGroupLink<Addressing> *ProtocolLink() { return &fInternalLink; }
list_link link;
private:
typedef MulticastGroupInterfaceState<AddressType> InterfaceState;
@@ -84,21 +122,23 @@ private:
kExclude
};
MulticastFilter<AddressType> *fParent;
net_protocol *fSocket;
AddressType fMulticastAddress;
FilterMode fFilterMode;
InterfaceList fInterfaces;
MulticastGroupLink<Addressing> fInternalLink;
};
template<typename AddressType>
template<typename Addressing>
class MulticastFilter {
public:
typedef MulticastGroupState<AddressType> GroupState;
typedef typename Addressing::AddressType AddressType;
typedef MulticastGroupState<Addressing> GroupState;
MulticastFilter(net_socket *parent);
MulticastFilter(net_protocol *parent);
~MulticastFilter();
net_socket *Parent() const { return fParent; }
net_protocol *Parent() const { return fParent; }
GroupState *GetGroup(const AddressType &groupAddress, bool create);
void ReturnGroup(GroupState *group);
@@ -107,7 +147,7 @@ private:
typedef DoublyLinkedListCLink<GroupState> GroupStateLink;
typedef DoublyLinkedList<GroupState, GroupStateLink> States;
net_socket *fParent;
net_protocol *fParent;
// TODO change this into an hash table or tree
States fStates;
@@ -718,6 +718,7 @@ net_protocol_module_info sTCPModule = {
tcp_get_domain,
tcp_get_mtu,
tcp_receive_data,
NULL,
tcp_error,
tcp_error_reply,
};
@@ -82,6 +82,7 @@ public:
net_buffer **_buffer);
status_t StoreData(net_buffer *buffer);
status_t DeliverData(net_buffer *buffer);
net_domain * Domain() const
{
@@ -179,6 +180,7 @@ public:
~UdpEndpointManager();
status_t ReceiveData(net_buffer *buffer);
status_t Deframe(net_buffer *buffer);
UdpDomainSupport *OpenEndpoint(UdpEndpoint *endpoint);
status_t FreeEndpoint(UdpDomainSupport *domain);
@@ -544,8 +546,40 @@ UdpEndpointManager::InitCheck() const
status_t
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);
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);
if (bufferHeader.Status() < B_OK)
return bufferHeader.Status();
@@ -556,7 +590,7 @@ UdpEndpointManager::ReceiveData(net_buffer *buffer)
struct sockaddr *destination = (struct sockaddr *)&buffer->destination;
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);
return B_BAD_VALUE;
}
@@ -564,18 +598,16 @@ UdpEndpointManager::ReceiveData(net_buffer *buffer)
net_domain *domain = buffer->interface->domain;
net_address_module_info *addressModule = domain->address_module;
BenaphoreLocker _(fLock);
addressModule->set_port(source, header.source_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, destination, true).Data());
uint16 udpLength = ntohs(header.udp_length);
if (udpLength > buffer->size) {
TRACE_EPM(" ReceiveData(): buffer is too short, expected %hu.",
TRACE_EPM(" Deframe(): buffer is too short, expected %hu.",
udpLength);
return B_MISMATCHED_VALUES;
}
@@ -596,7 +628,7 @@ UdpEndpointManager::ReceiveData(net_buffer *buffer)
<< Checksum::BufferHelper(buffer, gBufferModule);
uint16 sum = udpChecksum;
if (sum != 0) {
TRACE_EPM(" ReceiveData(): bad checksum 0x%hx.", sum);
TRACE_EPM(" Deframe(): bad checksum 0x%hx.", sum);
return B_BAD_VALUE;
}
}
@@ -604,22 +636,7 @@ UdpEndpointManager::ReceiveData(net_buffer *buffer)
bufferHeader.Remove();
// remove UDP-header from buffer before passing it on
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_t status = domainSupport->DemuxIncomingBuffer(buffer);
if (status < B_OK) {
TRACE_EPM(" ReceiveData(): no endpoint.");
// TODO: send ICMP-error
return B_ERROR;
}
return B_ERROR;
return B_OK;
}
@@ -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
@@ -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
udp_error(uint32 code, net_buffer *data)
{
@@ -1204,6 +1247,7 @@ net_protocol_module_info sUDPModule = {
udp_get_domain,
udp_get_mtu,
udp_receive_data,
udp_deliver_data,
udp_error,
udp_error_reply,
};
@@ -510,6 +510,7 @@ net_protocol_module_info gLinkModule = {
link_get_domain,
link_get_mtu,
link_receive_data,
NULL,
link_error,
link_error_reply,
};