xref: /haiku/src/add-ons/kernel/network/protocols/ipv4/multicast.cpp (revision 79a0d25245275ef5f65afd610279dc9befffd65e)
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 
266a606180SHugo Santos template<typename Addressing>
278aa4c7e3SHugo Santos MulticastGroupInterface<Addressing>::MulticastGroupInterface(Filter *parent,
288aa4c7e3SHugo Santos 	const AddressType &address, net_interface *interface)
298aa4c7e3SHugo Santos 	: fParent(parent), fMulticastAddress(address), fInterface(interface)
3046527f68SHugo Santos {
3146527f68SHugo Santos }
3246527f68SHugo Santos 
3346527f68SHugo Santos 
346a606180SHugo Santos template<typename Addressing>
358aa4c7e3SHugo Santos MulticastGroupInterface<Addressing>::~MulticastGroupInterface()
3646527f68SHugo Santos {
376a606180SHugo Santos 	Clear();
3846527f68SHugo Santos }
3946527f68SHugo Santos 
4046527f68SHugo Santos 
416a606180SHugo Santos template<typename Addressing> status_t
428aa4c7e3SHugo Santos MulticastGroupInterface<Addressing>::Add()
4346527f68SHugo Santos {
448aa4c7e3SHugo Santos 	if (fFilterMode == kInclude && !fAddresses.IsEmpty())
4546527f68SHugo Santos 		return EINVAL;
4646527f68SHugo Santos 
4746527f68SHugo Santos 	fFilterMode = kExclude;
4846527f68SHugo Santos 	return B_OK;
4946527f68SHugo Santos }
5046527f68SHugo Santos 
5146527f68SHugo Santos 
526a606180SHugo Santos template<typename Addressing> status_t
538aa4c7e3SHugo Santos MulticastGroupInterface<Addressing>::Drop()
548aa4c7e3SHugo Santos {
558aa4c7e3SHugo Santos 	fAddresses.Clear();
568aa4c7e3SHugo Santos 	fFilterMode = kInclude;
578aa4c7e3SHugo Santos 	return B_OK;
588aa4c7e3SHugo Santos }
598aa4c7e3SHugo Santos 
608aa4c7e3SHugo Santos 
618aa4c7e3SHugo Santos template<typename Addressing> status_t
628aa4c7e3SHugo Santos MulticastGroupInterface<Addressing>::BlockSource(
6346527f68SHugo Santos 	const AddressType &sourceAddress)
6446527f68SHugo Santos {
6546527f68SHugo Santos 	if (fFilterMode != kExclude)
6646527f68SHugo Santos 		return EINVAL;
6746527f68SHugo Santos 
688aa4c7e3SHugo Santos 	fAddresses.Add(sourceAddress);
698aa4c7e3SHugo Santos 	return B_OK;
7046527f68SHugo Santos }
7146527f68SHugo Santos 
7246527f68SHugo Santos 
736a606180SHugo Santos template<typename Addressing> status_t
748aa4c7e3SHugo Santos MulticastGroupInterface<Addressing>::UnblockSource(
7546527f68SHugo Santos 	const AddressType &sourceAddress)
7646527f68SHugo Santos {
7746527f68SHugo Santos 	if (fFilterMode != kExclude)
7846527f68SHugo Santos 		return EINVAL;
7946527f68SHugo Santos 
808aa4c7e3SHugo Santos 	if (!fAddresses.Has(sourceAddress))
8146527f68SHugo Santos 		return EADDRNOTAVAIL;
8246527f68SHugo Santos 
838aa4c7e3SHugo Santos 	fAddresses.Add(sourceAddress);
848aa4c7e3SHugo Santos 	return B_OK;
8546527f68SHugo Santos }
8646527f68SHugo Santos 
8746527f68SHugo Santos 
888aa4c7e3SHugo Santos template<typename Addressing> status_t
898aa4c7e3SHugo Santos MulticastGroupInterface<Addressing>::AddSSM(const AddressType &sourceAddress)
906a606180SHugo Santos {
918aa4c7e3SHugo Santos 	if (fFilterMode == kExclude)
928aa4c7e3SHugo Santos 		return EINVAL;
938aa4c7e3SHugo Santos 
948aa4c7e3SHugo Santos 	fAddresses.Add(sourceAddress);
958aa4c7e3SHugo Santos 	return B_OK;
968aa4c7e3SHugo Santos }
978aa4c7e3SHugo Santos 
988aa4c7e3SHugo Santos 
998aa4c7e3SHugo Santos template<typename Addressing> status_t
1008aa4c7e3SHugo Santos MulticastGroupInterface<Addressing>::DropSSM(const AddressType &sourceAddress)
1018aa4c7e3SHugo Santos {
1028aa4c7e3SHugo Santos 	if (fFilterMode == kExclude)
1038aa4c7e3SHugo Santos 		return EINVAL;
1048aa4c7e3SHugo Santos 
1058aa4c7e3SHugo Santos 	if (!fAddresses.Has(sourceAddress))
1068aa4c7e3SHugo Santos 		return EADDRNOTAVAIL;
1078aa4c7e3SHugo Santos 
1088aa4c7e3SHugo Santos 	fAddresses.Add(sourceAddress);
1098aa4c7e3SHugo Santos 	return B_OK;
1106a606180SHugo Santos }
1116a606180SHugo Santos 
1126a606180SHugo Santos 
1136a606180SHugo Santos template<typename Addressing> bool
1148aa4c7e3SHugo Santos MulticastGroupInterface<Addressing>::IsEmpty() const
1156a606180SHugo Santos {
1168aa4c7e3SHugo Santos 	return fFilterMode == kInclude && fAddresses.IsEmpty();
11746527f68SHugo Santos }
11846527f68SHugo Santos 
11946527f68SHugo Santos 
1206a606180SHugo Santos template<typename Addressing> void
1218aa4c7e3SHugo Santos MulticastGroupInterface<Addressing>::Clear()
12246527f68SHugo Santos {
1238aa4c7e3SHugo Santos 	if (IsEmpty())
1248aa4c7e3SHugo Santos 		return;
1258aa4c7e3SHugo Santos 
1268aa4c7e3SHugo Santos 	fFilterMode = kInclude;
1278aa4c7e3SHugo Santos 	fAddresses.Clear();
1288aa4c7e3SHugo Santos 	Addressing::LeaveGroup(this);
1298aa4c7e3SHugo Santos }
1308aa4c7e3SHugo Santos 
1318aa4c7e3SHugo Santos 
1328aa4c7e3SHugo Santos template<typename Addressing> bool
1338aa4c7e3SHugo Santos MulticastGroupInterface<Addressing>::FilterAccepts(net_buffer *buffer) const
1348aa4c7e3SHugo Santos {
1358aa4c7e3SHugo Santos 	bool has = fAddresses.Has(Addressing::AddressFromSockAddr(
136*79a0d252SHugo Santos 		buffer->source));
1378aa4c7e3SHugo Santos 
1388aa4c7e3SHugo Santos 	return (has && fFilterMode == kInclude)
1398aa4c7e3SHugo Santos 		|| (!has && fFilterMode == kExclude);
14046527f68SHugo Santos }
14146527f68SHugo Santos 
14246527f68SHugo Santos 
1436a606180SHugo Santos template<typename Addressing>
1440e30c21cSHugo Santos MulticastFilter<Addressing>::MulticastFilter(ProtocolType *socket)
1450e30c21cSHugo Santos 	: fParent(socket), fStates((size_t)0)
1466c501a40SHugo Santos {
1476c501a40SHugo Santos }
1486c501a40SHugo Santos 
1496c501a40SHugo Santos 
1506a606180SHugo Santos template<typename Addressing>
1516a606180SHugo Santos MulticastFilter<Addressing>::~MulticastFilter()
15246527f68SHugo Santos {
15357967505SHugo Santos 	while (true) {
1544526eff1SHugo Santos 		typename States::Iterator iterator = fStates.GetIterator();
15557967505SHugo Santos 		if (!iterator.HasNext())
15657967505SHugo Santos 			return;
15757967505SHugo Santos 
1588aa4c7e3SHugo Santos 		GroupInterface *state = iterator.Next();
1596a606180SHugo Santos 		state->Clear();
1608aa4c7e3SHugo Santos 		_ReturnState(state);
16146527f68SHugo Santos 	}
16246527f68SHugo Santos }
16346527f68SHugo Santos 
16446527f68SHugo Santos 
1658aa4c7e3SHugo Santos template<typename Addressing> status_t
1668aa4c7e3SHugo Santos MulticastFilter<Addressing>::GetState(const AddressType &groupAddress,
1678aa4c7e3SHugo Santos 	net_interface *interface, GroupInterface* &state, bool create)
16846527f68SHugo Santos {
1698aa4c7e3SHugo Santos 	state = fStates.Lookup(std::make_pair(&groupAddress, interface->index));
17046527f68SHugo Santos 
1718aa4c7e3SHugo Santos 	if (state == NULL && create) {
1728aa4c7e3SHugo Santos 		state = new (nothrow) GroupInterface(this, groupAddress, interface);
1738aa4c7e3SHugo Santos 		if (state == NULL)
1748aa4c7e3SHugo Santos 			return B_NO_MEMORY;
1750e30c21cSHugo Santos 
1768aa4c7e3SHugo Santos 		status_t status = fStates.Insert(state);
1778aa4c7e3SHugo Santos 		if (status < B_OK) {
1780e30c21cSHugo Santos 			delete state;
1798aa4c7e3SHugo Santos 			return status;
1800e30c21cSHugo Santos 		}
1810e30c21cSHugo Santos 
1828aa4c7e3SHugo Santos 		status = Addressing::JoinGroup(state);
1838aa4c7e3SHugo Santos 		if (status < B_OK) {
1848aa4c7e3SHugo Santos 			fStates.Remove(state);
1858aa4c7e3SHugo Santos 			delete state;
1868aa4c7e3SHugo Santos 			return status;
1878aa4c7e3SHugo Santos 		}
1888aa4c7e3SHugo Santos 
1898aa4c7e3SHugo Santos 	}
1908aa4c7e3SHugo Santos 
1918aa4c7e3SHugo Santos 	return B_OK;
19246527f68SHugo Santos }
19346527f68SHugo Santos 
19446527f68SHugo Santos 
1956a606180SHugo Santos template<typename Addressing> void
1968aa4c7e3SHugo Santos MulticastFilter<Addressing>::ReturnState(GroupInterface *state)
19746527f68SHugo Santos {
1988aa4c7e3SHugo Santos 	if (state->IsEmpty())
1998aa4c7e3SHugo Santos 		_ReturnState(state);
20057967505SHugo Santos }
20157967505SHugo Santos 
20257967505SHugo Santos 
20357967505SHugo Santos template<typename Addressing> void
2048aa4c7e3SHugo Santos MulticastFilter<Addressing>::_ReturnState(GroupInterface *state)
20557967505SHugo Santos {
2068aa4c7e3SHugo Santos 	fStates.Remove(state);
2078aa4c7e3SHugo Santos 	delete state;
20846527f68SHugo Santos }
20946527f68SHugo Santos 
2104526eff1SHugo Santos // IPv4 explicit template instantiation
2114526eff1SHugo Santos template class MulticastFilter<IPv4Multicast>;
2128aa4c7e3SHugo Santos template class MulticastGroupInterface<IPv4Multicast>;
213