From 9d4331902caac05ca23bc6f4d27342acce15f202 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Thu, 26 Aug 2010 09:23:49 +0000 Subject: [PATCH] * Now we should also support link layer and INADDR_BROADCAST broadcasts again correctly. * This should finally fix ticket #6454, but I keep it open until it's confirmed. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@38365 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../kernel/network/protocols/ipv4/ipv4.cpp | 31 ++++--- .../kernel/network/protocols/udp/udp.cpp | 89 +++++++++++-------- 2 files changed, 66 insertions(+), 54 deletions(-) diff --git a/src/add-ons/kernel/network/protocols/ipv4/ipv4.cpp b/src/add-ons/kernel/network/protocols/ipv4/ipv4.cpp index 7aaa57cefc..9262ef9a6a 100644 --- a/src/add-ons/kernel/network/protocols/ipv4/ipv4.cpp +++ b/src/add-ons/kernel/network/protocols/ipv4/ipv4.cpp @@ -1581,6 +1581,7 @@ ipv4_receive_data(net_buffer* buffer) // lower layers notion of broadcast or multicast have no relevance to us // other than deciding whether to send an ICMP error bool wasMulticast = (buffer->flags & (MSG_BCAST | MSG_MCAST)) != 0; + bool notForUs = false; buffer->flags &= ~(MSG_BCAST | MSG_MCAST); sockaddr_in destination; @@ -1590,29 +1591,33 @@ ipv4_receive_data(net_buffer* buffer) buffer->flags |= MSG_BCAST; // Find first interface with a matching family - // TODO: support for ethernet broadcasts! - // TODO: we might need to send it to all interfaces if it's an ethernet - // broadcast as well! - sDatalinkModule->is_local_link_address(sDomain, true, - buffer->destination, &buffer->interface_address); + if (!sDatalinkModule->is_local_link_address(sDomain, true, + buffer->destination, &buffer->interface_address)) + notForUs = wasMulticast; } else if (IN_MULTICAST(ntohl(header.destination))) { buffer->flags |= MSG_MCAST; - // TODO: must set buffer->interface_address! } else { uint32 matchedAddressType = 0; // test if the packet is really for us if (!sDatalinkModule->is_local_address(sDomain, (sockaddr*)&destination, - &buffer->interface_address, &matchedAddressType)) { - sDatalinkModule->is_local_link_address(sDomain, true, - buffer->destination, &buffer->interface_address); + &buffer->interface_address, &matchedAddressType) + && !sDatalinkModule->is_local_link_address(sDomain, true, + buffer->destination, &buffer->interface_address)) { + notForUs = true; } else { // copy over special address types (MSG_BCAST or MSG_MCAST): buffer->flags |= matchedAddressType; } } - if (buffer->interface_address == NULL) { + // set net_buffer's source/destination address + fill_sockaddr_in((struct sockaddr_in*)buffer->source, header.source); + memcpy(buffer->destination, &destination, sizeof(sockaddr_in)); + + buffer->protocol = header.protocol; + + if (notForUs) { TRACE(" ipv4_receive_data(): packet was not for us %x -> %x", ntohl(header.source), ntohl(header.destination)); @@ -1625,12 +1630,6 @@ ipv4_receive_data(net_buffer* buffer) return B_ERROR; } - // set net_buffer's source/destination address - fill_sockaddr_in((struct sockaddr_in*)buffer->source, header.source); - memcpy(buffer->destination, &destination, sizeof(sockaddr_in)); - - buffer->protocol = header.protocol; - // remove any trailing/padding data status_t status = gBufferModule->trim(buffer, packetLength); if (status != B_OK) diff --git a/src/add-ons/kernel/network/protocols/udp/udp.cpp b/src/add-ons/kernel/network/protocols/udp/udp.cpp index f78a5f7ea4..374c8378ac 100644 --- a/src/add-ons/kernel/network/protocols/udp/udp.cpp +++ b/src/add-ons/kernel/network/protocols/udp/udp.cpp @@ -234,8 +234,10 @@ public: static int DumpEndpoints(int argc, char *argv[]); private: - UdpDomainSupport* _GetDomain(net_domain *domain, bool create); - UdpDomainSupport* _GetDomain(net_buffer* buffer); + inline net_domain* _GetDomain(net_buffer* buffer); + UdpDomainSupport* _GetDomainSupport(net_domain* domain, + bool create); + UdpDomainSupport* _GetDomainSupport(net_buffer* buffer); mutex fLock; status_t fStatus; @@ -504,23 +506,21 @@ UdpDomainSupport::_FindActiveEndpoint(const sockaddr *ourAddress, status_t -UdpDomainSupport::_DemuxBroadcast(net_buffer *buffer) +UdpDomainSupport::_DemuxBroadcast(net_buffer* buffer) { - sockaddr *peerAddr = buffer->source; - sockaddr *broadcastAddr = buffer->destination; - sockaddr *mask = NULL; - if (buffer->interface_address != NULL) - mask = (sockaddr *)buffer->interface_address->mask; - - TRACE_DOMAIN("_DemuxBroadcast(%p)", buffer); - + sockaddr* peerAddr = buffer->source; + sockaddr* broadcastAddr = buffer->destination; uint16 incomingPort = AddressModule()->get_port(broadcastAddr); - EndpointTable::Iterator it = fActiveEndpoints.GetIterator(); + sockaddr* mask = NULL; + if (buffer->interface_address != NULL) + mask = (sockaddr*)buffer->interface_address->mask; - while (it.HasNext()) { - UdpEndpoint *endpoint = it.Next(); + TRACE_DOMAIN("_DemuxBroadcast(%p): mask %p\n", buffer, mask); + EndpointTable::Iterator iterator = fActiveEndpoints.GetIterator(); + + while (UdpEndpoint* endpoint = iterator.Next()) { TRACE_DOMAIN(" _DemuxBroadcast(): checking endpoint %s...", AddressString(fDomain, *endpoint->LocalAddress(), true).Data()); @@ -540,7 +540,7 @@ UdpDomainSupport::_DemuxBroadcast(net_buffer *buffer) } if (endpoint->LocalAddress().MatchMasked(broadcastAddr, mask) - || endpoint->LocalAddress().IsEmpty(false)) { + || mask == NULL || endpoint->LocalAddress().IsEmpty(false)) { // address matches, dispatch to this endpoint: endpoint->StoreData(buffer); } @@ -675,7 +675,7 @@ UdpEndpointManager::ReceiveData(net_buffer *buffer) { TRACE_EPM("ReceiveData(%p [%" B_PRIu32 " bytes])", buffer, buffer->size); - UdpDomainSupport* domainSupport = _GetDomain(buffer); + UdpDomainSupport* domainSupport = _GetDomainSupport(buffer); if (domainSupport == NULL) { // we don't instantiate domain supports in the receiving path, as // we are only interested in delivering data to existing sockets. @@ -710,7 +710,7 @@ UdpEndpointManager::ReceiveError(status_t error, net_buffer* buffer) if (buffer->size < 4) return B_BAD_VALUE; - UdpDomainSupport* domainSupport = _GetDomain(buffer); + UdpDomainSupport* domainSupport = _GetDomainSupport(buffer); if (domainSupport == NULL) { // we don't instantiate domain supports in the receiving path, as // we are only interested in delivering data to existing sockets. @@ -738,25 +738,23 @@ UdpEndpointManager::ReceiveError(status_t error, net_buffer* buffer) status_t -UdpEndpointManager::Deframe(net_buffer *buffer) +UdpEndpointManager::Deframe(net_buffer* buffer) { TRACE_EPM("Deframe(%p [%ld bytes])", buffer, buffer->size); NetBufferHeaderReader bufferHeader(buffer); - if (bufferHeader.Status() < B_OK) + if (bufferHeader.Status() != B_OK) return bufferHeader.Status(); - udp_header &header = bufferHeader.Data(); + udp_header& header = bufferHeader.Data(); - if (buffer->interface_address == NULL - || buffer->interface_address->domain == NULL) { + net_domain* domain = _GetDomain(buffer); + if (domain == NULL) { TRACE_EPM(" Deframe(): UDP packed dropped as there was no domain " "specified (interface address %p).", buffer->interface_address); return B_BAD_VALUE; } - - net_domain *domain = buffer->interface_address->domain; - net_address_module_info *addressModule = domain->address_module; + net_address_module_info* addressModule = domain->address_module; SocketAddress source(addressModule, buffer->source); SocketAddress destination(addressModule, buffer->destination); @@ -799,7 +797,7 @@ UdpEndpointManager::OpenEndpoint(UdpEndpoint *endpoint) { MutexLocker _(fLock); - UdpDomainSupport *domain = _GetDomain(endpoint->Domain(), true); + UdpDomainSupport* domain = _GetDomainSupport(endpoint->Domain(), true); if (domain) domain->Ref(); return domain; @@ -823,10 +821,23 @@ UdpEndpointManager::FreeEndpoint(UdpDomainSupport *domain) // #pragma mark - -UdpDomainSupport * -UdpEndpointManager::_GetDomain(net_domain *domain, bool create) +inline net_domain* +UdpEndpointManager::_GetDomain(net_buffer* buffer) { - UdpDomainList::Iterator it = fDomains.GetIterator(); + if (buffer->interface_address != NULL) + return buffer->interface_address->domain; + + return gStackModule->get_domain(buffer->destination->sa_family); +} + + +UdpDomainSupport* +UdpEndpointManager::_GetDomainSupport(net_domain* domain, bool create) +{ + ASSERT_LOCKED_MUTEX(&fLock); + + if (domain == NULL) + return NULL; // TODO convert this into a Hashtable or install per-domain // receiver handlers that forward the requests to the @@ -834,8 +845,8 @@ UdpEndpointManager::_GetDomain(net_domain *domain, bool create) // being constructed UdpDomainSupport could call // register_domain_receiving_protocol() with the right // family. - while (it.HasNext()) { - UdpDomainSupport *domainSupport = it.Next(); + UdpDomainList::Iterator iterator = fDomains.GetIterator(); + while (UdpDomainSupport* domainSupport = iterator.Next()) { if (domainSupport->Domain() == domain) return domainSupport; } @@ -843,8 +854,8 @@ UdpEndpointManager::_GetDomain(net_domain *domain, bool create) if (!create) return NULL; - UdpDomainSupport *domainSupport = - new (std::nothrow) UdpDomainSupport(domain); + UdpDomainSupport* domainSupport + = new (std::nothrow) UdpDomainSupport(domain); if (domainSupport == NULL || domainSupport->Init() < B_OK) { delete domainSupport; return NULL; @@ -855,14 +866,16 @@ UdpEndpointManager::_GetDomain(net_domain *domain, bool create) } +/*! Retrieves the UdpDomainSupport object responsible for this buffer, if the + domain can be determined. This is only successful if the domain support is + already existing, ie. there must already be an endpoint for the domain. +*/ UdpDomainSupport* -UdpEndpointManager::_GetDomain(net_buffer* buffer) +UdpEndpointManager::_GetDomainSupport(net_buffer* buffer) { - if (buffer->interface_address == NULL) - return NULL; - MutexLocker _(fLock); - return _GetDomain(buffer->interface_address->domain, false); + + return _GetDomainSupport(_GetDomain(buffer), false); // TODO: we don't want to hold to the manager's lock during the // whole RX path, we may not hold an endpoint's lock with the // manager lock held.