xref: /haiku/src/add-ons/kernel/network/protocols/ipv6/multicast.h (revision a127b88ecbfab58f64944c98aa47722a18e363b2)
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 
24 struct net_buffer;
25 struct net_protocol;
26 
27 
28 template<typename Addressing> class MulticastFilter;
29 template<typename Addressing> class MulticastGroupInterface;
30 
31 
32 struct 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 
48 template<typename AddressType>
49 class AddressSet {
50 	struct ContainedAddress : DoublyLinkedListLinkImpl<ContainedAddress> {
51 		AddressType address;
52 	};
53 
54 	typedef DoublyLinkedList<ContainedAddress> AddressList;
55 
56 public:
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 
114 private:
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 
131 template<typename Addressing>
132 class MulticastGroupInterface {
133 public:
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 
193 private:
194 	// for g++ 2.95
195 	friend struct 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 
207 template<typename Addressing>
208 class MulticastFilter {
209 public:
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 
223 private:
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