xref: /haiku/src/add-ons/kernel/network/protocols/ipv4/multicast.cpp (revision 4fd62caa9acc437534c41bbb7d3fc9d53e915005)
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 
18 using std::nothrow;
19 
20 
21 static inline bool
22 operator==(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 
31 template<typename Addressing>
32 MulticastGroupInterface<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 
42 template<typename Addressing>
43 MulticastGroupInterface<Addressing>::~MulticastGroupInterface()
44 {
45 	Clear();
46 }
47 
48 
49 template<typename Addressing> status_t
50 MulticastGroupInterface<Addressing>::Add()
51 {
52 	if (fFilterMode == kInclude && !fAddresses.IsEmpty())
53 		return EINVAL;
54 
55 	fFilterMode = kExclude;
56 	return B_OK;
57 }
58 
59 
60 template<typename Addressing> status_t
61 MulticastGroupInterface<Addressing>::Drop()
62 {
63 	fAddresses.Clear();
64 	Addressing::LeaveGroup(this);
65 	fFilterMode = kInclude;
66 	return B_OK;
67 }
68 
69 
70 template<typename Addressing> status_t
71 MulticastGroupInterface<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 
82 template<typename Addressing> status_t
83 MulticastGroupInterface<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 
97 template<typename Addressing> status_t
98 MulticastGroupInterface<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 
108 template<typename Addressing> status_t
109 MulticastGroupInterface<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 
122 template<typename Addressing> bool
123 MulticastGroupInterface<Addressing>::IsEmpty() const
124 {
125 	return fFilterMode == kInclude && fAddresses.IsEmpty();
126 }
127 
128 
129 template<typename Addressing> void
130 MulticastGroupInterface<Addressing>::Clear()
131 {
132 	if (IsEmpty())
133 		return;
134 
135 	fFilterMode = kInclude;
136 	fAddresses.Clear();
137 	Addressing::LeaveGroup(this);
138 }
139 
140 
141 template<typename Addressing> bool
142 MulticastGroupInterface<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 
152 template<typename Addressing>
153 MulticastFilter<Addressing>::MulticastFilter(ProtocolType *socket)
154 	: fParent(socket), fStates()
155 {
156 }
157 
158 
159 template<typename Addressing>
160 MulticastFilter<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 
174 template<typename Addressing> status_t
175 MulticastFilter<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 	}
199 
200 	return B_OK;
201 }
202 
203 
204 template<typename Addressing> void
205 MulticastFilter<Addressing>::ReturnState(GroupInterface *state)
206 {
207 	if (state->IsEmpty())
208 		_ReturnState(state);
209 }
210 
211 
212 template<typename Addressing> void
213 MulticastFilter<Addressing>::_ReturnState(GroupInterface *state)
214 {
215 	fStates.Remove(state);
216 	delete state;
217 }
218 
219 // IPv4 explicit template instantiation
220 template class MulticastFilter<IPv4Multicast>;
221 template class MulticastGroupInterface<IPv4Multicast>;
222