146527f68SHugo Santos /* 246527f68SHugo Santos * Copyright 2007, Haiku, Inc. All Rights Reserved. 346527f68SHugo Santos * Distributed under the terms of the MIT License. 446527f68SHugo Santos * 546527f68SHugo Santos * Authors: 646527f68SHugo Santos * Hugo Santos, hugosantos@gmail.com 746527f68SHugo Santos */ 846527f68SHugo Santos 946527f68SHugo Santos #include "multicast.h" 1046527f68SHugo Santos 116a606180SHugo Santos #include <net_buffer.h> 126a606180SHugo Santos 1346527f68SHugo Santos #include <netinet/in.h> 1446527f68SHugo Santos 1546527f68SHugo Santos #include <new> 1646527f68SHugo Santos 1746527f68SHugo Santos static inline bool 1846527f68SHugo Santos operator==(const in_addr &a1, const in_addr &a2) 1946527f68SHugo Santos { 2046527f68SHugo Santos return a1.s_addr == a2.s_addr; 2146527f68SHugo Santos } 2246527f68SHugo Santos 2346527f68SHugo Santos using std::nothrow; 2446527f68SHugo Santos 2546527f68SHugo Santos 2646527f68SHugo Santos template<typename AddressType> 2746527f68SHugo Santos MulticastGroupInterfaceState<AddressType>::MulticastGroupInterfaceState( 2846527f68SHugo Santos net_interface *interface) 2946527f68SHugo Santos : fInterface(interface) 3046527f68SHugo Santos { 3146527f68SHugo Santos } 3246527f68SHugo Santos 3346527f68SHugo Santos 3446527f68SHugo Santos template<typename AddressType> 3546527f68SHugo Santos MulticastGroupInterfaceState<AddressType>::~MulticastGroupInterfaceState() 3646527f68SHugo Santos { 374526eff1SHugo Santos typename SourceList::Iterator iterator = fSources.GetIterator(); 3846527f68SHugo Santos while (iterator.HasNext()) { 3946527f68SHugo Santos _Remove(iterator.Next()); 4046527f68SHugo Santos } 4146527f68SHugo Santos } 4246527f68SHugo Santos 4346527f68SHugo Santos 4446527f68SHugo Santos template<typename AddressType> status_t 4546527f68SHugo Santos MulticastGroupInterfaceState<AddressType>::Add(const AddressType &address) 4646527f68SHugo Santos { 4746527f68SHugo Santos return _Get(address, true) ? B_OK : ENOBUFS; 4846527f68SHugo Santos } 4946527f68SHugo Santos 5046527f68SHugo Santos 5146527f68SHugo Santos template<typename AddressType> status_t 5246527f68SHugo Santos MulticastGroupInterfaceState<AddressType>::Remove(const AddressType &address) 5346527f68SHugo Santos { 5446527f68SHugo Santos Source *state = _Get(address, false); 5546527f68SHugo Santos if (state == NULL) 5646527f68SHugo Santos return EADDRNOTAVAIL; 5746527f68SHugo Santos 5846527f68SHugo Santos _Remove(state); 5946527f68SHugo Santos return B_OK; 6046527f68SHugo Santos } 6146527f68SHugo Santos 6246527f68SHugo Santos 634526eff1SHugo Santos template<typename AddressType> typename MulticastGroupInterfaceState<AddressType>::Source * 6446527f68SHugo Santos MulticastGroupInterfaceState<AddressType>::_Get(const AddressType &address, 6546527f68SHugo Santos bool create) 6646527f68SHugo Santos { 674526eff1SHugo Santos typename SourceList::Iterator iterator = fSources.GetIterator(); 6846527f68SHugo Santos while (iterator.HasNext()) { 6946527f68SHugo Santos Source *state = iterator.Next(); 7046527f68SHugo Santos if (state->address == address) 7146527f68SHugo Santos return state; 7246527f68SHugo Santos } 7346527f68SHugo Santos 7446527f68SHugo Santos if (!create) 7546527f68SHugo Santos return false; 7646527f68SHugo Santos 7746527f68SHugo Santos Source *state = new (nothrow) Source; 7846527f68SHugo Santos if (state) { 7946527f68SHugo Santos state->address = address; 8046527f68SHugo Santos fSources.Add(state); 8146527f68SHugo Santos } 8246527f68SHugo Santos 8346527f68SHugo Santos return state; 8446527f68SHugo Santos } 8546527f68SHugo Santos 8646527f68SHugo Santos 8746527f68SHugo Santos template<typename AddressType> void 8846527f68SHugo Santos MulticastGroupInterfaceState<AddressType>::_Remove(Source *state) 8946527f68SHugo Santos { 9046527f68SHugo Santos fSources.Remove(state); 9146527f68SHugo Santos delete state; 9246527f68SHugo Santos } 9346527f68SHugo Santos 9446527f68SHugo Santos 956a606180SHugo Santos template<typename Addressing> 960e30c21cSHugo Santos MulticastGroupState<Addressing>::MulticastGroupState(ProtocolType *socket, 976a606180SHugo Santos const AddressType &address) 986a606180SHugo Santos : fSocket(socket), fMulticastAddress(address), fFilterMode(kInclude) 9946527f68SHugo Santos { 10046527f68SHugo Santos } 10146527f68SHugo Santos 10246527f68SHugo Santos 1036a606180SHugo Santos template<typename Addressing> 1046a606180SHugo Santos MulticastGroupState<Addressing>::~MulticastGroupState() 10546527f68SHugo Santos { 1066a606180SHugo Santos Clear(); 10746527f68SHugo Santos } 10846527f68SHugo Santos 10946527f68SHugo Santos 1106a606180SHugo Santos template<typename Addressing> status_t 1116a606180SHugo Santos MulticastGroupState<Addressing>::Add(net_interface *interface) 11246527f68SHugo Santos { 11346527f68SHugo Santos if (fFilterMode == kInclude && !fInterfaces.IsEmpty()) 11446527f68SHugo Santos return EINVAL; 11546527f68SHugo Santos 11646527f68SHugo Santos fFilterMode = kExclude; 11746527f68SHugo Santos 11846527f68SHugo Santos return _GetInterface(interface, true) != NULL ? B_OK : ENOBUFS; 11946527f68SHugo Santos } 12046527f68SHugo Santos 12146527f68SHugo Santos 1226a606180SHugo Santos template<typename Addressing> status_t 1236a606180SHugo Santos MulticastGroupState<Addressing>::Drop(net_interface *interface) 12446527f68SHugo Santos { 12546527f68SHugo Santos InterfaceState *state = _GetInterface(interface, false); 12646527f68SHugo Santos if (state == NULL) 12746527f68SHugo Santos return EADDRNOTAVAIL; 12846527f68SHugo Santos 12946527f68SHugo Santos _RemoveInterface(state); 13046527f68SHugo Santos 13146527f68SHugo Santos if (fInterfaces.IsEmpty()) 13246527f68SHugo Santos fFilterMode = kInclude; 13346527f68SHugo Santos 13446527f68SHugo Santos return B_OK; 13546527f68SHugo Santos } 13646527f68SHugo Santos 13746527f68SHugo Santos 1386a606180SHugo Santos template<typename Addressing> status_t 1396a606180SHugo Santos MulticastGroupState<Addressing>::BlockSource(net_interface *interface, 14046527f68SHugo Santos const AddressType &sourceAddress) 14146527f68SHugo Santos { 14246527f68SHugo Santos if (fFilterMode != kExclude) 14346527f68SHugo Santos return EINVAL; 14446527f68SHugo Santos 14546527f68SHugo Santos InterfaceState *state = _GetInterface(interface, false); 14646527f68SHugo Santos if (state == NULL) 14746527f68SHugo Santos return EINVAL; 14846527f68SHugo Santos 14946527f68SHugo Santos return state->Add(sourceAddress); 15046527f68SHugo Santos } 15146527f68SHugo Santos 15246527f68SHugo Santos 1536a606180SHugo Santos template<typename Addressing> status_t 1546a606180SHugo Santos MulticastGroupState<Addressing>::UnblockSource(net_interface *interface, 15546527f68SHugo Santos const AddressType &sourceAddress) 15646527f68SHugo Santos { 15746527f68SHugo Santos if (fFilterMode != kExclude) 15846527f68SHugo Santos return EINVAL; 15946527f68SHugo Santos 16046527f68SHugo Santos InterfaceState *state = _GetInterface(interface, false); 16146527f68SHugo Santos if (state == NULL) 16246527f68SHugo Santos return EINVAL; 16346527f68SHugo Santos 16446527f68SHugo Santos return state->Remove(sourceAddress); 16546527f68SHugo Santos } 16646527f68SHugo Santos 1676a606180SHugo Santos template<typename Addressing> status_t 1686a606180SHugo Santos MulticastGroupState<Addressing>::AddSSM(net_interface *interface, 16946527f68SHugo Santos const AddressType &sourceAddress) 17046527f68SHugo Santos { 17146527f68SHugo Santos if (fFilterMode == kExclude) 17246527f68SHugo Santos return EINVAL; 17346527f68SHugo Santos 17446527f68SHugo Santos InterfaceState *state = _GetInterface(interface, true); 17546527f68SHugo Santos if (state == NULL) 17646527f68SHugo Santos return ENOBUFS; 17746527f68SHugo Santos 17846527f68SHugo Santos return state->Add(sourceAddress); 17946527f68SHugo Santos } 18046527f68SHugo Santos 18146527f68SHugo Santos 1826a606180SHugo Santos template<typename Addressing> status_t 1836a606180SHugo Santos MulticastGroupState<Addressing>::DropSSM(net_interface *interface, 18446527f68SHugo Santos const AddressType &sourceAddress) 18546527f68SHugo Santos { 18646527f68SHugo Santos if (fFilterMode == kExclude) 18746527f68SHugo Santos return EINVAL; 18846527f68SHugo Santos 18946527f68SHugo Santos InterfaceState *state = _GetInterface(interface, false); 19046527f68SHugo Santos if (state == NULL) 19146527f68SHugo Santos return EADDRNOTAVAIL; 19246527f68SHugo Santos 19346527f68SHugo Santos return state->Remove(sourceAddress); 19446527f68SHugo Santos } 19546527f68SHugo Santos 19646527f68SHugo Santos 1976a606180SHugo Santos template<typename Addressing> void 1986a606180SHugo Santos MulticastGroupState<Addressing>::Clear() 1996a606180SHugo Santos { 2004526eff1SHugo Santos typename InterfaceList::Iterator iterator = fInterfaces.GetIterator(); 2016a606180SHugo Santos while (iterator.HasNext()) 2026a606180SHugo Santos _RemoveInterface(iterator.Next()); 2036a606180SHugo Santos } 2046a606180SHugo Santos 2056a606180SHugo Santos 2066a606180SHugo Santos template<typename Addressing> bool 2076a606180SHugo Santos MulticastGroupState<Addressing>::FilterAccepts(net_buffer *buffer) 2086a606180SHugo Santos { 2096a606180SHugo Santos InterfaceState *state = _GetInterface(buffer->interface, false); 2106a606180SHugo Santos if (state == NULL) 2116a606180SHugo Santos return false; 2126a606180SHugo Santos 2130e30c21cSHugo Santos bool has = state->Contains(Addressing::AddressFromSockAddr( 2146a606180SHugo Santos (sockaddr *)&buffer->source)); 2156a606180SHugo Santos 2166a606180SHugo Santos return (has && fFilterMode == kInclude) || (!has && fFilterMode == kExclude); 2176a606180SHugo Santos } 2186a606180SHugo Santos 2196a606180SHugo Santos 2204526eff1SHugo Santos template<typename Addressing> typename MulticastGroupState<Addressing>::InterfaceState * 2216a606180SHugo Santos MulticastGroupState<Addressing>::_GetInterface(net_interface *interface, 22246527f68SHugo Santos bool create) 22346527f68SHugo Santos { 2244526eff1SHugo Santos typename InterfaceList::Iterator iterator = fInterfaces.GetIterator(); 22546527f68SHugo Santos while (iterator.HasNext()) { 22646527f68SHugo Santos InterfaceState *state = iterator.Next(); 22746527f68SHugo Santos if (state->Interface() == interface) 22846527f68SHugo Santos return state; 22946527f68SHugo Santos } 23046527f68SHugo Santos 23146527f68SHugo Santos if (!create) 23246527f68SHugo Santos return false; 23346527f68SHugo Santos 23446527f68SHugo Santos InterfaceState *state = new (nothrow) InterfaceState(interface); 23546527f68SHugo Santos if (state) 23646527f68SHugo Santos fInterfaces.Add(state); 23746527f68SHugo Santos 23846527f68SHugo Santos return state; 23946527f68SHugo Santos } 24046527f68SHugo Santos 24146527f68SHugo Santos 2426a606180SHugo Santos template<typename Addressing> void 2436a606180SHugo Santos MulticastGroupState<Addressing>::_RemoveInterface(InterfaceState *state) 24446527f68SHugo Santos { 24546527f68SHugo Santos fInterfaces.Remove(state); 24646527f68SHugo Santos delete state; 24746527f68SHugo Santos } 24846527f68SHugo Santos 24946527f68SHugo Santos 2506a606180SHugo Santos template<typename Addressing> 2510e30c21cSHugo Santos MulticastFilter<Addressing>::MulticastFilter(ProtocolType *socket) 2520e30c21cSHugo Santos : fParent(socket), fStates((size_t)0) 2536c501a40SHugo Santos { 2546c501a40SHugo Santos } 2556c501a40SHugo Santos 2566c501a40SHugo Santos 2576a606180SHugo Santos template<typename Addressing> 2586a606180SHugo Santos MulticastFilter<Addressing>::~MulticastFilter() 25946527f68SHugo Santos { 260*57967505SHugo Santos while (true) { 2614526eff1SHugo Santos typename States::Iterator iterator = fStates.GetIterator(); 262*57967505SHugo Santos if (!iterator.HasNext()) 263*57967505SHugo Santos return; 264*57967505SHugo Santos 26546527f68SHugo Santos GroupState *state = iterator.Next(); 2666a606180SHugo Santos state->Clear(); 267*57967505SHugo Santos _ReturnGroup(state); 26846527f68SHugo Santos } 26946527f68SHugo Santos } 27046527f68SHugo Santos 27146527f68SHugo Santos 2724526eff1SHugo Santos template<typename Addressing> typename MulticastFilter<Addressing>::GroupState * 2736a606180SHugo Santos MulticastFilter<Addressing>::GetGroup(const AddressType &groupAddress, 27446527f68SHugo Santos bool create) 27546527f68SHugo Santos { 2760e30c21cSHugo Santos GroupState *state = fStates.Lookup(groupAddress); 2770e30c21cSHugo Santos if (state) 27846527f68SHugo Santos return state; 27946527f68SHugo Santos 2800e30c21cSHugo Santos if (create) { 2810e30c21cSHugo Santos state = new (nothrow) GroupState(fParent, groupAddress); 2826a606180SHugo Santos if (state) { 2830e30c21cSHugo Santos if (fStates.Insert(state) >= B_OK) { 2840e30c21cSHugo Santos if (Addressing::JoinGroup(state) >= B_OK) 28546527f68SHugo Santos return state; 2860e30c21cSHugo Santos 2870e30c21cSHugo Santos fStates.Remove(state); 2880e30c21cSHugo Santos } 2890e30c21cSHugo Santos 2900e30c21cSHugo Santos delete state; 2910e30c21cSHugo Santos } 2920e30c21cSHugo Santos } 2930e30c21cSHugo Santos 2940e30c21cSHugo Santos return NULL; 29546527f68SHugo Santos } 29646527f68SHugo Santos 29746527f68SHugo Santos 2986a606180SHugo Santos template<typename Addressing> void 2996a606180SHugo Santos MulticastFilter<Addressing>::ReturnGroup(GroupState *group) 30046527f68SHugo Santos { 301*57967505SHugo Santos if (group->IsEmpty()) 302*57967505SHugo Santos _ReturnGroup(group); 303*57967505SHugo Santos } 304*57967505SHugo Santos 305*57967505SHugo Santos 306*57967505SHugo Santos template<typename Addressing> void 307*57967505SHugo Santos MulticastFilter<Addressing>::_ReturnGroup(GroupState *group) 308*57967505SHugo Santos { 3090e30c21cSHugo Santos Addressing::LeaveGroup(group); 31046527f68SHugo Santos fStates.Remove(group); 31146527f68SHugo Santos delete group; 31246527f68SHugo Santos } 31346527f68SHugo Santos 3144526eff1SHugo Santos // IPv4 explicit template instantiation 3154526eff1SHugo Santos template class MulticastFilter<IPv4Multicast>; 3164526eff1SHugo Santos template class MulticastGroupState<IPv4Multicast>; 3174526eff1SHugo Santos template class MulticastGroupInterfaceState<in_addr>; 318