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