xref: /haiku/src/add-ons/kernel/network/protocols/ipv4/multicast.cpp (revision e277f0be5755a37e30f098deb6fb7542ac850a47)
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 	fFilterMode = kInclude;
65 	return B_OK;
66 }
67 
68 
69 template<typename Addressing> status_t
70 MulticastGroupInterface<Addressing>::BlockSource(
71 	const AddressType &sourceAddress)
72 {
73 	if (fFilterMode != kExclude)
74 		return EINVAL;
75 
76 	fAddresses.Add(sourceAddress);
77 	return B_OK;
78 }
79 
80 
81 template<typename Addressing> status_t
82 MulticastGroupInterface<Addressing>::UnblockSource(
83 	const AddressType &sourceAddress)
84 {
85 	if (fFilterMode != kExclude)
86 		return EINVAL;
87 
88 	if (!fAddresses.Has(sourceAddress))
89 		return EADDRNOTAVAIL;
90 
91 	fAddresses.Add(sourceAddress);
92 	return B_OK;
93 }
94 
95 
96 template<typename Addressing> status_t
97 MulticastGroupInterface<Addressing>::AddSSM(const AddressType &sourceAddress)
98 {
99 	if (fFilterMode == kExclude)
100 		return EINVAL;
101 
102 	fAddresses.Add(sourceAddress);
103 	return B_OK;
104 }
105 
106 
107 template<typename Addressing> status_t
108 MulticastGroupInterface<Addressing>::DropSSM(const AddressType &sourceAddress)
109 {
110 	if (fFilterMode == kExclude)
111 		return EINVAL;
112 
113 	if (!fAddresses.Has(sourceAddress))
114 		return EADDRNOTAVAIL;
115 
116 	fAddresses.Add(sourceAddress);
117 	return B_OK;
118 }
119 
120 
121 template<typename Addressing> bool
122 MulticastGroupInterface<Addressing>::IsEmpty() const
123 {
124 	return fFilterMode == kInclude && fAddresses.IsEmpty();
125 }
126 
127 
128 template<typename Addressing> void
129 MulticastGroupInterface<Addressing>::Clear()
130 {
131 	if (IsEmpty())
132 		return;
133 
134 	fFilterMode = kInclude;
135 	fAddresses.Clear();
136 	Addressing::LeaveGroup(this);
137 }
138 
139 
140 template<typename Addressing> bool
141 MulticastGroupInterface<Addressing>::FilterAccepts(net_buffer *buffer) const
142 {
143 	bool has = fAddresses.Has(Addressing::AddressFromSockAddr(
144 		buffer->source));
145 
146 	return (has && fFilterMode == kInclude)
147 		|| (!has && fFilterMode == kExclude);
148 }
149 
150 
151 template<typename Addressing>
152 MulticastFilter<Addressing>::MulticastFilter(ProtocolType *socket)
153 	: fParent(socket), fStates()
154 {
155 }
156 
157 
158 template<typename Addressing>
159 MulticastFilter<Addressing>::~MulticastFilter()
160 {
161 	while (true) {
162 		typename States::Iterator iterator = fStates.GetIterator();
163 		if (!iterator.HasNext())
164 			return;
165 
166 		GroupInterface *state = iterator.Next();
167 		state->Clear();
168 		_ReturnState(state);
169 	}
170 }
171 
172 
173 template<typename Addressing> status_t
174 MulticastFilter<Addressing>::GetState(const AddressType &groupAddress,
175 	net_interface *interface, GroupInterface* &state, bool create)
176 {
177 	state = fStates.Lookup(std::make_pair(&groupAddress, interface->index));
178 
179 	if (state == NULL && create) {
180 		state = new (nothrow) GroupInterface(this, groupAddress, interface);
181 		if (state == NULL)
182 			return B_NO_MEMORY;
183 
184 		status_t status = fStates.Insert(state);
185 		if (status < B_OK) {
186 			delete state;
187 			return status;
188 		}
189 
190 		status = Addressing::JoinGroup(state);
191 		if (status < B_OK) {
192 			fStates.Remove(state);
193 			delete state;
194 			return status;
195 		}
196 
197 	}
198 
199 	return B_OK;
200 }
201 
202 
203 template<typename Addressing> void
204 MulticastFilter<Addressing>::ReturnState(GroupInterface *state)
205 {
206 	if (state->IsEmpty())
207 		_ReturnState(state);
208 }
209 
210 
211 template<typename Addressing> void
212 MulticastFilter<Addressing>::_ReturnState(GroupInterface *state)
213 {
214 	fStates.Remove(state);
215 	delete state;
216 }
217 
218 // IPv4 explicit template instantiation
219 template class MulticastFilter<IPv4Multicast>;
220 template class MulticastGroupInterface<IPv4Multicast>;
221