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 #ifndef _IPV6_MULTICAST_H_ 9 #define _IPV6_MULTICAST_H_ 10 11 12 #include <util/DoublyLinkedList.h> 13 #include <util/OpenHashTable.h> 14 15 #include <net_datalink.h> 16 17 #include <netinet6/in6.h> 18 19 #include <utility> 20 21 #include "jenkins.h" 22 23 24 struct net_buffer; 25 struct net_protocol; 26 27 28 template<typename Addressing> class MulticastFilter; 29 template<typename Addressing> class MulticastGroupInterface; 30 31 32 struct IPv6Multicast { 33 typedef struct in6_addr AddressType; 34 typedef struct ipv6_protocol ProtocolType; 35 typedef MulticastGroupInterface<IPv6Multicast> GroupInterface; 36 37 static status_t JoinGroup(GroupInterface *); 38 static status_t LeaveGroup(GroupInterface *); 39 40 static const in6_addr &AddressFromSockAddr(const sockaddr *sockaddr) 41 { return ((const sockaddr_in6 *)sockaddr)->sin6_addr; } 42 static size_t HashAddress(const in6_addr &address) 43 { return jenkins_hashword((const uint32*)&address, 44 sizeof(in6_addr) / sizeof(uint32), 0); } 45 }; 46 47 48 template<typename AddressType> 49 class AddressSet { 50 struct ContainedAddress : DoublyLinkedListLinkImpl<ContainedAddress> { 51 AddressType address; 52 }; 53 54 typedef DoublyLinkedList<ContainedAddress> AddressList; 55 56 public: 57 AddressSet() 58 : fCount(0) {} 59 60 ~AddressSet() { Clear(); } 61 62 status_t Add(const AddressType &address) 63 { 64 if (Has(address)) 65 return B_OK; 66 67 ContainedAddress *container = new ContainedAddress(); 68 if (container == NULL) 69 return B_NO_MEMORY; 70 71 container->address = address; 72 fAddresses.Add(container); 73 74 return B_OK; 75 } 76 77 void Remove(const AddressType &address) 78 { 79 ContainedAddress *container = _Get(address); 80 if (container == NULL) 81 return; 82 83 fAddresses.Remove(container); 84 delete container; 85 } 86 87 bool Has(const AddressType &address) const 88 { 89 return _Get(address) != NULL; 90 } 91 92 bool IsEmpty() const { return fAddresses.IsEmpty(); } 93 94 void Clear() 95 { 96 while (!fAddresses.IsEmpty()) 97 Remove(fAddresses.Head()->address); 98 } 99 100 class Iterator { 101 public: 102 Iterator(const AddressList &addresses) 103 : fBaseIterator(addresses.GetIterator()) {} 104 105 bool HasNext() const { return fBaseIterator.HasNext(); } 106 AddressType &Next() { return fBaseIterator.Next()->address; } 107 108 private: 109 typename AddressList::ConstIterator fBaseIterator; 110 }; 111 112 Iterator GetIterator() const { return Iterator(fAddresses); } 113 114 private: 115 ContainedAddress *_Get(const AddressType &address) const 116 { 117 typename AddressList::ConstIterator it = fAddresses.GetIterator(); 118 while (it.HasNext()) { 119 ContainedAddress *container = it.Next(); 120 if (container->address == address) 121 return container; 122 } 123 return NULL; 124 } 125 126 AddressList fAddresses; 127 int fCount; 128 }; 129 130 131 template<typename Addressing> 132 class MulticastGroupInterface { 133 public: 134 typedef MulticastGroupInterface<Addressing> ThisType; 135 typedef typename Addressing::AddressType AddressType; 136 typedef MulticastFilter<Addressing> Filter; 137 typedef ::AddressSet<AddressType> AddressSet; 138 139 enum FilterMode { 140 kInclude, 141 kExclude 142 }; 143 144 MulticastGroupInterface(Filter *parent, const AddressType &address, 145 net_interface *interface); 146 ~MulticastGroupInterface(); 147 148 Filter *Parent() const { return fParent; } 149 150 const AddressType &Address() const { return fMulticastAddress; } 151 net_interface *Interface() const { return fInterface; } 152 153 status_t Add(); 154 status_t Drop(); 155 status_t BlockSource(const AddressType &sourceAddress); 156 status_t UnblockSource(const AddressType &sourceAddress); 157 status_t AddSSM(const AddressType &sourceAddress); 158 status_t DropSSM(const AddressType &sourceAddress); 159 160 bool IsEmpty() const; 161 void Clear(); 162 163 FilterMode Mode() const { return fFilterMode; } 164 const AddressSet &Sources() const { return fAddresses; } 165 166 bool FilterAccepts(net_buffer *buffer) const; 167 168 struct HashDefinition { 169 typedef std::pair<const AddressType *, uint32> KeyType; 170 typedef ThisType ValueType; 171 172 size_t HashKey(const KeyType &key) const 173 { 174 size_t result = 0; 175 result = jenkins_hashword((const uint32*)key.first, 176 sizeof(in6_addr) / sizeof(uint32), result); 177 result = jenkins_hashword(&key.second, 1, result); 178 return result; 179 } 180 size_t Hash(ValueType *value) const 181 { return HashKey(std::make_pair(&value->Address(), 182 value->Interface()->index)); } 183 bool Compare(const KeyType &key, ValueType *value) const 184 { return value->Interface()->index == key.second 185 && value->Address() == *key.first; } 186 MulticastGroupInterface*& GetLink(ValueType *value) const 187 { return value->HashLink(); } 188 }; 189 190 MulticastGroupInterface*& HashLink() { return fLink; } 191 MulticastGroupInterface*& MulticastGroupsHashLink() { return fMulticastGroupsLink; } 192 193 private: 194 // for g++ 2.95 195 friend struct HashDefinition; 196 197 Filter *fParent; 198 AddressType fMulticastAddress; 199 net_interface *fInterface; 200 FilterMode fFilterMode; 201 AddressSet fAddresses; 202 MulticastGroupInterface* fLink; 203 MulticastGroupInterface* fMulticastGroupsLink; 204 }; 205 206 207 template<typename Addressing> 208 class MulticastFilter { 209 public: 210 typedef typename Addressing::AddressType AddressType; 211 typedef typename Addressing::ProtocolType ProtocolType; 212 typedef MulticastGroupInterface<Addressing> GroupInterface; 213 214 MulticastFilter(ProtocolType *parent); 215 ~MulticastFilter(); 216 217 ProtocolType *Socket() const { return fParent; } 218 219 status_t GetState(const AddressType &groupAddress, 220 net_interface *interface, GroupInterface* &state, bool create); 221 void ReturnState(GroupInterface *state); 222 223 private: 224 typedef typename GroupInterface::HashDefinition HashDefinition; 225 typedef BOpenHashTable<HashDefinition> States; 226 227 void _ReturnState(GroupInterface *state); 228 229 ProtocolType *fParent; 230 States fStates; 231 }; 232 233 234 #endif // _IPV6_MULTICAST_H_ 235