146527f68SHugo Santos /*
261729d93SAxel Dörfler * Copyright 2007-2010, 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
1846527f68SHugo Santos using std::nothrow;
1946527f68SHugo Santos
2046527f68SHugo Santos
2161729d93SAxel Dörfler static inline bool
operator ==(const in_addr & a,const in_addr & b)2261729d93SAxel Dörfler operator==(const in_addr& a, const in_addr& b)
2361729d93SAxel Dörfler {
2461729d93SAxel Dörfler return a.s_addr == b.s_addr;
2561729d93SAxel Dörfler }
2661729d93SAxel Dörfler
2761729d93SAxel Dörfler
2861729d93SAxel Dörfler // #pragma mark -
2961729d93SAxel Dörfler
3061729d93SAxel Dörfler
316a606180SHugo Santos template<typename Addressing>
MulticastGroupInterface(Filter * parent,const AddressType & address,net_interface * interface)328aa4c7e3SHugo Santos MulticastGroupInterface<Addressing>::MulticastGroupInterface(Filter *parent,
338aa4c7e3SHugo Santos const AddressType &address, net_interface *interface)
3461729d93SAxel Dörfler :
3561729d93SAxel Dörfler fParent(parent),
3661729d93SAxel Dörfler fMulticastAddress(address),
3761729d93SAxel Dörfler fInterface(interface)
3846527f68SHugo Santos {
3946527f68SHugo Santos }
4046527f68SHugo Santos
4146527f68SHugo Santos
426a606180SHugo Santos template<typename Addressing>
~MulticastGroupInterface()438aa4c7e3SHugo Santos MulticastGroupInterface<Addressing>::~MulticastGroupInterface()
4446527f68SHugo Santos {
456a606180SHugo Santos Clear();
4646527f68SHugo Santos }
4746527f68SHugo Santos
4846527f68SHugo Santos
496a606180SHugo Santos template<typename Addressing> status_t
Add()508aa4c7e3SHugo Santos MulticastGroupInterface<Addressing>::Add()
5146527f68SHugo Santos {
528aa4c7e3SHugo Santos if (fFilterMode == kInclude && !fAddresses.IsEmpty())
5346527f68SHugo Santos return EINVAL;
5446527f68SHugo Santos
5546527f68SHugo Santos fFilterMode = kExclude;
5646527f68SHugo Santos return B_OK;
5746527f68SHugo Santos }
5846527f68SHugo Santos
5946527f68SHugo Santos
606a606180SHugo Santos template<typename Addressing> status_t
Drop()618aa4c7e3SHugo Santos MulticastGroupInterface<Addressing>::Drop()
628aa4c7e3SHugo Santos {
638aa4c7e3SHugo Santos fAddresses.Clear();
64fa2fa026SSiarzhuk Zharski Addressing::LeaveGroup(this);
658aa4c7e3SHugo Santos fFilterMode = kInclude;
668aa4c7e3SHugo Santos return B_OK;
678aa4c7e3SHugo Santos }
688aa4c7e3SHugo Santos
698aa4c7e3SHugo Santos
708aa4c7e3SHugo Santos template<typename Addressing> status_t
BlockSource(const AddressType & sourceAddress)718aa4c7e3SHugo Santos MulticastGroupInterface<Addressing>::BlockSource(
7246527f68SHugo Santos const AddressType &sourceAddress)
7346527f68SHugo Santos {
7446527f68SHugo Santos if (fFilterMode != kExclude)
7546527f68SHugo Santos return EINVAL;
7646527f68SHugo Santos
778aa4c7e3SHugo Santos fAddresses.Add(sourceAddress);
788aa4c7e3SHugo Santos return B_OK;
7946527f68SHugo Santos }
8046527f68SHugo Santos
8146527f68SHugo Santos
826a606180SHugo Santos template<typename Addressing> status_t
UnblockSource(const AddressType & sourceAddress)838aa4c7e3SHugo Santos MulticastGroupInterface<Addressing>::UnblockSource(
8446527f68SHugo Santos const AddressType &sourceAddress)
8546527f68SHugo Santos {
8646527f68SHugo Santos if (fFilterMode != kExclude)
8746527f68SHugo Santos return EINVAL;
8846527f68SHugo Santos
898aa4c7e3SHugo Santos if (!fAddresses.Has(sourceAddress))
9046527f68SHugo Santos return EADDRNOTAVAIL;
9146527f68SHugo Santos
928aa4c7e3SHugo Santos fAddresses.Add(sourceAddress);
938aa4c7e3SHugo Santos return B_OK;
9446527f68SHugo Santos }
9546527f68SHugo Santos
9646527f68SHugo Santos
978aa4c7e3SHugo Santos template<typename Addressing> status_t
AddSSM(const AddressType & sourceAddress)988aa4c7e3SHugo Santos MulticastGroupInterface<Addressing>::AddSSM(const AddressType &sourceAddress)
996a606180SHugo Santos {
1008aa4c7e3SHugo Santos if (fFilterMode == kExclude)
1018aa4c7e3SHugo Santos return EINVAL;
1028aa4c7e3SHugo Santos
1038aa4c7e3SHugo Santos fAddresses.Add(sourceAddress);
1048aa4c7e3SHugo Santos return B_OK;
1058aa4c7e3SHugo Santos }
1068aa4c7e3SHugo Santos
1078aa4c7e3SHugo Santos
1088aa4c7e3SHugo Santos template<typename Addressing> status_t
DropSSM(const AddressType & sourceAddress)1098aa4c7e3SHugo Santos MulticastGroupInterface<Addressing>::DropSSM(const AddressType &sourceAddress)
1108aa4c7e3SHugo Santos {
1118aa4c7e3SHugo Santos if (fFilterMode == kExclude)
1128aa4c7e3SHugo Santos return EINVAL;
1138aa4c7e3SHugo Santos
1148aa4c7e3SHugo Santos if (!fAddresses.Has(sourceAddress))
1158aa4c7e3SHugo Santos return EADDRNOTAVAIL;
1168aa4c7e3SHugo Santos
1178aa4c7e3SHugo Santos fAddresses.Add(sourceAddress);
1188aa4c7e3SHugo Santos return B_OK;
1196a606180SHugo Santos }
1206a606180SHugo Santos
1216a606180SHugo Santos
1226a606180SHugo Santos template<typename Addressing> bool
IsEmpty() const1238aa4c7e3SHugo Santos MulticastGroupInterface<Addressing>::IsEmpty() const
1246a606180SHugo Santos {
1258aa4c7e3SHugo Santos return fFilterMode == kInclude && fAddresses.IsEmpty();
12646527f68SHugo Santos }
12746527f68SHugo Santos
12846527f68SHugo Santos
1296a606180SHugo Santos template<typename Addressing> void
Clear()1308aa4c7e3SHugo Santos MulticastGroupInterface<Addressing>::Clear()
13146527f68SHugo Santos {
1328aa4c7e3SHugo Santos if (IsEmpty())
1338aa4c7e3SHugo Santos return;
1348aa4c7e3SHugo Santos
1358aa4c7e3SHugo Santos fFilterMode = kInclude;
1368aa4c7e3SHugo Santos fAddresses.Clear();
1378aa4c7e3SHugo Santos Addressing::LeaveGroup(this);
1388aa4c7e3SHugo Santos }
1398aa4c7e3SHugo Santos
1408aa4c7e3SHugo Santos
1418aa4c7e3SHugo Santos template<typename Addressing> bool
FilterAccepts(net_buffer * buffer) const1428aa4c7e3SHugo Santos MulticastGroupInterface<Addressing>::FilterAccepts(net_buffer *buffer) const
1438aa4c7e3SHugo Santos {
1448aa4c7e3SHugo Santos bool has = fAddresses.Has(Addressing::AddressFromSockAddr(
14579a0d252SHugo Santos buffer->source));
1468aa4c7e3SHugo Santos
1478aa4c7e3SHugo Santos return (has && fFilterMode == kInclude)
1488aa4c7e3SHugo Santos || (!has && fFilterMode == kExclude);
14946527f68SHugo Santos }
15046527f68SHugo Santos
15146527f68SHugo Santos
1526a606180SHugo Santos template<typename Addressing>
MulticastFilter(ProtocolType * socket)1530e30c21cSHugo Santos MulticastFilter<Addressing>::MulticastFilter(ProtocolType *socket)
154276aa463SIngo Weinhold : fParent(socket), fStates()
1556c501a40SHugo Santos {
1566c501a40SHugo Santos }
1576c501a40SHugo Santos
1586c501a40SHugo Santos
1596a606180SHugo Santos template<typename Addressing>
~MulticastFilter()1606a606180SHugo Santos MulticastFilter<Addressing>::~MulticastFilter()
16146527f68SHugo Santos {
16257967505SHugo Santos while (true) {
1634526eff1SHugo Santos typename States::Iterator iterator = fStates.GetIterator();
16457967505SHugo Santos if (!iterator.HasNext())
16557967505SHugo Santos return;
16657967505SHugo Santos
1678aa4c7e3SHugo Santos GroupInterface *state = iterator.Next();
1686a606180SHugo Santos state->Clear();
1698aa4c7e3SHugo Santos _ReturnState(state);
17046527f68SHugo Santos }
17146527f68SHugo Santos }
17246527f68SHugo Santos
17346527f68SHugo Santos
1748aa4c7e3SHugo Santos template<typename Addressing> status_t
GetState(const AddressType & groupAddress,net_interface * interface,GroupInterface * & state,bool create)1758aa4c7e3SHugo Santos MulticastFilter<Addressing>::GetState(const AddressType &groupAddress,
1768aa4c7e3SHugo Santos net_interface *interface, GroupInterface* &state, bool create)
17746527f68SHugo Santos {
1788aa4c7e3SHugo Santos state = fStates.Lookup(std::make_pair(&groupAddress, interface->index));
17946527f68SHugo Santos
1808aa4c7e3SHugo Santos if (state == NULL && create) {
1818aa4c7e3SHugo Santos state = new (nothrow) GroupInterface(this, groupAddress, interface);
1828aa4c7e3SHugo Santos if (state == NULL)
1838aa4c7e3SHugo Santos return B_NO_MEMORY;
1840e30c21cSHugo Santos
1858aa4c7e3SHugo Santos status_t status = fStates.Insert(state);
1868aa4c7e3SHugo Santos if (status < B_OK) {
1870e30c21cSHugo Santos delete state;
1888aa4c7e3SHugo Santos return status;
1890e30c21cSHugo Santos }
1900e30c21cSHugo Santos
1918aa4c7e3SHugo Santos status = Addressing::JoinGroup(state);
1928aa4c7e3SHugo Santos if (status < B_OK) {
1938aa4c7e3SHugo Santos fStates.Remove(state);
1948aa4c7e3SHugo Santos delete state;
1958aa4c7e3SHugo Santos return status;
1968aa4c7e3SHugo Santos }
1978aa4c7e3SHugo Santos
198*9e3513fcSJérôme Duval } else if (create)
199*9e3513fcSJérôme Duval return EADDRINUSE;
2008aa4c7e3SHugo Santos
2018aa4c7e3SHugo Santos return B_OK;
20246527f68SHugo Santos }
20346527f68SHugo Santos
20446527f68SHugo Santos
2056a606180SHugo Santos template<typename Addressing> void
ReturnState(GroupInterface * state)2068aa4c7e3SHugo Santos MulticastFilter<Addressing>::ReturnState(GroupInterface *state)
20746527f68SHugo Santos {
2088aa4c7e3SHugo Santos if (state->IsEmpty())
2098aa4c7e3SHugo Santos _ReturnState(state);
21057967505SHugo Santos }
21157967505SHugo Santos
21257967505SHugo Santos
21357967505SHugo Santos template<typename Addressing> void
_ReturnState(GroupInterface * state)2148aa4c7e3SHugo Santos MulticastFilter<Addressing>::_ReturnState(GroupInterface *state)
21557967505SHugo Santos {
2168aa4c7e3SHugo Santos fStates.Remove(state);
2178aa4c7e3SHugo Santos delete state;
21846527f68SHugo Santos }
21946527f68SHugo Santos
2204526eff1SHugo Santos // IPv4 explicit template instantiation
2214526eff1SHugo Santos template class MulticastFilter<IPv4Multicast>;
2228aa4c7e3SHugo Santos template class MulticastGroupInterface<IPv4Multicast>;
223