xref: /haiku/src/add-ons/kernel/network/protocols/ipv6/multicast.h (revision 83b1a68c52ba3e0e8796282759f694b7fdddf06d)
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 
192 private:
193 	// for g++ 2.95
194 	friend class HashDefinition;
195 
196 	Filter *fParent;
197 	AddressType fMulticastAddress;
198 	net_interface *fInterface;
199 	FilterMode fFilterMode;
200 	AddressSet fAddresses;
201 	MulticastGroupInterface* fLink;
202 };
203 
204 
205 template<typename Addressing>
206 class MulticastFilter {
207 public:
208 	typedef typename Addressing::AddressType AddressType;
209 	typedef typename Addressing::ProtocolType ProtocolType;
210 	typedef MulticastGroupInterface<Addressing> GroupInterface;
211 
212 	MulticastFilter(ProtocolType *parent);
213 	~MulticastFilter();
214 
215 	ProtocolType *Socket() const { return fParent; }
216 
217 	status_t GetState(const AddressType &groupAddress,
218 		net_interface *interface, GroupInterface* &state, bool create);
219 	void ReturnState(GroupInterface *state);
220 
221 private:
222 	typedef typename GroupInterface::HashDefinition HashDefinition;
223 	typedef BOpenHashTable<HashDefinition> States;
224 
225 	void _ReturnState(GroupInterface *state);
226 
227 	ProtocolType *fParent;
228 	States fStates;
229 };
230 
231 
232 #endif	// _IPV6_MULTICAST_H_
233