1/*
2 * Copyright 2007-2010, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *      Hugo Santos, hugosantos@gmail.com
7 */
8
9#include "multicast.h"
10
11#include <net_buffer.h>
12
13#include <netinet/in.h>
14
15#include <new>
16
17
18using std::nothrow;
19
20
21static inline bool
22operator==(const in_addr& a, const in_addr& b)
23{
24	return a.s_addr == b.s_addr;
25}
26
27
28// #pragma mark -
29
30
31template<typename Addressing>
32MulticastGroupInterface<Addressing>::MulticastGroupInterface(Filter *parent,
33	const AddressType &address, net_interface *interface)
34	:
35	fParent(parent),
36	fMulticastAddress(address),
37	fInterface(interface)
38{
39}
40
41
42template<typename Addressing>
43MulticastGroupInterface<Addressing>::~MulticastGroupInterface()
44{
45	Clear();
46}
47
48
49template<typename Addressing> status_t
50MulticastGroupInterface<Addressing>::Add()
51{
52	if (fFilterMode == kInclude && !fAddresses.IsEmpty())
53		return EINVAL;
54
55	fFilterMode = kExclude;
56	return B_OK;
57}
58
59
60template<typename Addressing> status_t
61MulticastGroupInterface<Addressing>::Drop()
62{
63	fAddresses.Clear();
64	Addressing::LeaveGroup(this);
65	fFilterMode = kInclude;
66	return B_OK;
67}
68
69
70template<typename Addressing> status_t
71MulticastGroupInterface<Addressing>::BlockSource(
72	const AddressType &sourceAddress)
73{
74	if (fFilterMode != kExclude)
75		return EINVAL;
76
77	fAddresses.Add(sourceAddress);
78	return B_OK;
79}
80
81
82template<typename Addressing> status_t
83MulticastGroupInterface<Addressing>::UnblockSource(
84	const AddressType &sourceAddress)
85{
86	if (fFilterMode != kExclude)
87		return EINVAL;
88
89	if (!fAddresses.Has(sourceAddress))
90		return EADDRNOTAVAIL;
91
92	fAddresses.Add(sourceAddress);
93	return B_OK;
94}
95
96
97template<typename Addressing> status_t
98MulticastGroupInterface<Addressing>::AddSSM(const AddressType &sourceAddress)
99{
100	if (fFilterMode == kExclude)
101		return EINVAL;
102
103	fAddresses.Add(sourceAddress);
104	return B_OK;
105}
106
107
108template<typename Addressing> status_t
109MulticastGroupInterface<Addressing>::DropSSM(const AddressType &sourceAddress)
110{
111	if (fFilterMode == kExclude)
112		return EINVAL;
113
114	if (!fAddresses.Has(sourceAddress))
115		return EADDRNOTAVAIL;
116
117	fAddresses.Add(sourceAddress);
118	return B_OK;
119}
120
121
122template<typename Addressing> bool
123MulticastGroupInterface<Addressing>::IsEmpty() const
124{
125	return fFilterMode == kInclude && fAddresses.IsEmpty();
126}
127
128
129template<typename Addressing> void
130MulticastGroupInterface<Addressing>::Clear()
131{
132	if (IsEmpty())
133		return;
134
135	fFilterMode = kInclude;
136	fAddresses.Clear();
137	Addressing::LeaveGroup(this);
138}
139
140
141template<typename Addressing> bool
142MulticastGroupInterface<Addressing>::FilterAccepts(net_buffer *buffer) const
143{
144	bool has = fAddresses.Has(Addressing::AddressFromSockAddr(
145		buffer->source));
146
147	return (has && fFilterMode == kInclude)
148		|| (!has && fFilterMode == kExclude);
149}
150
151
152template<typename Addressing>
153MulticastFilter<Addressing>::MulticastFilter(ProtocolType *socket)
154	: fParent(socket), fStates()
155{
156}
157
158
159template<typename Addressing>
160MulticastFilter<Addressing>::~MulticastFilter()
161{
162	while (true) {
163		typename States::Iterator iterator = fStates.GetIterator();
164		if (!iterator.HasNext())
165			return;
166
167		GroupInterface *state = iterator.Next();
168		state->Clear();
169		_ReturnState(state);
170	}
171}
172
173
174template<typename Addressing> status_t
175MulticastFilter<Addressing>::GetState(const AddressType &groupAddress,
176	net_interface *interface, GroupInterface* &state, bool create)
177{
178	state = fStates.Lookup(std::make_pair(&groupAddress, interface->index));
179
180	if (state == NULL && create) {
181		state = new (nothrow) GroupInterface(this, groupAddress, interface);
182		if (state == NULL)
183			return B_NO_MEMORY;
184
185		status_t status = fStates.Insert(state);
186		if (status < B_OK) {
187			delete state;
188			return status;
189		}
190
191		status = Addressing::JoinGroup(state);
192		if (status < B_OK) {
193			fStates.Remove(state);
194			delete state;
195			return status;
196		}
197
198	} else if (create)
199		return EADDRINUSE;
200
201	return B_OK;
202}
203
204
205template<typename Addressing> void
206MulticastFilter<Addressing>::ReturnState(GroupInterface *state)
207{
208	if (state->IsEmpty())
209		_ReturnState(state);
210}
211
212
213template<typename Addressing> void
214MulticastFilter<Addressing>::_ReturnState(GroupInterface *state)
215{
216	fStates.Remove(state);
217	delete state;
218}
219
220// IPv4 explicit template instantiation
221template class MulticastFilter<IPv4Multicast>;
222template class MulticastGroupInterface<IPv4Multicast>;
223