* ipv4_error_received() also needs to fill in the buffer's address, and

protocol, and cut off its IPv4 header before forwarding the buffer to the
  upper layers.
* Some minor cleanup.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@37711 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2010-07-23 10:08:23 +00:00
parent 6404b00512
commit b0e48987f0
1 changed files with 104 additions and 57 deletions

View File

@ -763,6 +763,56 @@ fill_sockaddr_in(sockaddr_in* target, in_addr_t address)
}
static status_t
get_int_option(void* target, size_t length, int value)
{
if (length != sizeof(int))
return B_BAD_VALUE;
return user_memcpy(target, &value, sizeof(int));
}
template<typename Type> static status_t
set_int_option(Type &target, const void* _value, size_t length)
{
int value;
if (length != sizeof(int))
return B_BAD_VALUE;
if (user_memcpy(&value, _value, sizeof(int)) != B_OK)
return B_BAD_ADDRESS;
target = value;
return B_OK;
}
static net_protocol_module_info*
receiving_protocol(uint8 protocol)
{
net_protocol_module_info* module = sReceivingProtocol[protocol];
if (module != NULL)
return module;
MutexLocker locker(sReceivingProtocolLock);
module = sReceivingProtocol[protocol];
if (module != NULL)
return module;
if (gStackModule->get_domain_receiving_protocol(sDomain, protocol,
&module) == B_OK)
sReceivingProtocol[protocol] = module;
return module;
}
// #pragma mark - multicast
status_t
IPv4Multicast::JoinGroup(IPv4GroupInterface* state)
{
@ -798,27 +848,6 @@ IPv4Multicast::LeaveGroup(IPv4GroupInterface* state)
}
static net_protocol_module_info*
receiving_protocol(uint8 protocol)
{
net_protocol_module_info* module = sReceivingProtocol[protocol];
if (module != NULL)
return module;
MutexLocker locker(sReceivingProtocolLock);
module = sReceivingProtocol[protocol];
if (module != NULL)
return module;
if (gStackModule->get_domain_receiving_protocol(sDomain, protocol,
&module) == B_OK)
sReceivingProtocol[protocol] = module;
return module;
}
static status_t
ipv4_delta_group(IPv4GroupInterface* group, int option,
net_interface* interface, const in_addr* sourceAddr)
@ -969,33 +998,7 @@ ipv4_generic_delta_membership(ipv4_protocol* protocol, int option,
}
static status_t
get_int_option(void* target, size_t length, int value)
{
if (length != sizeof(int))
return B_BAD_VALUE;
return user_memcpy(target, &value, sizeof(int));
}
template<typename Type> static status_t
set_int_option(Type &target, const void* _value, size_t length)
{
int value;
if (length != sizeof(int))
return B_BAD_VALUE;
if (user_memcpy(&value, _value, sizeof(int)) != B_OK)
return B_BAD_ADDRESS;
target = value;
return B_OK;
}
// #pragma mark -
// #pragma mark - module interface
net_protocol*
@ -1547,7 +1550,7 @@ ipv4_get_mtu(net_protocol* protocol, const struct sockaddr* address)
status_t
ipv4_receive_data(net_buffer* buffer)
{
TRACE("ReceiveData(%p [%ld bytes])", buffer, buffer->size);
TRACE("ipv4_receive_data(%p [%ld bytes])", buffer, buffer->size);
NetBufferHeaderReader<ipv4_header> bufferHeader(buffer);
if (bufferHeader.Status() != B_OK)
@ -1588,9 +1591,9 @@ ipv4_receive_data(net_buffer* buffer)
&buffer->interface, &matchedAddressType)
&& !sDatalinkModule->is_local_link_address(sDomain, true,
buffer->destination, &buffer->interface)) {
TRACE(" ReceiveData(): packet was not for us %x -> %x",
TRACE(" ipv4_receive_data(): packet was not for us %x -> %x",
ntohl(header.source), ntohl(header.destination));
// Send ICMP error: Host unreachable
sDomain->module->error_reply(NULL, buffer,
icmp_encode(ICMP_TYPE_UNREACH, ICMP_CODE_HOST_UNREACH), NULL);
@ -1605,7 +1608,7 @@ ipv4_receive_data(net_buffer* buffer)
fill_sockaddr_in((struct sockaddr_in*)buffer->source, header.source);
memcpy(buffer->destination, &destination, sizeof(sockaddr_in));
uint8 protocol = buffer->protocol = header.protocol;
buffer->protocol = header.protocol;
// remove any trailing/padding data
status_t status = gBufferModule->trim(buffer, packetLength);
@ -1617,15 +1620,15 @@ ipv4_receive_data(net_buffer* buffer)
if ((fragmentOffset & IP_MORE_FRAGMENTS) != 0
|| (fragmentOffset & IP_FRAGMENT_OFFSET_MASK) != 0) {
// this is a fragment
TRACE(" ReceiveData(): Found a Fragment!");
TRACE(" ipv4_receive_data(): Found a Fragment!");
status = reassemble_fragments(header, &buffer);
TRACE(" ReceiveData(): -> %s", strerror(status));
TRACE(" ipv4_receive_data(): -> %s", strerror(status));
if (status != B_OK)
return status;
if (buffer == NULL) {
// buffer was put into fragment packet
TRACE(" ReceiveData(): Not yet assembled.");
TRACE(" ipv4_receive_data(): Not yet assembled.");
return B_OK;
}
}
@ -1639,11 +1642,11 @@ ipv4_receive_data(net_buffer* buffer)
// Preserve the ipv4 header for ICMP processing
gBufferModule->store_header(buffer);
gBufferModule->remove_header(buffer, headerLength);
bufferHeader.Remove(headerLength);
// the header is of variable size and may include IP options
// (TODO: that we ignore for now)
net_protocol_module_info* module = receiving_protocol(protocol);
net_protocol_module_info* module = receiving_protocol(buffer->protocol);
if (module == NULL) {
// no handler for this packet
if (!rawDelivered) {
@ -1682,6 +1685,50 @@ ipv4_deliver_data(net_protocol* _protocol, net_buffer* buffer)
status_t
ipv4_error_received(uint32 code, net_buffer* buffer)
{
TRACE(" ipv4_error_received(code %" B_PRIx32 ", buffer %p [%zu bytes])",
code, buffer, buffer->size);
NetBufferHeaderReader<ipv4_header> bufferHeader(buffer);
if (bufferHeader.Status() != B_OK)
return bufferHeader.Status();
ipv4_header& header = bufferHeader.Data();
TRACE_ONLY(dump_ipv4_header(header));
// We do not check the packet length, as we usually only get a part of it
uint16 headerLength = header.HeaderLength();
if (header.version != IPV4_VERSION
|| headerLength < sizeof(ipv4_header)
|| gBufferModule->checksum(buffer, 0, headerLength, true) != 0)
return B_BAD_DATA;
// Restore addresses of the original buffer
// lower layers notion of broadcast or multicast have no relevance to us
// TODO: they actually have when deciding whether to send an ICMP error
buffer->flags &= ~(MSG_BCAST | MSG_MCAST);
fill_sockaddr_in((struct sockaddr_in*)buffer->source, header.source);
fill_sockaddr_in((struct sockaddr_in*)buffer->destination,
header.destination);
if (header.destination == INADDR_BROADCAST)
buffer->flags |= MSG_BCAST;
else if (IN_MULTICAST(ntohl(header.destination)))
buffer->flags |= MSG_MCAST;
// test if the packet is really from us
if (!sDatalinkModule->is_local_address(sDomain, buffer->source, NULL,
NULL)) {
TRACE(" ipv4_error_received(): packet was not for us %x -> %x",
ntohl(header.source), ntohl(header.destination));
return B_ERROR;
}
buffer->protocol = header.protocol;
bufferHeader.Remove(headerLength);
net_protocol_module_info* protocol = receiving_protocol(buffer->protocol);
if (protocol == NULL)
return B_ERROR;