1/*
2 * Copyright 2010, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Atis Elsts, the.kfx@gmail.com
7 */
8#ifndef _IPV6_MULTICAST_H_
9#define _IPV6_MULTICAST_H_
10
11
12#include <util/DoublyLinkedList.h>
13#include <util/OpenHashTable.h>
14
15#include <net_datalink.h>
16
17#include <netinet6/in6.h>
18
19#include <utility>
20
21#include "jenkins.h"
22
23
24struct net_buffer;
25struct net_protocol;
26
27
28template<typename Addressing> class MulticastFilter;
29template<typename Addressing> class MulticastGroupInterface;
30
31
32struct IPv6Multicast {
33	typedef struct in6_addr AddressType;
34	typedef struct ipv6_protocol ProtocolType;
35	typedef MulticastGroupInterface<IPv6Multicast> GroupInterface;
36
37	static status_t JoinGroup(GroupInterface *);
38	static status_t LeaveGroup(GroupInterface *);
39
40	static const in6_addr &AddressFromSockAddr(const sockaddr *sockaddr)
41		{ return ((const sockaddr_in6 *)sockaddr)->sin6_addr; }
42	static size_t HashAddress(const in6_addr &address)
43		{ return jenkins_hashword((const uint32*)&address,
44				sizeof(in6_addr) / sizeof(uint32), 0); }
45};
46
47
48template<typename AddressType>
49class AddressSet {
50	struct ContainedAddress : DoublyLinkedListLinkImpl<ContainedAddress> {
51		AddressType address;
52	};
53
54	typedef DoublyLinkedList<ContainedAddress> AddressList;
55
56public:
57	AddressSet()
58		: fCount(0) {}
59
60	~AddressSet() { Clear(); }
61
62	status_t Add(const AddressType &address)
63	{
64		if (Has(address))
65			return B_OK;
66
67		ContainedAddress *container = new ContainedAddress();
68		if (container == NULL)
69			return B_NO_MEMORY;
70
71		container->address = address;
72		fAddresses.Add(container);
73
74		return B_OK;
75	}
76
77	void Remove(const AddressType &address)
78	{
79		ContainedAddress *container = _Get(address);
80		if (container == NULL)
81			return;
82
83		fAddresses.Remove(container);
84		delete container;
85	}
86
87	bool Has(const AddressType &address) const
88	{
89		return _Get(address) != NULL;
90	}
91
92	bool IsEmpty() const { return fAddresses.IsEmpty(); }
93
94	void Clear()
95	{
96		while (!fAddresses.IsEmpty())
97			Remove(fAddresses.Head()->address);
98	}
99
100	class Iterator {
101	public:
102		Iterator(const AddressList &addresses)
103			: fBaseIterator(addresses.GetIterator()) {}
104
105		bool HasNext() const { return fBaseIterator.HasNext(); }
106		AddressType &Next() { return fBaseIterator.Next()->address; }
107
108	private:
109		typename AddressList::ConstIterator fBaseIterator;
110	};
111
112	Iterator GetIterator() const { return Iterator(fAddresses); }
113
114private:
115	ContainedAddress *_Get(const AddressType &address) const
116	{
117		typename AddressList::ConstIterator it = fAddresses.GetIterator();
118		while (it.HasNext()) {
119			ContainedAddress *container = it.Next();
120			if (container->address == address)
121				return container;
122		}
123		return NULL;
124	}
125
126	AddressList fAddresses;
127	int fCount;
128};
129
130
131template<typename Addressing>
132class MulticastGroupInterface {
133public:
134	typedef MulticastGroupInterface<Addressing> ThisType;
135	typedef typename Addressing::AddressType AddressType;
136	typedef MulticastFilter<Addressing> Filter;
137	typedef ::AddressSet<AddressType> AddressSet;
138
139	enum FilterMode {
140		kInclude,
141		kExclude
142	};
143
144	MulticastGroupInterface(Filter *parent, const AddressType &address,
145		net_interface *interface);
146	~MulticastGroupInterface();
147
148	Filter *Parent() const { return fParent; }
149
150	const AddressType &Address() const { return fMulticastAddress; }
151	net_interface *Interface() const { return fInterface; }
152
153	status_t Add();
154	status_t Drop();
155	status_t BlockSource(const AddressType &sourceAddress);
156	status_t UnblockSource(const AddressType &sourceAddress);
157	status_t AddSSM(const AddressType &sourceAddress);
158	status_t DropSSM(const AddressType &sourceAddress);
159
160	bool IsEmpty() const;
161	void Clear();
162
163	FilterMode Mode() const { return fFilterMode; }
164	const AddressSet &Sources() const { return fAddresses; }
165
166	bool FilterAccepts(net_buffer *buffer) const;
167
168	struct HashDefinition {
169		typedef std::pair<const AddressType *, uint32> KeyType;
170		typedef ThisType ValueType;
171
172		size_t HashKey(const KeyType &key) const
173			{
174				size_t result = 0;
175				result = jenkins_hashword((const uint32*)key.first,
176					sizeof(in6_addr) / sizeof(uint32), result);
177				result = jenkins_hashword(&key.second, 1, result);
178				return result;
179			}
180		size_t Hash(ValueType *value) const
181			{ return HashKey(std::make_pair(&value->Address(),
182				value->Interface()->index)); }
183		bool Compare(const KeyType &key, ValueType *value) const
184			{ return value->Interface()->index == key.second
185				&& value->Address() == *key.first; }
186		MulticastGroupInterface*& GetLink(ValueType *value) const
187			{ return value->HashLink(); }
188	};
189
190	MulticastGroupInterface*& HashLink() { return fLink; }
191	MulticastGroupInterface*& MulticastGroupsHashLink() { return fMulticastGroupsLink; }
192
193private:
194	// for g++ 2.95
195	friend class HashDefinition;
196
197	Filter *fParent;
198	AddressType fMulticastAddress;
199	net_interface *fInterface;
200	FilterMode fFilterMode;
201	AddressSet fAddresses;
202	MulticastGroupInterface* fLink;
203	MulticastGroupInterface* fMulticastGroupsLink;
204};
205
206
207template<typename Addressing>
208class MulticastFilter {
209public:
210	typedef typename Addressing::AddressType AddressType;
211	typedef typename Addressing::ProtocolType ProtocolType;
212	typedef MulticastGroupInterface<Addressing> GroupInterface;
213
214	MulticastFilter(ProtocolType *parent);
215	~MulticastFilter();
216
217	ProtocolType *Socket() const { return fParent; }
218
219	status_t GetState(const AddressType &groupAddress,
220		net_interface *interface, GroupInterface* &state, bool create);
221	void ReturnState(GroupInterface *state);
222
223private:
224	typedef typename GroupInterface::HashDefinition HashDefinition;
225	typedef BOpenHashTable<HashDefinition> States;
226
227	void _ReturnState(GroupInterface *state);
228
229	ProtocolType *fParent;
230	States fStates;
231};
232
233
234#endif	// _IPV6_MULTICAST_H_
235