xref: /haiku/src/add-ons/kernel/network/protocols/ipv4/multicast.cpp (revision 57967505c2947a442e0a1185ab7a3930786787cc)
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