xref: /haiku/src/add-ons/kernel/network/protocols/ipv4/multicast.cpp (revision fa2fa02613347204e0e1aa2e588f5e4a4d19d108)
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
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>
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>
438aa4c7e3SHugo Santos MulticastGroupInterface<Addressing>::~MulticastGroupInterface()
4446527f68SHugo Santos {
456a606180SHugo Santos 	Clear();
4646527f68SHugo Santos }
4746527f68SHugo Santos 
4846527f68SHugo Santos 
496a606180SHugo Santos template<typename Addressing> status_t
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
618aa4c7e3SHugo Santos MulticastGroupInterface<Addressing>::Drop()
628aa4c7e3SHugo Santos {
638aa4c7e3SHugo Santos 	fAddresses.Clear();
64*fa2fa026SSiarzhuk 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
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
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
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
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
1238aa4c7e3SHugo 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
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
1428aa4c7e3SHugo 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>
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>
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
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 
1988aa4c7e3SHugo Santos 	}
1998aa4c7e3SHugo Santos 
2008aa4c7e3SHugo Santos 	return B_OK;
20146527f68SHugo Santos }
20246527f68SHugo Santos 
20346527f68SHugo Santos 
2046a606180SHugo Santos template<typename Addressing> void
2058aa4c7e3SHugo Santos MulticastFilter<Addressing>::ReturnState(GroupInterface *state)
20646527f68SHugo Santos {
2078aa4c7e3SHugo Santos 	if (state->IsEmpty())
2088aa4c7e3SHugo Santos 		_ReturnState(state);
20957967505SHugo Santos }
21057967505SHugo Santos 
21157967505SHugo Santos 
21257967505SHugo Santos template<typename Addressing> void
2138aa4c7e3SHugo Santos MulticastFilter<Addressing>::_ReturnState(GroupInterface *state)
21457967505SHugo Santos {
2158aa4c7e3SHugo Santos 	fStates.Remove(state);
2168aa4c7e3SHugo Santos 	delete state;
21746527f68SHugo Santos }
21846527f68SHugo Santos 
2194526eff1SHugo Santos // IPv4 explicit template instantiation
2204526eff1SHugo Santos template class MulticastFilter<IPv4Multicast>;
2218aa4c7e3SHugo Santos template class MulticastGroupInterface<IPv4Multicast>;
222