From d3be4145727574faf2834aab6d3c85a2edfc8c4b Mon Sep 17 00:00:00 2001 From: Hugo Santos Date: Sun, 15 Apr 2007 04:02:02 +0000 Subject: [PATCH] initial IPv4 multicast receive path. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20692 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../kernel/network/protocols/ipv4/ipv4.cpp | 143 ++++++++++++++++-- 1 file changed, 127 insertions(+), 16 deletions(-) diff --git a/src/add-ons/kernel/network/protocols/ipv4/ipv4.cpp b/src/add-ons/kernel/network/protocols/ipv4/ipv4.cpp index 6811f0dc6e..eadc6fc259 100644 --- a/src/add-ons/kernel/network/protocols/ipv4/ipv4.cpp +++ b/src/add-ons/kernel/network/protocols/ipv4/ipv4.cpp @@ -115,13 +115,30 @@ class FragmentPacket { net_timer fTimer; }; -typedef DoublyLinkedList RawSocketList; +class MulticastGroup { +public: + MulticastGroup(const in_addr &address); + + status_t Deliver(net_buffer *buffer); + + static uint32 Hash(void *address, const void *key, uint32 range); + static int Compare(void *address, const void *key); + static int32 NextOffset() { return offsetof(MulticastGroup, fNext); } + + static const int kMaxGroups = 64; + +private: + MulticastGroup *fNext; + in_addr fMulticastAddress; +}; class RawSocket : public DoublyLinkedListLinkImpl, public DatagramSocket<> { public: RawSocket(net_socket *socket); }; +typedef DoublyLinkedList RawSocketList; + struct ipv4_protocol : net_protocol { ipv4_protocol(net_socket *socket) : multicast_filter(socket) {} @@ -151,6 +168,8 @@ static RawSocketList sRawSockets; static benaphore sRawSocketsLock; static benaphore sFragmentLock; static hash_table *sFragmentHash; +static benaphore sMulticastGroupsLock; +static hash_table *sMulticastGroups; static net_protocol_module_info *sReceivingProtocol[256]; static benaphore sReceivingProtocolLock; @@ -393,6 +412,46 @@ FragmentPacket::StaleTimer(struct net_timer *timer, void *data) } +MulticastGroup::MulticastGroup(const in_addr &address) + : fMulticastAddress(address) +{ +} + + +status_t +MulticastGroup::Deliver(net_buffer *buffer) +{ + return B_ERROR; +} + + +int +MulticastGroup::Compare(void *_group, const void *_key) +{ + MulticastGroup *group = (MulticastGroup *)_group; + + return memcmp(&group->fMulticastAddress, _key, sizeof(in_addr)); +} + + +uint32 +MulticastGroup::Hash(void *_group, const void *_key, uint32 range) +{ + const in_addr *address = (const in_addr *)_key; + if (_group != NULL) + address = &((MulticastGroup *)_group)->fMulticastAddress; + + union { + in_addr_t address; + uint8 data[4]; + } addr; + + addr.address = address->s_addr & IN_CLASSD_HOST; + + return (addr.data[0] ^ addr.data[1] ^ addr.data[2] ^ addr.data[3]) % range; +} + + // #pragma mark - @@ -604,6 +663,22 @@ raw_receive_data(net_buffer *buffer) } +static status_t +deliver_multicast(net_buffer *buffer) +{ + BenaphoreLocker _(sMulticastGroupsLock); + + MulticastGroup *group = (MulticastGroup *)hash_lookup(sMulticastGroups, + &buffer->destination); + if (group == NULL) + return B_OK; + + // RAW sockets will be registered just like any other + + return group->Deliver(buffer); +} + + static net_protocol_module_info * receiving_protocol(uint8 protocol) { @@ -1252,15 +1327,27 @@ ipv4_receive_data(net_buffer *buffer) destination.sin_family = AF_INET; destination.sin_addr.s_addr = header.destination; - // test if the packet is really for us - uint32 matchedAddressType; - if (!sDatalinkModule->is_local_address(sDomain, (sockaddr*)&destination, - &buffer->interface, &matchedAddressType)) { - TRACE(" ReceiveData(): packet was not for us %lx -> %lx", - ntohl(header.source), ntohl(header.destination)); - return B_ERROR; - } - if (matchedAddressType != 0) { + // lower layers notion of Broadcast or Multicast have no relevance to us + buffer->flags &= ~(MSG_BCAST | MSG_MCAST); + + if (header.destination == INADDR_BROADCAST) { + buffer->flags |= MSG_BCAST; + // TODO set incoming interface. we should have some notion from which + // device interface this buffer is coming from. + buffer->interface = NULL; + } else if (IN_MULTICAST(header.destination)) { + buffer->flags |= MSG_MCAST; + buffer->interface = NULL; + } else { + uint32 matchedAddressType = 0; + // test if the packet is really for us + if (!sDatalinkModule->is_local_address(sDomain, (sockaddr*)&destination, + &buffer->interface, &matchedAddressType)) { + TRACE(" ReceiveData(): packet was not for us %lx -> %lx", + ntohl(header.source), ntohl(header.destination)); + return B_ERROR; + } + // copy over special address types (MSG_BCAST or MSG_MCAST): buffer->flags |= matchedAddressType; } @@ -1290,6 +1377,14 @@ ipv4_receive_data(net_buffer *buffer) } } + if (buffer->flags & MSG_MCAST) { + // Unfortunely historical reasons dictate that the IP multicast + // model be a little different from the unicast one. We deliver + // this frame directly to all sockets registered with interest + // for this multicast group. + return deliver_multicast(buffer); + } + // Since the buffer might have been changed (reassembled fragment) // we must no longer access bufferHeader or header anymore after // this point @@ -1341,14 +1436,24 @@ init_ipv4() if (status < B_OK) goto err1; - status = benaphore_init(&sReceivingProtocolLock, "IPv4 receiving protocols"); + status = benaphore_init(&sMulticastGroupsLock, "IPv4 multicast groups"); if (status < B_OK) goto err2; + status = benaphore_init(&sReceivingProtocolLock, "IPv4 receiving protocols"); + if (status < B_OK) + goto err3; + + sMulticastGroups = hash_init(MulticastGroup::kMaxGroups, + MulticastGroup::NextOffset(), &MulticastGroup::Compare, + &MulticastGroup::Hash); + if (sMulticastGroups == NULL) + goto err4; + sFragmentHash = hash_init(MAX_HASH_FRAGMENTS, FragmentPacket::NextOffset(), &FragmentPacket::Compare, &FragmentPacket::Hash); if (sFragmentHash == NULL) - goto err3; + goto err5; new (&sRawSockets) RawSocketList; // static initializers do not work in the kernel, @@ -1358,19 +1463,23 @@ init_ipv4() status = gStackModule->register_domain_protocols(AF_INET, SOCK_RAW, 0, "network/protocols/ipv4/v1", NULL); if (status < B_OK) - goto err4; + goto err6; status = gStackModule->register_domain(AF_INET, "internet", &gIPv4Module, &gIPv4AddressModule, &sDomain); if (status < B_OK) - goto err4; + goto err6; return B_OK; -err4: +err6: hash_uninit(sFragmentHash); -err3: +err5: + hash_uninit(sMulticastGroups); +err4: benaphore_destroy(&sReceivingProtocolLock); +err3: + benaphore_destroy(&sMulticastGroupsLock); err2: benaphore_destroy(&sFragmentLock); err1: @@ -1393,8 +1502,10 @@ uninit_ipv4() gStackModule->unregister_domain(sDomain); benaphore_unlock(&sReceivingProtocolLock); + hash_uninit(sMulticastGroups); hash_uninit(sFragmentHash); + benaphore_destroy(&sMulticastGroupsLock); benaphore_destroy(&sFragmentLock); benaphore_destroy(&sRawSocketsLock); benaphore_destroy(&sReceivingProtocolLock);