initial IPv4 multicast receive path.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20692 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Hugo Santos 2007-04-15 04:02:02 +00:00
parent 6c501a4085
commit d3be414572

View File

@ -115,13 +115,30 @@ class FragmentPacket {
net_timer fTimer;
};
typedef DoublyLinkedList<class RawSocket> 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<RawSocket>, public DatagramSocket<> {
public:
RawSocket(net_socket *socket);
};
typedef DoublyLinkedList<RawSocket> 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);