xref: /haiku/src/add-ons/kernel/network/protocols/ipv4/multicast.h (revision 8465a069104e40de35a4a56225b26ca5ba5c74f9)
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 #ifndef _PRIVATE_MULTICAST_H_
1046527f68SHugo Santos #define _PRIVATE_MULTICAST_H_
1146527f68SHugo Santos 
1246527f68SHugo Santos #include <util/DoublyLinkedList.h>
130e30c21cSHugo Santos #include <util/OpenHashTable.h>
1446527f68SHugo Santos 
158aa4c7e3SHugo Santos #include <net_datalink.h>
168aa4c7e3SHugo Santos 
176a606180SHugo Santos #include <netinet/in.h>
186c501a40SHugo Santos 
198aa4c7e3SHugo Santos #include <utility>
208aa4c7e3SHugo Santos 
216a606180SHugo Santos struct net_buffer;
226a606180SHugo Santos struct net_protocol;
236a606180SHugo Santos 
246a606180SHugo Santos // This code is template'ized as it is reusable for IPv6
256a606180SHugo Santos 
266a606180SHugo Santos template<typename Addressing> class MulticastFilter;
278aa4c7e3SHugo Santos template<typename Addressing> class MulticastGroupInterface;
286a606180SHugo Santos 
296a606180SHugo Santos // TODO move this elsewhere...
306a606180SHugo Santos struct IPv4Multicast {
316a606180SHugo Santos 	typedef struct in_addr AddressType;
320e30c21cSHugo Santos 	typedef struct ipv4_protocol ProtocolType;
338aa4c7e3SHugo Santos 	typedef MulticastGroupInterface<IPv4Multicast> GroupInterface;
346a606180SHugo Santos 
358aa4c7e3SHugo Santos 	static status_t JoinGroup(GroupInterface *);
368aa4c7e3SHugo Santos 	static status_t LeaveGroup(GroupInterface *);
376a606180SHugo Santos 
380e30c21cSHugo Santos 	static const in_addr &AddressFromSockAddr(const sockaddr *sockaddr)
390e30c21cSHugo Santos 		{ return ((const sockaddr_in *)sockaddr)->sin_addr; }
400e30c21cSHugo Santos 	static size_t HashAddress(const in_addr &address)
410e30c21cSHugo Santos 		{ return address.s_addr; }
426a606180SHugo Santos };
4346527f68SHugo Santos 
4446527f68SHugo Santos template<typename AddressType>
458aa4c7e3SHugo Santos class AddressSet {
468aa4c7e3SHugo Santos public:
478aa4c7e3SHugo Santos 	struct ContainedAddress : DoublyLinkedListLinkImpl<ContainedAddress> {
4846527f68SHugo Santos 		AddressType address;
4946527f68SHugo Santos 	};
5046527f68SHugo Santos 
518aa4c7e3SHugo Santos 	~AddressSet() { Clear(); }
5246527f68SHugo Santos 
538aa4c7e3SHugo Santos 	status_t Add(const AddressType &address)
548aa4c7e3SHugo Santos 	{
558aa4c7e3SHugo Santos 		if (Has(address))
568aa4c7e3SHugo Santos 			return B_OK;
5746527f68SHugo Santos 
588aa4c7e3SHugo Santos 		ContainedAddress *container = new ContainedAddress();
598aa4c7e3SHugo Santos 		if (container == NULL)
608aa4c7e3SHugo Santos 			return B_NO_MEMORY;
6146527f68SHugo Santos 
628aa4c7e3SHugo Santos 		container->address = address;
638aa4c7e3SHugo Santos 		fAddresses.Add(container);
648aa4c7e3SHugo Santos 
658aa4c7e3SHugo Santos 		return B_OK;
668aa4c7e3SHugo Santos 	}
678aa4c7e3SHugo Santos 
688aa4c7e3SHugo Santos 	void Remove(const AddressType &address)
698aa4c7e3SHugo Santos 	{
708aa4c7e3SHugo Santos 		ContainedAddress *container = _Get(address);
718aa4c7e3SHugo Santos 		if (container == NULL)
728aa4c7e3SHugo Santos 			return;
738aa4c7e3SHugo Santos 
748aa4c7e3SHugo Santos 		fAddresses.Remove(container);
758aa4c7e3SHugo Santos 		delete container;
768aa4c7e3SHugo Santos 	}
778aa4c7e3SHugo Santos 
788aa4c7e3SHugo Santos 	bool Has(const AddressType &address) const
798aa4c7e3SHugo Santos 	{
808aa4c7e3SHugo Santos 		return _Get(address) != NULL;
818aa4c7e3SHugo Santos 	}
828aa4c7e3SHugo Santos 
838aa4c7e3SHugo Santos 	bool IsEmpty() const { return fAddresses.IsEmpty(); }
848aa4c7e3SHugo Santos 
858aa4c7e3SHugo Santos 	void Clear()
868aa4c7e3SHugo Santos 	{
878aa4c7e3SHugo Santos 		while (!fAddresses.IsEmpty())
888aa4c7e3SHugo Santos 			Remove(fAddresses.Head()->address);
898aa4c7e3SHugo Santos 	}
906a606180SHugo Santos 
9146527f68SHugo Santos private:
928aa4c7e3SHugo Santos 	typedef DoublyLinkedList<ContainedAddress> AddressList;
9346527f68SHugo Santos 
948aa4c7e3SHugo Santos 	ContainedAddress *_Get(const AddressType &address) const
958aa4c7e3SHugo Santos 	{
96*8465a069SHugo Santos 		typename AddressList::ConstIterator it = fAddresses.GetIterator();
978aa4c7e3SHugo Santos 		while (it.HasNext()) {
988aa4c7e3SHugo Santos 			ContainedAddress *container = it.Next();
998aa4c7e3SHugo Santos 			if (container->address == address)
1008aa4c7e3SHugo Santos 				return container;
1018aa4c7e3SHugo Santos 		}
1028aa4c7e3SHugo Santos 		return NULL;
1038aa4c7e3SHugo Santos 	}
10446527f68SHugo Santos 
1058aa4c7e3SHugo Santos 	AddressList fAddresses;
10646527f68SHugo Santos };
10746527f68SHugo Santos 
1088aa4c7e3SHugo Santos 
1096a606180SHugo Santos template<typename Addressing>
1108aa4c7e3SHugo Santos class MulticastGroupInterface
1118aa4c7e3SHugo Santos 	: public HashTableLink< MulticastGroupInterface<Addressing> > {
11246527f68SHugo Santos public:
1138aa4c7e3SHugo Santos 	typedef MulticastGroupInterface<Addressing> ThisType;
1140e30c21cSHugo Santos 	typedef HashTableLink<ThisType> HashLink;
1156a606180SHugo Santos 	typedef typename Addressing::AddressType AddressType;
1168aa4c7e3SHugo Santos 	typedef MulticastFilter<Addressing> Filter;
11746527f68SHugo Santos 
11846527f68SHugo Santos 	enum FilterMode {
11946527f68SHugo Santos 		kInclude,
12046527f68SHugo Santos 		kExclude
12146527f68SHugo Santos 	};
12246527f68SHugo Santos 
1238aa4c7e3SHugo Santos 	MulticastGroupInterface(Filter *parent, const AddressType &address,
1248aa4c7e3SHugo Santos 		net_interface *interface);
1258aa4c7e3SHugo Santos 	~MulticastGroupInterface();
1268aa4c7e3SHugo Santos 
1278aa4c7e3SHugo Santos 	Filter *Parent() const { return fParent; }
1288aa4c7e3SHugo Santos 
1298aa4c7e3SHugo Santos 	const AddressType &Address() const { return fMulticastAddress; }
1308aa4c7e3SHugo Santos 	net_interface *Interface() const { return fInterface; }
1318aa4c7e3SHugo Santos 
1328aa4c7e3SHugo Santos 	status_t Add();
1338aa4c7e3SHugo Santos 	status_t Drop();
1348aa4c7e3SHugo Santos 	status_t BlockSource(const AddressType &sourceAddress);
1358aa4c7e3SHugo Santos 	status_t UnblockSource(const AddressType &sourceAddress);
1368aa4c7e3SHugo Santos 	status_t AddSSM(const AddressType &sourceAddress);
1378aa4c7e3SHugo Santos 	status_t DropSSM(const AddressType &sourceAddress);
1388aa4c7e3SHugo Santos 
1398aa4c7e3SHugo Santos 	bool IsEmpty() const;
1408aa4c7e3SHugo Santos 	void Clear();
1418aa4c7e3SHugo Santos 
1428aa4c7e3SHugo Santos 	bool FilterAccepts(net_buffer *buffer) const;
1438aa4c7e3SHugo Santos 
1448aa4c7e3SHugo Santos 	struct HashDefinition {
1458aa4c7e3SHugo Santos 		typedef void ParentType;
1468aa4c7e3SHugo Santos 		typedef std::pair<const AddressType *, uint32> KeyType;
1478aa4c7e3SHugo Santos 		typedef ThisType ValueType;
1488aa4c7e3SHugo Santos 
1498aa4c7e3SHugo Santos 		size_t HashKey(const KeyType &key) const
1508aa4c7e3SHugo Santos 			{ return Addressing::HashAddress(*key.first) ^ key.second; }
1518aa4c7e3SHugo Santos 		size_t Hash(ValueType *value) const
1528aa4c7e3SHugo Santos 			{ return HashKey(std::make_pair(&value->Address(),
1538aa4c7e3SHugo Santos 				value->Interface()->index)); }
1548aa4c7e3SHugo Santos 		bool Compare(const KeyType &key, ValueType *value) const
1558aa4c7e3SHugo Santos 			{ return value->Interface()->index == key.second
1568aa4c7e3SHugo Santos 				&& value->Address().s_addr == key.first->s_addr; }
1578aa4c7e3SHugo Santos 		HashLink  *GetLink(ValueType *value) const { return &value->fLink; }
1588aa4c7e3SHugo Santos 	};
1598aa4c7e3SHugo Santos 
1608aa4c7e3SHugo Santos private:
1618aa4c7e3SHugo Santos 	// for g++ 2.95
1628aa4c7e3SHugo Santos 	friend class HashDefinition;
1638aa4c7e3SHugo Santos 
1648aa4c7e3SHugo Santos 	Filter *fParent;
16546527f68SHugo Santos 	AddressType fMulticastAddress;
1668aa4c7e3SHugo Santos 	net_interface *fInterface;
16746527f68SHugo Santos 	FilterMode fFilterMode;
1688aa4c7e3SHugo Santos 	AddressSet<AddressType> fAddresses;
1698aa4c7e3SHugo Santos 	HashLink fLink;
17046527f68SHugo Santos };
17146527f68SHugo Santos 
1726a606180SHugo Santos template<typename Addressing>
17346527f68SHugo Santos class MulticastFilter {
17446527f68SHugo Santos public:
1756a606180SHugo Santos 	typedef typename Addressing::AddressType AddressType;
1760e30c21cSHugo Santos 	typedef typename Addressing::ProtocolType ProtocolType;
1778aa4c7e3SHugo Santos 	typedef MulticastGroupInterface<Addressing> GroupInterface;
17846527f68SHugo Santos 
1790e30c21cSHugo Santos 	MulticastFilter(ProtocolType *parent);
18046527f68SHugo Santos 	~MulticastFilter();
18146527f68SHugo Santos 
1828aa4c7e3SHugo Santos 	ProtocolType *Socket() const { return fParent; }
1836c501a40SHugo Santos 
1848aa4c7e3SHugo Santos 	status_t GetState(const AddressType &groupAddress,
1858aa4c7e3SHugo Santos 		net_interface *interface, GroupInterface* &state, bool create);
1868aa4c7e3SHugo Santos 	void ReturnState(GroupInterface *state);
18746527f68SHugo Santos 
18846527f68SHugo Santos private:
1898aa4c7e3SHugo Santos 	typedef typename GroupInterface::HashDefinition HashDefinition;
1908aa4c7e3SHugo Santos 	typedef OpenHashTable<HashDefinition> States;
19146527f68SHugo Santos 
1928aa4c7e3SHugo Santos 	void _ReturnState(GroupInterface *state);
19357967505SHugo Santos 
1940e30c21cSHugo Santos 	ProtocolType *fParent;
19546527f68SHugo Santos 	States fStates;
19646527f68SHugo Santos };
19746527f68SHugo Santos 
19846527f68SHugo Santos #endif
199