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