Author: axeld Date: 2010-08-26 11:23:49 +0200 (Thu, 26 Aug 2010) New Revision: 38365 Changeset: http://dev.haiku-os.org/changeset/38365 Ticket: http://dev.haiku-os.org/ticket/6454 Modified: haiku/trunk/src/add-ons/kernel/network/protocols/ipv4/ipv4.cpp haiku/trunk/src/add-ons/kernel/network/protocols/udp/udp.cpp Log: * 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. Modified: haiku/trunk/src/add-ons/kernel/network/protocols/ipv4/ipv4.cpp =================================================================== --- haiku/trunk/src/add-ons/kernel/network/protocols/ipv4/ipv4.cpp 2010-08-26 09:16:18 UTC (rev 38364) +++ haiku/trunk/src/add-ons/kernel/network/protocols/ipv4/ipv4.cpp 2010-08-26 09:23:49 UTC (rev 38365) @@ -1581,6 +1581,7 @@ // 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 @@ 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 @@ 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) Modified: haiku/trunk/src/add-ons/kernel/network/protocols/udp/udp.cpp =================================================================== --- haiku/trunk/src/add-ons/kernel/network/protocols/udp/udp.cpp 2010-08-26 09:16:18 UTC (rev 38364) +++ haiku/trunk/src/add-ons/kernel/network/protocols/udp/udp.cpp 2010-08-26 09:23:49 UTC (rev 38365) @@ -234,8 +234,10 @@ 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 @@ status_t -UdpDomainSupport::_DemuxBroadcast(net_buffer *buffer) +UdpDomainSupport::_DemuxBroadcast(net_buffer* buffer) { - sockaddr *peerAddr = buffer->source; - sockaddr *broadcastAddr = buffer->destination; - sockaddr *mask = NULL; + sockaddr* peerAddr = buffer->source; + sockaddr* broadcastAddr = buffer->destination; + uint16 incomingPort = AddressModule()->get_port(broadcastAddr); + + sockaddr* mask = NULL; if (buffer->interface_address != NULL) - mask = (sockaddr *)buffer->interface_address->mask; + mask = (sockaddr*)buffer->interface_address->mask; - TRACE_DOMAIN("_DemuxBroadcast(%p)", buffer); + TRACE_DOMAIN("_DemuxBroadcast(%p): mask %p\n", buffer, mask); - uint16 incomingPort = AddressModule()->get_port(broadcastAddr); + EndpointTable::Iterator iterator = fActiveEndpoints.GetIterator(); - EndpointTable::Iterator it = fActiveEndpoints.GetIterator(); - - while (it.HasNext()) { - UdpEndpoint *endpoint = it.Next(); - + while (UdpEndpoint* endpoint = iterator.Next()) { TRACE_DOMAIN(" _DemuxBroadcast(): checking endpoint %s...", AddressString(fDomain, *endpoint->LocalAddress(), true).Data()); @@ -540,7 +540,7 @@ } 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 @@ { 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 @@ 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,26 +738,24 @@ status_t -UdpEndpointManager::Deframe(net_buffer *buffer) +UdpEndpointManager::Deframe(net_buffer* buffer) { TRACE_EPM("Deframe(%p [%ld bytes])", buffer, buffer->size); NetBufferHeaderReader<udp_header> 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_address_module_info* addressModule = domain->address_module; - net_domain *domain = buffer->interface_address->domain; - net_address_module_info *addressModule = domain->address_module; - SocketAddress source(addressModule, buffer->source); SocketAddress destination(addressModule, buffer->destination); @@ -799,7 +797,7 @@ { MutexLocker _(fLock); - UdpDomainSupport *domain = _GetDomain(endpoint->Domain(), true); + UdpDomainSupport* domain = _GetDomainSupport(endpoint->Domain(), true); if (domain) domain->Ref(); return domain; @@ -823,19 +821,32 @@ // #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 // appropriate DemuxIncomingBuffer(). For instance, while // 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 @@ 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 @@ } +/*! 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); - 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.