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