* 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
This commit is contained in:
Axel Dörfler
2010-08-26 09:23:49 +00:00
parent ef3f86e723
commit 9d4331902c
2 changed files with 66 additions and 54 deletions
@@ -1581,6 +1581,7 @@ ipv4_receive_data(net_buffer* buffer)
// lower layers notion of broadcast or multicast have no relevance to us // lower layers notion of broadcast or multicast have no relevance to us
// other than deciding whether to send an ICMP error // other than deciding whether to send an ICMP error
bool wasMulticast = (buffer->flags & (MSG_BCAST | MSG_MCAST)) != 0; bool wasMulticast = (buffer->flags & (MSG_BCAST | MSG_MCAST)) != 0;
bool notForUs = false;
buffer->flags &= ~(MSG_BCAST | MSG_MCAST); buffer->flags &= ~(MSG_BCAST | MSG_MCAST);
sockaddr_in destination; sockaddr_in destination;
@@ -1590,29 +1591,33 @@ ipv4_receive_data(net_buffer* buffer)
buffer->flags |= MSG_BCAST; buffer->flags |= MSG_BCAST;
// Find first interface with a matching family // Find first interface with a matching family
// TODO: support for ethernet broadcasts! if (!sDatalinkModule->is_local_link_address(sDomain, true,
// TODO: we might need to send it to all interfaces if it's an ethernet buffer->destination, &buffer->interface_address))
// broadcast as well! notForUs = wasMulticast;
sDatalinkModule->is_local_link_address(sDomain, true,
buffer->destination, &buffer->interface_address);
} else if (IN_MULTICAST(ntohl(header.destination))) { } else if (IN_MULTICAST(ntohl(header.destination))) {
buffer->flags |= MSG_MCAST; buffer->flags |= MSG_MCAST;
// TODO: must set buffer->interface_address!
} else { } else {
uint32 matchedAddressType = 0; uint32 matchedAddressType = 0;
// test if the packet is really for us // test if the packet is really for us
if (!sDatalinkModule->is_local_address(sDomain, (sockaddr*)&destination, if (!sDatalinkModule->is_local_address(sDomain, (sockaddr*)&destination,
&buffer->interface_address, &matchedAddressType)) { &buffer->interface_address, &matchedAddressType)
sDatalinkModule->is_local_link_address(sDomain, true, && !sDatalinkModule->is_local_link_address(sDomain, true,
buffer->destination, &buffer->interface_address); buffer->destination, &buffer->interface_address)) {
notForUs = true;
} else { } else {
// copy over special address types (MSG_BCAST or MSG_MCAST): // copy over special address types (MSG_BCAST or MSG_MCAST):
buffer->flags |= matchedAddressType; 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", TRACE(" ipv4_receive_data(): packet was not for us %x -> %x",
ntohl(header.source), ntohl(header.destination)); ntohl(header.source), ntohl(header.destination));
@@ -1625,12 +1630,6 @@ ipv4_receive_data(net_buffer* buffer)
return B_ERROR; 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 // remove any trailing/padding data
status_t status = gBufferModule->trim(buffer, packetLength); status_t status = gBufferModule->trim(buffer, packetLength);
if (status != B_OK) if (status != B_OK)
@@ -234,8 +234,10 @@ public:
static int DumpEndpoints(int argc, char *argv[]); static int DumpEndpoints(int argc, char *argv[]);
private: private:
UdpDomainSupport* _GetDomain(net_domain *domain, bool create); inline net_domain* _GetDomain(net_buffer* buffer);
UdpDomainSupport* _GetDomain(net_buffer* buffer); UdpDomainSupport* _GetDomainSupport(net_domain* domain,
bool create);
UdpDomainSupport* _GetDomainSupport(net_buffer* buffer);
mutex fLock; mutex fLock;
status_t fStatus; status_t fStatus;
@@ -504,23 +506,21 @@ UdpDomainSupport::_FindActiveEndpoint(const sockaddr *ourAddress,
status_t status_t
UdpDomainSupport::_DemuxBroadcast(net_buffer *buffer) UdpDomainSupport::_DemuxBroadcast(net_buffer* buffer)
{ {
sockaddr *peerAddr = buffer->source; sockaddr* peerAddr = buffer->source;
sockaddr *broadcastAddr = buffer->destination; sockaddr* broadcastAddr = buffer->destination;
sockaddr *mask = NULL;
if (buffer->interface_address != NULL)
mask = (sockaddr *)buffer->interface_address->mask;
TRACE_DOMAIN("_DemuxBroadcast(%p)", buffer);
uint16 incomingPort = AddressModule()->get_port(broadcastAddr); 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()) { TRACE_DOMAIN("_DemuxBroadcast(%p): mask %p\n", buffer, mask);
UdpEndpoint *endpoint = it.Next();
EndpointTable::Iterator iterator = fActiveEndpoints.GetIterator();
while (UdpEndpoint* endpoint = iterator.Next()) {
TRACE_DOMAIN(" _DemuxBroadcast(): checking endpoint %s...", TRACE_DOMAIN(" _DemuxBroadcast(): checking endpoint %s...",
AddressString(fDomain, *endpoint->LocalAddress(), true).Data()); AddressString(fDomain, *endpoint->LocalAddress(), true).Data());
@@ -540,7 +540,7 @@ UdpDomainSupport::_DemuxBroadcast(net_buffer *buffer)
} }
if (endpoint->LocalAddress().MatchMasked(broadcastAddr, mask) if (endpoint->LocalAddress().MatchMasked(broadcastAddr, mask)
|| endpoint->LocalAddress().IsEmpty(false)) { || mask == NULL || endpoint->LocalAddress().IsEmpty(false)) {
// address matches, dispatch to this endpoint: // address matches, dispatch to this endpoint:
endpoint->StoreData(buffer); endpoint->StoreData(buffer);
} }
@@ -675,7 +675,7 @@ UdpEndpointManager::ReceiveData(net_buffer *buffer)
{ {
TRACE_EPM("ReceiveData(%p [%" B_PRIu32 " bytes])", buffer, buffer->size); TRACE_EPM("ReceiveData(%p [%" B_PRIu32 " bytes])", buffer, buffer->size);
UdpDomainSupport* domainSupport = _GetDomain(buffer); UdpDomainSupport* domainSupport = _GetDomainSupport(buffer);
if (domainSupport == NULL) { if (domainSupport == NULL) {
// we don't instantiate domain supports in the receiving path, as // we don't instantiate domain supports in the receiving path, as
// we are only interested in delivering data to existing sockets. // 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) if (buffer->size < 4)
return B_BAD_VALUE; return B_BAD_VALUE;
UdpDomainSupport* domainSupport = _GetDomain(buffer); UdpDomainSupport* domainSupport = _GetDomainSupport(buffer);
if (domainSupport == NULL) { if (domainSupport == NULL) {
// we don't instantiate domain supports in the receiving path, as // we don't instantiate domain supports in the receiving path, as
// we are only interested in delivering data to existing sockets. // we are only interested in delivering data to existing sockets.
@@ -738,25 +738,23 @@ UdpEndpointManager::ReceiveError(status_t error, net_buffer* buffer)
status_t status_t
UdpEndpointManager::Deframe(net_buffer *buffer) UdpEndpointManager::Deframe(net_buffer* buffer)
{ {
TRACE_EPM("Deframe(%p [%ld bytes])", buffer, buffer->size); TRACE_EPM("Deframe(%p [%ld bytes])", buffer, buffer->size);
NetBufferHeaderReader<udp_header> bufferHeader(buffer); NetBufferHeaderReader<udp_header> bufferHeader(buffer);
if (bufferHeader.Status() < B_OK) if (bufferHeader.Status() != B_OK)
return bufferHeader.Status(); return bufferHeader.Status();
udp_header &header = bufferHeader.Data(); udp_header& header = bufferHeader.Data();
if (buffer->interface_address == NULL net_domain* domain = _GetDomain(buffer);
|| buffer->interface_address->domain == NULL) { if (domain == NULL) {
TRACE_EPM(" Deframe(): UDP packed dropped as there was no domain " TRACE_EPM(" Deframe(): UDP packed dropped as there was no domain "
"specified (interface address %p).", buffer->interface_address); "specified (interface address %p).", buffer->interface_address);
return B_BAD_VALUE; 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 source(addressModule, buffer->source);
SocketAddress destination(addressModule, buffer->destination); SocketAddress destination(addressModule, buffer->destination);
@@ -799,7 +797,7 @@ UdpEndpointManager::OpenEndpoint(UdpEndpoint *endpoint)
{ {
MutexLocker _(fLock); MutexLocker _(fLock);
UdpDomainSupport *domain = _GetDomain(endpoint->Domain(), true); UdpDomainSupport* domain = _GetDomainSupport(endpoint->Domain(), true);
if (domain) if (domain)
domain->Ref(); domain->Ref();
return domain; return domain;
@@ -823,10 +821,23 @@ UdpEndpointManager::FreeEndpoint(UdpDomainSupport *domain)
// #pragma mark - // #pragma mark -
UdpDomainSupport * inline net_domain*
UdpEndpointManager::_GetDomain(net_domain *domain, bool create) 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 // TODO convert this into a Hashtable or install per-domain
// receiver handlers that forward the requests to the // receiver handlers that forward the requests to the
@@ -834,8 +845,8 @@ UdpEndpointManager::_GetDomain(net_domain *domain, bool create)
// being constructed UdpDomainSupport could call // being constructed UdpDomainSupport could call
// register_domain_receiving_protocol() with the right // register_domain_receiving_protocol() with the right
// family. // family.
while (it.HasNext()) { UdpDomainList::Iterator iterator = fDomains.GetIterator();
UdpDomainSupport *domainSupport = it.Next(); while (UdpDomainSupport* domainSupport = iterator.Next()) {
if (domainSupport->Domain() == domain) if (domainSupport->Domain() == domain)
return domainSupport; return domainSupport;
} }
@@ -843,8 +854,8 @@ UdpEndpointManager::_GetDomain(net_domain *domain, bool create)
if (!create) if (!create)
return NULL; return NULL;
UdpDomainSupport *domainSupport = UdpDomainSupport* domainSupport
new (std::nothrow) UdpDomainSupport(domain); = new (std::nothrow) UdpDomainSupport(domain);
if (domainSupport == NULL || domainSupport->Init() < B_OK) { if (domainSupport == NULL || domainSupport->Init() < B_OK) {
delete domainSupport; delete domainSupport;
return NULL; 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* 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 // 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 // whole RX path, we may not hold an endpoint's lock with the
// manager lock held. // manager lock held.