diff --git a/headers/private/kernel/util/MultiHashTable.h b/headers/private/kernel/util/MultiHashTable.h index 4b05aca556..79df88d250 100644 --- a/headers/private/kernel/util/MultiHashTable.h +++ b/headers/private/kernel/util/MultiHashTable.h @@ -85,6 +85,8 @@ public: return true; } + Iterator GetIterator() const { return HashTable::GetIterator(); } + private: void _Insert(ValueType **table, size_t tableSize, ValueType *value) { diff --git a/src/add-ons/kernel/network/protocols/ipv4/ipv4.cpp b/src/add-ons/kernel/network/protocols/ipv4/ipv4.cpp index 3639505157..11f929cf8a 100644 --- a/src/add-ons/kernel/network/protocols/ipv4/ipv4.cpp +++ b/src/add-ons/kernel/network/protocols/ipv4/ipv4.cpp @@ -11,6 +11,7 @@ #include "multicast.h" #include +#include #include #include #include @@ -22,7 +23,7 @@ #include #include #include -#include +#include #include #include @@ -30,6 +31,7 @@ #include #include #include +#include //#define TRACE_IPV4 @@ -118,48 +120,6 @@ class FragmentPacket { }; -class MulticastGroup { -public: - MulticastGroup(const in_addr &address); - - status_t Deliver(net_protocol_module_info *module, net_buffer *buffer, - bool raw); - - void Add(IPv4Multicast::GroupState *groupState); - void Remove(IPv4Multicast::GroupState *groupState); - bool IsEmpty() const { return fLinks.IsEmpty(); } - - struct HashDefinition { - typedef void ParentType; - typedef const in_addr KeyType; - typedef MulticastGroup ValueType; - - size_t HashKey(const in_addr &address) const - { return address.s_addr; } - size_t Hash(MulticastGroup *group) const - { return HashKey(group->fMulticastAddress); } - bool Compare(const in_addr &address, MulticastGroup *group) const - { return group->fMulticastAddress.s_addr == address.s_addr; } - HashTableLink *GetLink(MulticastGroup *group) const - { return &group->fLink; } - }; - - void DumpInternalState() const; - -private: - // for g++ 2.95 - friend class HashDefinition; - - typedef DoublyLinkedList Links; - - in_addr fMulticastAddress; - Links fLinks; - - HashTableLink fLink; -}; - - - class RawSocket : public DoublyLinkedListLinkImpl, public DatagramSocket<> { public: RawSocket(net_socket *socket); @@ -167,8 +127,29 @@ class RawSocket : public DoublyLinkedListLinkImpl, public DatagramSoc typedef DoublyLinkedList RawSocketList; +typedef MulticastGroupInterface IPv4GroupInterface; typedef MulticastFilter IPv4MulticastFilter; +struct MulticastStateHash { + typedef void ParentType; + typedef std::pair KeyType; + typedef IPv4GroupInterface ValueType; + + size_t HashKey(const KeyType &key) const + { return key.first->s_addr ^ key.second; } + size_t Hash(ValueType *value) const + { return HashKey(std::make_pair(&value->Address(), + value->Interface()->index)); } + bool Compare(const KeyType &key, ValueType *value) const + { return value->Interface()->index == key.second + && value->Address().s_addr == key.first->s_addr; } + bool CompareValues(ValueType *value1, ValueType *value2) const + { return value1->Interface()->index == value2->Interface()->index + && value1->Address().s_addr == value2->Address().s_addr; } + HashTableLink *GetLink(ValueType *value) const { return value; } +}; + + struct ipv4_protocol : net_protocol { ipv4_protocol() : multicast_filter(this) {} @@ -205,8 +186,10 @@ static benaphore sRawSocketsLock; static benaphore sFragmentLock; static hash_table *sFragmentHash; static benaphore sMulticastGroupsLock; -typedef OpenHashTable MulticastGroups; -static MulticastGroups *sMulticastGroups; + +typedef MultiHashTable MulticastState; +static MulticastState *sMulticastState; + static net_protocol_module_info *sReceivingProtocol[256]; static benaphore sReceivingProtocolLock; @@ -461,73 +444,6 @@ FragmentPacket::StaleTimer(struct net_timer *timer, void *data) } -MulticastGroup::MulticastGroup(const in_addr &address) - : fMulticastAddress(address) -{ -} - - -status_t -MulticastGroup::Deliver(net_protocol_module_info *module, net_buffer *buffer, - bool deliverToRaw) -{ - Links::Iterator iterator = fLinks.GetIterator(); - - while (iterator.HasNext()) { - IPv4Multicast::GroupState *groupState = iterator.Next(); - - if (deliverToRaw && groupState->Socket()->raw == NULL) - continue; - - if (groupState->FilterAccepts(buffer)) { - // as Multicast filters are installed with an IPv4 protocol - // reference, we need to go and find the appropriate instance - // related to the 'receiving protocol' with module 'module'. - net_protocol *proto = groupState->Socket()->socket->first_protocol; - - while (proto && proto->module != module) - proto = proto->next; - - if (proto) - module->deliver_data(proto, buffer); - } - } - - return B_OK; -} - - -void -MulticastGroup::Add(IPv4Multicast::GroupState *groupState) -{ - fLinks.Add(groupState); -} - - -void -MulticastGroup::Remove(IPv4Multicast::GroupState *groupState) -{ - fLinks.Remove(groupState); -} - - -void -MulticastGroup::DumpInternalState() const -{ - char addrBuf[64]; - - kprintf("group %s (%p)\n", print_address(&fMulticastAddress, addrBuf, - sizeof(addrBuf)), this); - - Links::ConstIterator it = fLinks.GetIterator(); - while (it.HasNext()) { - IPv4Multicast::GroupState *group = it.Next(); - - kprintf(" socket %p\n", group->Socket()); - } -} - - // #pragma mark - @@ -730,12 +646,37 @@ deliver_multicast(net_protocol_module_info *module, net_buffer *buffer, BenaphoreLocker _(sMulticastGroupsLock); - MulticastGroup *group = sMulticastGroups->Lookup( - ((sockaddr_in *)&buffer->destination)->sin_addr); - if (group == NULL) - return B_OK; + sockaddr_in *multicastAddr = (sockaddr_in *)&buffer->destination; - return group->Deliver(module, buffer, deliverToRaw); + MulticastState::Iterator it = sMulticastState->Lookup(std::make_pair( + &multicastAddr->sin_addr, buffer->interface->index)); + + while (it.HasNext()) { + IPv4GroupInterface *state = it.Next(); + + if (state->Interface()->index != buffer->interface->index + || state->Address().s_addr != multicastAddr->sin_addr.s_addr) + break; + + if (deliverToRaw && state->Parent()->Socket()->raw == NULL) + continue; + + if (state->FilterAccepts(buffer)) { + // as Multicast filters are installed with an IPv4 protocol + // reference, we need to go and find the appropriate instance + // related to the 'receiving protocol' with module 'module'. + net_protocol *proto = + state->Parent()->Socket()->socket->first_protocol; + + while (proto && proto->module != module) + proto = proto->next; + + if (proto) + module->deliver_data(proto, buffer); + } + } + + return B_OK; } @@ -770,40 +711,42 @@ raw_receive_data(net_buffer *buffer) status_t -IPv4Multicast::JoinGroup(GroupState *groupState) +IPv4Multicast::JoinGroup(IPv4GroupInterface *state) { BenaphoreLocker _(sMulticastGroupsLock); - MulticastGroup *group = sMulticastGroups->Lookup(groupState->Address()); - if (group == NULL) { - group = new (std::nothrow) MulticastGroup(groupState->Address()); - if (group == NULL) - return B_NO_MEMORY; + sockaddr_in groupAddr; + memset(&groupAddr, 0, sizeof(groupAddr)); + groupAddr.sin_addr = state->Address(); - sMulticastGroups->Insert(group); - } + net_interface *intf = state->Interface(); - group->Add(groupState); + status_t status = + intf->first_protocol->module->join_multicast(intf->first_protocol, + (sockaddr *)&groupAddr); + if (status < B_OK) + return status; + + sMulticastState->Insert(state); return B_OK; } status_t -IPv4Multicast::LeaveGroup(GroupState *groupState) +IPv4Multicast::LeaveGroup(IPv4GroupInterface *state) { BenaphoreLocker _(sMulticastGroupsLock); - MulticastGroup *group = sMulticastGroups->Lookup(groupState->Address()); - if (group == NULL) - return ENOENT; + sMulticastState->Remove(state); - group->Remove(groupState); - if (group->IsEmpty()) { - sMulticastGroups->Remove(group); - delete group; - } + sockaddr_in groupAddr; + memset(&groupAddr, 0, sizeof(groupAddr)); + groupAddr.sin_addr = state->Address(); - return B_OK; + net_interface *intf = state->Interface(); + + return intf->first_protocol->module->join_multicast(intf->first_protocol, + (sockaddr *)&groupAddr); } @@ -838,22 +781,22 @@ fill_sockaddr_in(sockaddr_in *target, in_addr_t address) static status_t -ipv4_delta_group(IPv4MulticastFilter::GroupState *group, int option, +ipv4_delta_group(IPv4GroupInterface *group, int option, net_interface *interface, const in_addr *sourceAddr) { switch (option) { case IP_ADD_MEMBERSHIP: - return group->Add(interface); + return group->Add(); case IP_DROP_MEMBERSHIP: - return group->Drop(interface); + return group->Drop(); case IP_BLOCK_SOURCE: - return group->BlockSource(interface, *sourceAddr); + return group->BlockSource(*sourceAddr); case IP_UNBLOCK_SOURCE: - return group->UnblockSource(interface, *sourceAddr); + return group->UnblockSource(*sourceAddr); case IP_ADD_SOURCE_MEMBERSHIP: - return group->AddSSM(interface, *sourceAddr); + return group->AddSSM(*sourceAddr); case IP_DROP_SOURCE_MEMBERSHIP: - return group->DropSSM(interface, *sourceAddr); + return group->DropSSM(*sourceAddr); } return B_ERROR; @@ -866,22 +809,21 @@ ipv4_delta_membership(ipv4_protocol *protocol, int option, const in_addr *sourceAddr) { IPv4MulticastFilter &filter = protocol->multicast_filter; - IPv4MulticastFilter::GroupState *group = NULL; + IPv4GroupInterface *state = NULL; + status_t status = B_OK; switch (option) { case IP_ADD_MEMBERSHIP: case IP_ADD_SOURCE_MEMBERSHIP: - group = filter.GetGroup(*groupAddr, true); - if (group == NULL) - return ENOBUFS; + status = filter.GetState(*groupAddr, interface, state, true); break; case IP_DROP_MEMBERSHIP: case IP_BLOCK_SOURCE: case IP_UNBLOCK_SOURCE: case IP_DROP_SOURCE_MEMBERSHIP: - group = filter.GetGroup(*groupAddr, false); - if (group == NULL) { + filter.GetState(*groupAddr, interface, state, false); + if (state == NULL) { if (option == IP_DROP_MEMBERSHIP || option == IP_DROP_SOURCE_MEMBERSHIP) return EADDRNOTAVAIL; @@ -891,10 +833,11 @@ ipv4_delta_membership(ipv4_protocol *protocol, int option, break; } - status_t status = ipv4_delta_group(group, option, interface, sourceAddr); - - filter.ReturnGroup(group); + if (status < B_OK) + return status; + status = ipv4_delta_group(state, option, interface, sourceAddr); + filter.ReturnState(state); return status; } @@ -1590,10 +1533,17 @@ ipv4_error_reply(net_protocol *protocol, net_buffer *causedError, uint32 code, static int dump_ipv4_multicast(int argc, char *argv[]) { - MulticastGroups::Iterator it = sMulticastGroups->GetIterator(); + MulticastState::Iterator it = sMulticastState->GetIterator(); - while (it.HasNext()) - it.Next()->DumpInternalState(); + while (it.HasNext()) { + IPv4GroupInterface *state = it.Next(); + + char addrBuf[64]; + + kprintf("%p: group <%s, %s> sock %p\n", state, + state->Interface()->name, print_address(&state->Address(), + addrBuf, sizeof(addrBuf)), state->Parent()->Socket()); + } return 0; } @@ -1623,11 +1573,11 @@ init_ipv4() if (status < B_OK) goto err3; - sMulticastGroups = new MulticastGroups(); - if (sMulticastGroups == NULL) + sMulticastState = new MulticastState(); + if (sMulticastState == NULL) goto err4; - status = sMulticastGroups->InitCheck(); + status = sMulticastState->InitCheck(); if (status < B_OK) goto err5; @@ -1659,7 +1609,7 @@ init_ipv4() err6: hash_uninit(sFragmentHash); err5: - delete sMulticastGroups; + delete sMulticastState; err4: benaphore_destroy(&sReceivingProtocolLock); err3: @@ -1688,7 +1638,7 @@ uninit_ipv4() gStackModule->unregister_domain(sDomain); benaphore_unlock(&sReceivingProtocolLock); - delete sMulticastGroups; + delete sMulticastState; hash_uninit(sFragmentHash); benaphore_destroy(&sMulticastGroupsLock); diff --git a/src/add-ons/kernel/network/protocols/ipv4/multicast.cpp b/src/add-ons/kernel/network/protocols/ipv4/multicast.cpp index 5e24757b37..f4d61d432d 100644 --- a/src/add-ons/kernel/network/protocols/ipv4/multicast.cpp +++ b/src/add-ons/kernel/network/protocols/ipv4/multicast.cpp @@ -23,227 +23,120 @@ operator==(const in_addr &a1, const in_addr &a2) using std::nothrow; -template -MulticastGroupInterfaceState::MulticastGroupInterfaceState( - net_interface *interface) - : fInterface(interface) -{ -} - - -template -MulticastGroupInterfaceState::~MulticastGroupInterfaceState() -{ - typename SourceList::Iterator iterator = fSources.GetIterator(); - while (iterator.HasNext()) { - _Remove(iterator.Next()); - } -} - - -template status_t -MulticastGroupInterfaceState::Add(const AddressType &address) -{ - return _Get(address, true) ? B_OK : ENOBUFS; -} - - -template status_t -MulticastGroupInterfaceState::Remove(const AddressType &address) -{ - Source *state = _Get(address, false); - if (state == NULL) - return EADDRNOTAVAIL; - - _Remove(state); - return B_OK; -} - - -template typename MulticastGroupInterfaceState::Source * -MulticastGroupInterfaceState::_Get(const AddressType &address, - bool create) -{ - typename SourceList::Iterator iterator = fSources.GetIterator(); - while (iterator.HasNext()) { - Source *state = iterator.Next(); - if (state->address == address) - return state; - } - - if (!create) - return false; - - Source *state = new (nothrow) Source; - if (state) { - state->address = address; - fSources.Add(state); - } - - return state; -} - - -template void -MulticastGroupInterfaceState::_Remove(Source *state) -{ - fSources.Remove(state); - delete state; -} - - template -MulticastGroupState::MulticastGroupState(ProtocolType *socket, - const AddressType &address) - : fSocket(socket), fMulticastAddress(address), fFilterMode(kInclude) +MulticastGroupInterface::MulticastGroupInterface(Filter *parent, + const AddressType &address, net_interface *interface) + : fParent(parent), fMulticastAddress(address), fInterface(interface) { } template -MulticastGroupState::~MulticastGroupState() +MulticastGroupInterface::~MulticastGroupInterface() { Clear(); } template status_t -MulticastGroupState::Add(net_interface *interface) +MulticastGroupInterface::Add() { - if (fFilterMode == kInclude && !fInterfaces.IsEmpty()) + if (fFilterMode == kInclude && !fAddresses.IsEmpty()) return EINVAL; fFilterMode = kExclude; - - return _GetInterface(interface, true) != NULL ? B_OK : ENOBUFS; -} - - -template status_t -MulticastGroupState::Drop(net_interface *interface) -{ - InterfaceState *state = _GetInterface(interface, false); - if (state == NULL) - return EADDRNOTAVAIL; - - _RemoveInterface(state); - - if (fInterfaces.IsEmpty()) - fFilterMode = kInclude; - return B_OK; } template status_t -MulticastGroupState::BlockSource(net_interface *interface, +MulticastGroupInterface::Drop() +{ + fAddresses.Clear(); + fFilterMode = kInclude; + return B_OK; +} + + +template status_t +MulticastGroupInterface::BlockSource( const AddressType &sourceAddress) { if (fFilterMode != kExclude) return EINVAL; - InterfaceState *state = _GetInterface(interface, false); - if (state == NULL) - return EINVAL; - - return state->Add(sourceAddress); + fAddresses.Add(sourceAddress); + return B_OK; } template status_t -MulticastGroupState::UnblockSource(net_interface *interface, +MulticastGroupInterface::UnblockSource( const AddressType &sourceAddress) { if (fFilterMode != kExclude) return EINVAL; - InterfaceState *state = _GetInterface(interface, false); - if (state == NULL) - return EINVAL; - - return state->Remove(sourceAddress); -} - -template status_t -MulticastGroupState::AddSSM(net_interface *interface, - const AddressType &sourceAddress) -{ - if (fFilterMode == kExclude) - return EINVAL; - - InterfaceState *state = _GetInterface(interface, true); - if (state == NULL) - return ENOBUFS; - - return state->Add(sourceAddress); -} - - -template status_t -MulticastGroupState::DropSSM(net_interface *interface, - const AddressType &sourceAddress) -{ - if (fFilterMode == kExclude) - return EINVAL; - - InterfaceState *state = _GetInterface(interface, false); - if (state == NULL) + if (!fAddresses.Has(sourceAddress)) return EADDRNOTAVAIL; - return state->Remove(sourceAddress); + fAddresses.Add(sourceAddress); + return B_OK; } -template void -MulticastGroupState::Clear() +template status_t +MulticastGroupInterface::AddSSM(const AddressType &sourceAddress) { - typename InterfaceList::Iterator iterator = fInterfaces.GetIterator(); - while (iterator.HasNext()) - _RemoveInterface(iterator.Next()); + if (fFilterMode == kExclude) + return EINVAL; + + fAddresses.Add(sourceAddress); + return B_OK; +} + + +template status_t +MulticastGroupInterface::DropSSM(const AddressType &sourceAddress) +{ + if (fFilterMode == kExclude) + return EINVAL; + + if (!fAddresses.Has(sourceAddress)) + return EADDRNOTAVAIL; + + fAddresses.Add(sourceAddress); + return B_OK; } template bool -MulticastGroupState::FilterAccepts(net_buffer *buffer) +MulticastGroupInterface::IsEmpty() const { - 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 MulticastGroupState::InterfaceState * -MulticastGroupState::_GetInterface(net_interface *interface, - bool create) -{ - typename InterfaceList::Iterator iterator = fInterfaces.GetIterator(); - while (iterator.HasNext()) { - InterfaceState *state = iterator.Next(); - if (state->Interface() == interface) - return state; - } - - if (!create) - return false; - - InterfaceState *state = new (nothrow) InterfaceState(interface); - if (state) - fInterfaces.Add(state); - - return state; + return fFilterMode == kInclude && fAddresses.IsEmpty(); } template void -MulticastGroupState::_RemoveInterface(InterfaceState *state) +MulticastGroupInterface::Clear() { - fInterfaces.Remove(state); - delete state; + if (IsEmpty()) + return; + + fFilterMode = kInclude; + fAddresses.Clear(); + Addressing::LeaveGroup(this); +} + + +template bool +MulticastGroupInterface::FilterAccepts(net_buffer *buffer) const +{ + bool has = fAddresses.Has(Addressing::AddressFromSockAddr( + (sockaddr *)&buffer->source)); + + return (has && fFilterMode == kInclude) + || (!has && fFilterMode == kExclude); } @@ -262,56 +155,58 @@ MulticastFilter::~MulticastFilter() if (!iterator.HasNext()) return; - GroupState *state = iterator.Next(); + GroupInterface *state = iterator.Next(); state->Clear(); - _ReturnGroup(state); + _ReturnState(state); } } -template typename MulticastFilter::GroupState * -MulticastFilter::GetGroup(const AddressType &groupAddress, - bool create) +template status_t +MulticastFilter::GetState(const AddressType &groupAddress, + net_interface *interface, GroupInterface* &state, bool create) { - GroupState *state = fStates.Lookup(groupAddress); - if (state) - return state; + state = fStates.Lookup(std::make_pair(&groupAddress, interface->index)); - if (create) { - state = new (nothrow) GroupState(fParent, groupAddress); - if (state) { - if (fStates.Insert(state) >= B_OK) { - if (Addressing::JoinGroup(state) >= B_OK) - return state; - - fStates.Remove(state); - } + if (state == NULL && create) { + state = new (nothrow) GroupInterface(this, groupAddress, interface); + if (state == NULL) + return B_NO_MEMORY; + status_t status = fStates.Insert(state); + if (status < B_OK) { delete state; + return status; } + + status = Addressing::JoinGroup(state); + if (status < B_OK) { + fStates.Remove(state); + delete state; + return status; + } + } - return NULL; + return B_OK; } template void -MulticastFilter::ReturnGroup(GroupState *group) +MulticastFilter::ReturnState(GroupInterface *state) { - if (group->IsEmpty()) - _ReturnGroup(group); + if (state->IsEmpty()) + _ReturnState(state); } template void -MulticastFilter::_ReturnGroup(GroupState *group) +MulticastFilter::_ReturnState(GroupInterface *state) { - Addressing::LeaveGroup(group); - fStates.Remove(group); - delete group; + fStates.Remove(state); + delete state; } // IPv4 explicit template instantiation template class MulticastFilter; -template class MulticastGroupState; -template class MulticastGroupInterfaceState; +template class MulticastGroupInterface; diff --git a/src/add-ons/kernel/network/protocols/ipv4/multicast.h b/src/add-ons/kernel/network/protocols/ipv4/multicast.h index 3119257f79..423381c189 100644 --- a/src/add-ons/kernel/network/protocols/ipv4/multicast.h +++ b/src/add-ons/kernel/network/protocols/ipv4/multicast.h @@ -12,25 +12,28 @@ #include #include +#include + #include +#include + struct net_buffer; -struct net_interface; struct net_protocol; // This code is template'ized as it is reusable for IPv6 template class MulticastFilter; -template class MulticastGroupState; +template class MulticastGroupInterface; // TODO move this elsewhere... struct IPv4Multicast { typedef struct in_addr AddressType; typedef struct ipv4_protocol ProtocolType; - typedef MulticastGroupState GroupState; + typedef MulticastGroupInterface GroupInterface; - static status_t JoinGroup(GroupState *); - static status_t LeaveGroup(GroupState *); + static status_t JoinGroup(GroupInterface *); + static status_t LeaveGroup(GroupInterface *); static const in_addr &AddressFromSockAddr(const sockaddr *sockaddr) { return ((const sockaddr_in *)sockaddr)->sin_addr; } @@ -39,106 +42,131 @@ struct IPv4Multicast { }; template -struct MulticastSource - : DoublyLinkedListLinkImpl< MulticastSource > { - AddressType address; -}; - -template -class MulticastGroupInterfaceState - : public DoublyLinkedListLinkImpl< MulticastGroupInterfaceState > { +class AddressSet { public: - MulticastGroupInterfaceState(net_interface *interface); - ~MulticastGroupInterfaceState(); - - net_interface *Interface() const { return fInterface; } - - status_t Add(const AddressType &address); - status_t Remove(const AddressType &address); - - bool Contains(const AddressType &address) - { return _Get(address, false) != NULL; } - -private: - typedef MulticastSource Source; - typedef DoublyLinkedList SourceList; - - Source *_Get(const AddressType &address, bool create); - void _Remove(Source *state); - - net_interface *fInterface; - // TODO make this an hash table as well - SourceList fSources; -}; - -template -class MulticastGroupState - : public DoublyLinkedListLinkImpl< MulticastGroupState > { -public: - typedef MulticastGroupState ThisType; - typedef HashTableLink HashLink; - typedef typename Addressing::AddressType AddressType; - typedef typename Addressing::ProtocolType ProtocolType; - - MulticastGroupState(ProtocolType *parent, const AddressType &address); - ~MulticastGroupState(); - - ProtocolType *Socket() const { return fSocket; } - - const AddressType &Address() const { return fMulticastAddress; } - bool IsEmpty() const - { return fFilterMode == kInclude && fInterfaces.IsEmpty(); } - - status_t Add(net_interface *interface); - status_t Drop(net_interface *interface); - status_t BlockSource(net_interface *interface, - const AddressType &sourceAddress); - status_t UnblockSource(net_interface *interface, - const AddressType &sourceAddress); - status_t AddSSM(net_interface *interface, - const AddressType &sourceAddress); - status_t DropSSM(net_interface *interface, - const AddressType &sourceAddress); - - void Clear(); - - bool FilterAccepts(net_buffer *buffer); - - struct HashDefinition { - typedef void ParentType; - typedef typename MulticastGroupState::AddressType KeyType; - typedef typename MulticastGroupState::ThisType ValueType; - typedef typename MulticastGroupState::HashLink HashLink; - - size_t HashKey(const KeyType &key) const - { return Addressing::HashAddress(key); } - size_t Hash(ValueType *value) const - { return HashKey(value->Address()); } - bool Compare(const KeyType &key, ValueType *value) const - { return key == value->Address(); } - HashLink *GetLink(ValueType *value) const { return &value->fHashLink; } + struct ContainedAddress : DoublyLinkedListLinkImpl { + AddressType address; }; + ~AddressSet() { Clear(); } + + status_t Add(const AddressType &address) + { + if (Has(address)) + return B_OK; + + ContainedAddress *container = new ContainedAddress(); + if (container == NULL) + return B_NO_MEMORY; + + container->address = address; + fAddresses.Add(container); + + return B_OK; + } + + void Remove(const AddressType &address) + { + ContainedAddress *container = _Get(address); + if (container == NULL) + return; + + fAddresses.Remove(container); + delete container; + } + + bool Has(const AddressType &address) const + { + return _Get(address) != NULL; + } + + bool IsEmpty() const { return fAddresses.IsEmpty(); } + + void Clear() + { + while (!fAddresses.IsEmpty()) + Remove(fAddresses.Head()->address); + } + private: - // for g++ 2.95 - friend class HashDefinition; + typedef DoublyLinkedList AddressList; - typedef MulticastGroupInterfaceState InterfaceState; - typedef DoublyLinkedList InterfaceList; + ContainedAddress *_Get(const AddressType &address) const + { + AddressList::ConstIterator it = fAddresses.GetIterator(); + while (it.HasNext()) { + ContainedAddress *container = it.Next(); + if (container->address == address) + return container; + } + return NULL; + } - InterfaceState *_GetInterface(net_interface *interface, bool create); - void _RemoveInterface(InterfaceState *state); + AddressList fAddresses; +}; + + +template +class MulticastGroupInterface + : public HashTableLink< MulticastGroupInterface > { +public: + typedef MulticastGroupInterface ThisType; + typedef HashTableLink HashLink; + typedef typename Addressing::AddressType AddressType; + typedef MulticastFilter Filter; enum FilterMode { kInclude, kExclude }; - ProtocolType *fSocket; + MulticastGroupInterface(Filter *parent, const AddressType &address, + net_interface *interface); + ~MulticastGroupInterface(); + + Filter *Parent() const { return fParent; } + + const AddressType &Address() const { return fMulticastAddress; } + net_interface *Interface() const { return fInterface; } + + status_t Add(); + status_t Drop(); + status_t BlockSource(const AddressType &sourceAddress); + status_t UnblockSource(const AddressType &sourceAddress); + status_t AddSSM(const AddressType &sourceAddress); + status_t DropSSM(const AddressType &sourceAddress); + + bool IsEmpty() const; + void Clear(); + + bool FilterAccepts(net_buffer *buffer) const; + + struct HashDefinition { + typedef void ParentType; + typedef std::pair KeyType; + typedef ThisType ValueType; + + size_t HashKey(const KeyType &key) const + { return Addressing::HashAddress(*key.first) ^ key.second; } + size_t Hash(ValueType *value) const + { return HashKey(std::make_pair(&value->Address(), + value->Interface()->index)); } + bool Compare(const KeyType &key, ValueType *value) const + { return value->Interface()->index == key.second + && value->Address().s_addr == key.first->s_addr; } + HashLink *GetLink(ValueType *value) const { return &value->fLink; } + }; + +private: + // for g++ 2.95 + friend class HashDefinition; + + Filter *fParent; AddressType fMulticastAddress; + net_interface *fInterface; FilterMode fFilterMode; - InterfaceList fInterfaces; - HashLink fHashLink; + AddressSet fAddresses; + HashLink fLink; }; template @@ -146,21 +174,22 @@ class MulticastFilter { public: typedef typename Addressing::AddressType AddressType; typedef typename Addressing::ProtocolType ProtocolType; - typedef MulticastGroupState GroupState; + typedef MulticastGroupInterface GroupInterface; MulticastFilter(ProtocolType *parent); ~MulticastFilter(); - ProtocolType *Parent() const { return fParent; } + ProtocolType *Socket() const { return fParent; } - GroupState *GetGroup(const AddressType &groupAddress, bool create); - void ReturnGroup(GroupState *group); + status_t GetState(const AddressType &groupAddress, + net_interface *interface, GroupInterface* &state, bool create); + void ReturnState(GroupInterface *state); private: - typedef typename GroupState::HashDefinition GroupHashDefinition; - typedef OpenHashTable States; + typedef typename GroupInterface::HashDefinition HashDefinition; + typedef OpenHashTable States; - void _ReturnGroup(GroupState *group); + void _ReturnState(GroupInterface *state); ProtocolType *fParent; States fStates; diff --git a/src/add-ons/kernel/network/stack/datalink.cpp b/src/add-ons/kernel/network/stack/datalink.cpp index 8de2541fda..cf17b44856 100644 --- a/src/add-ons/kernel/network/stack/datalink.cpp +++ b/src/add-ons/kernel/network/stack/datalink.cpp @@ -804,7 +804,7 @@ interface_protocol_join_multicast(net_datalink_protocol *_protocol, const sockaddr *address) { // TODO - return EINVAL; + return ENOTSUP; } @@ -813,7 +813,7 @@ interface_protocol_leave_multicast(net_datalink_protocol *_protocol, const sockaddr *address) { // TODO - return EINVAL; + return ENOTSUP; }