From 1978fb81ee336190191a317ad0fb413e8044f2fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Wed, 21 Jul 2010 12:00:27 +0000 Subject: [PATCH] * First part of ICMP support: this is based on the work by Ivo Vachkov (GSoC 2007), and Yin Qiu (GSoC 2008). And even though I needed to rewrite pretty much all of it because of the countless bugs and problems it had, it still shares the same architectural problems of introducing a domain dependent error mechanism to the upper layers, and needing the net_buffer::network_header hack. This I will rework later. * net_buffer's append_size(), and prepend_size() will now gracefully handle buffers without a data node. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@37647 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/net/icmp.h | 59 +++++ headers/private/net/net_buffer.h | 7 +- headers/private/net/net_protocol.h | 2 +- .../kernel/network/protocols/icmp/Jamfile | 19 +- .../kernel/network/protocols/icmp/icmp.cpp | 229 +++++++++++++++--- .../kernel/network/protocols/ipv4/ipv4.cpp | 114 +++++---- .../kernel/network/protocols/ipv4/ipv4.h | 47 ++++ .../kernel/network/stack/net_buffer.cpp | 14 ++ 8 files changed, 386 insertions(+), 105 deletions(-) create mode 100644 headers/private/net/icmp.h create mode 100644 src/add-ons/kernel/network/protocols/ipv4/ipv4.h diff --git a/headers/private/net/icmp.h b/headers/private/net/icmp.h new file mode 100644 index 0000000000..91dca3c5d5 --- /dev/null +++ b/headers/private/net/icmp.h @@ -0,0 +1,59 @@ +/* + * Copyright 2006-2010, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef ICMP_H +#define ICMP_H + + +// TODO: this will go private soon + + +// RFC 792 +#define ICMP_TYPE_ECHO_REPLY 0 +#define ICMP_TYPE_UNREACH 3 +#define ICMP_TYPE_SOURCE_QUENCH 4 +#define ICMP_TYPE_REDIRECT 5 +#define ICMP_TYPE_ECHO_REQUEST 8 +#define ICMP_TYPE_TIME_EXCEEDED 11 +#define ICMP_TYPE_PARAM_PROBLEM 12 +#define ICMP_TYPE_TIMESTAMP_REQUEST 13 +#define ICMP_TYPE_TIMESTAMP_REPLY 14 +#define ICMP_TYPE_INFO_REQUEST 15 +#define ICMP_TYPE_INFO_REPLY 16 +// RFC 950 +#define ICMP_TYPE_ADDR_MASK_REQUEST 17 +#define ICMP_TYPE_ADDR_MASK_REPLY 18 + +#define ICMP_CODE_TIMEEX_IN_TRANSIT 0 +#define ICMP_CODE_TIMEEX_FRAG 1 +#define ICMP_CODE_PARAM_PROBLEM 0 +#define ICMP_CODE_SOURCE_QUENCH 0 +#define ICMP_CODE_NET_UNREACH 0 +#define ICMP_CODE_HOST_UNREACH 1 +#define ICMP_CODE_PROTO_UNREACH 2 +#define ICMP_CODE_PORT_UNREACH 3 +#define ICMP_CODE_FRAG_NEEDED 4 +#define ICMP_CODE_SOURCE_ROUTE_FAIL 5 +#define ICMP_CODE_REDIRECT_NET 0 +#define ICMP_CODE_REDIRECT_HOST 1 +#define ICMP_CODE_REDIRECT_TOS_NET 2 +#define ICMP_CODE_REDIRECT_TOS_HOST 3 + + +static inline void +icmp_decode(uint32 errorCode, uint8 &type, uint8 &code) +{ + type = errorCode >> 8; + code = errorCode & 0x0FF; +} + + +static inline uint32 +icmp_encode(uint8 type, uint8 code) +{ + return ((uint32)type) << 8 + code; +} + + +#endif // ICMP_H diff --git a/headers/private/net/net_buffer.h b/headers/private/net/net_buffer.h index 2748f85ff6..2b108c4f0e 100644 --- a/headers/private/net/net_buffer.h +++ b/headers/private/net/net_buffer.h @@ -1,5 +1,5 @@ /* - * Copyright 2006-2008, Haiku, Inc. All Rights Reserved. + * Copyright 2006-2010, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. */ #ifndef NET_BUFFER_H @@ -14,6 +14,7 @@ #define NET_BUFFER_MODULE_NAME "network/stack/buffer/v1" + typedef struct net_buffer { struct list_link link; @@ -36,7 +37,10 @@ typedef struct net_buffer { uint32 flags; uint32 size; uint8 protocol; + + // TODO: these two should go away again uint8 hoplimit; + void * network_header; } net_buffer; struct ancillary_data_container; @@ -98,4 +102,5 @@ struct net_buffer_module_info { void (*dump)(net_buffer *buffer); }; + #endif // NET_BUFFER_H diff --git a/headers/private/net/net_protocol.h b/headers/private/net/net_protocol.h index 266e82b2e9..bca3652718 100644 --- a/headers/private/net/net_protocol.h +++ b/headers/private/net/net_protocol.h @@ -70,7 +70,7 @@ struct net_protocol_module_info { status_t (*receive_data)(net_buffer *data); status_t (*deliver_data)(net_protocol *protocol, net_buffer *data); - status_t (*error)(uint32 code, net_buffer *data); + status_t (*error_received)(uint32 code, net_buffer *data); status_t (*error_reply)(net_protocol *self, net_buffer *causedError, uint32 code, void *errorData); diff --git a/src/add-ons/kernel/network/protocols/icmp/Jamfile b/src/add-ons/kernel/network/protocols/icmp/Jamfile index 1d4428cd27..1c600627b9 100644 --- a/src/add-ons/kernel/network/protocols/icmp/Jamfile +++ b/src/add-ons/kernel/network/protocols/icmp/Jamfile @@ -1,25 +1,8 @@ SubDir HAIKU_TOP src add-ons kernel network protocols icmp ; -SetSubDirSupportedPlatformsBeOSCompatible ; - -if $(TARGET_PLATFORM) != haiku { - UseHeaders [ FStandardOSHeaders ] : true ; - # Needed for and maybe other stuff. - UseHeaders [ FDirName $(HAIKU_TOP) headers posix ] : true ; - # We need the public network headers also when not compiling for Haiku. - # Unfortunately we get more than we want, namely all POSIX headers. -} - +UseHeaders [ FDirName $(HAIKU_TOP) src add-ons kernel network protocols ipv4 ] ; UsePrivateHeaders kernel net ; KernelAddon icmp : icmp.cpp ; - -# Installation -HaikuInstall install-networking : /boot/home/config/add-ons/kernel/haiku_network/protocols - : icmp ; - -Package haiku-networkingkit-cvs : - haiku : - boot home config add-ons kernel haiku_network protocols ; diff --git a/src/add-ons/kernel/network/protocols/icmp/icmp.cpp b/src/add-ons/kernel/network/protocols/icmp/icmp.cpp index 0168d7facc..14f8959988 100644 --- a/src/add-ons/kernel/network/protocols/icmp/icmp.cpp +++ b/src/add-ons/kernel/network/protocols/icmp/icmp.cpp @@ -7,24 +7,36 @@ */ -#include -#include -#include -#include +/*! RFC 792 details the ICMP protocol, RFC 1122 lists when an ICMP error must, + shall, or must not be sent. +*/ -#include -#include +#include #include #include #include #include -//#define TRACE_ICMP +#include +#include + +#include +#include +#include +#include +#include + +//#include + +#include "ipv4.h" + + +#define TRACE_ICMP #ifdef TRACE_ICMP -# define TRACE(x) dprintf x +# define TRACE(x...) dprintf(x) #else -# define TRACE(x) ; +# define TRACE(x...) ; #endif @@ -44,6 +56,12 @@ struct icmp_header { uint16 _reserved; uint16 next_mtu; } path_mtu; + uint32 gateway; + struct { + uint16 unused; + uint16 mtu; + } frag; + uint32 zero; }; }; @@ -70,6 +88,36 @@ net_buffer_module_info* gBufferModule; static net_stack_module_info* sStackModule; +static net_domain* +get_domain(struct net_buffer* buffer) +{ + net_domain* domain; + if (buffer->interface != NULL) + domain = buffer->interface->domain; + else + domain = sStackModule->get_domain(buffer->source->sa_family); + + if (domain == NULL || domain->module == NULL) + return NULL; + + return domain; +} + + +static bool +is_icmp_error(uint8 type) +{ + return type == ICMP_TYPE_UNREACH + || type == ICMP_TYPE_PARAM_PROBLEM + || type == ICMP_TYPE_REDIRECT + || type == ICMP_TYPE_TIME_EXCEEDED + || type == ICMP_TYPE_SOURCE_QUENCH; +} + + +// #pragma mark - module API + + net_protocol* icmp_init_protocol(net_socket* socket) { @@ -234,42 +282,49 @@ icmp_get_mtu(net_protocol* protocol, const struct sockaddr* address) status_t icmp_receive_data(net_buffer* buffer) { - TRACE(("ICMP received some data, buffer length %lu\n", buffer->size)); + TRACE("ICMP received some data, buffer length %lu\n", buffer->size); + + net_domain* domain; + if (buffer->interface != NULL) + domain = buffer->interface->domain; + else + domain = sStackModule->get_domain(buffer->source->sa_family); + + if (domain == NULL || domain->module == NULL) + return B_ERROR; NetBufferHeaderReader bufferHeader(buffer); if (bufferHeader.Status() < B_OK) return bufferHeader.Status(); - icmp_header &header = bufferHeader.Data(); + icmp_header& header = bufferHeader.Data(); + uint8 type = header.type; - TRACE((" got type %u, code %u, checksum %u\n", header.type, header.code, - ntohs(header.checksum))); - TRACE((" computed checksum: %ld\n", - gBufferModule->checksum(buffer, 0, buffer->size, true))); + TRACE(" got type %u, code %u, checksum %u\n", header.type, header.code, + ntohs(header.checksum)); + TRACE(" computed checksum: %ld\n", + gBufferModule->checksum(buffer, 0, buffer->size, true)); if (gBufferModule->checksum(buffer, 0, buffer->size, true) != 0) return B_BAD_DATA; - switch (header.type) { + switch (type) { case ICMP_TYPE_ECHO_REPLY: break; case ICMP_TYPE_ECHO_REQUEST: { - net_domain* domain; - if (buffer->interface != NULL) { - domain = buffer->interface->domain; + net_domain* domain = get_domain(buffer); + if (domain == NULL) + break; + if (buffer->interface != NULL) { // We only reply to echo requests of our local interface; we // don't reply to broadcast requests if (!domain->address_module->equal_addresses( buffer->interface->address, buffer->destination)) break; - } else - domain = sStackModule->get_domain(buffer->source->sa_family); - - if (domain == NULL || domain->module == NULL) - break; + } net_buffer* reply = gBufferModule->duplicate(buffer); if (reply == NULL) @@ -278,13 +333,13 @@ icmp_receive_data(net_buffer* buffer) gBufferModule->swap_addresses(reply); // There already is an ICMP header, and we'll reuse it - NetBufferHeaderReader header(reply); + NetBufferHeaderReader newHeader(reply); - header->type = ICMP_TYPE_ECHO_REPLY; - header->code = 0; - header->checksum = 0; + newHeader->type = type == ICMP_TYPE_ECHO_REPLY; + newHeader->code = 0; + newHeader->checksum = 0; - header.Sync(); + newHeader.Sync(); *ICMPChecksumField(reply) = gBufferModule->checksum(reply, 0, reply->size, true); @@ -294,9 +349,36 @@ icmp_receive_data(net_buffer* buffer) gBufferModule->free(reply); return status; } + break; } - + + case ICMP_TYPE_UNREACH: + case ICMP_TYPE_SOURCE_QUENCH: + case ICMP_TYPE_PARAM_PROBLEM: + case ICMP_TYPE_TIME_EXCEEDED: + { + net_domain* domain = get_domain(buffer); + if (domain == NULL) + break; + + uint32 error = icmp_encode(header.type, header.code); + if (error > 0) { + // Deliver the error to the domain protocol which will + // propagate the error to the upper protocols + return domain->module->error_received(error, buffer); + } + break; + } + + case ICMP_TYPE_REDIRECT: + // TODO: Update the routing table + case ICMP_TYPE_TIMESTAMP_REQUEST: + case ICMP_TYPE_TIMESTAMP_REPLY: + case ICMP_TYPE_INFO_REQUEST: + case ICMP_TYPE_INFO_REPLY: default: + // RFC 1122 3.2.2: + // Unknown ICMP messages are silently discarded dprintf("ICMP: received unhandled type %u, code %u\n", header.type, header.code); break; @@ -308,17 +390,96 @@ icmp_receive_data(net_buffer* buffer) status_t -icmp_error(uint32 code, net_buffer* data) +icmp_error_received(uint32 code, net_buffer* data) { return B_ERROR; } +/*! Sends an ICMP error message to the source of the \a buffer causing the + error. +*/ status_t -icmp_error_reply(net_protocol* protocol, net_buffer* causedError, uint32 code, +icmp_error_reply(net_protocol* protocol, net_buffer* buffer, uint32 code, void* errorData) { - return B_ERROR; + TRACE("icmp_error_reply(code %#" B_PRIx32 ")\n", code); + + uint8 icmpType, icmpCode; + icmp_decode(code, icmpType, icmpCode); + + NetBufferHeaderReader bufferHeader(buffer); + size_t offset = 0; + + // TODO: get rid of network_header + ipv4_header* header = (ipv4_header*)buffer->network_header; + if (header == NULL) { + if (bufferHeader.Status() != B_OK) + return bufferHeader.Status(); + + header = &bufferHeader.Data(); + offset = header->HeaderLength(); + } + + char originalData[64]; + size_t originalSize + = std::min(buffer->size - offset, sizeof(originalData)); + if (originalSize < 8) { + // We need at least 8 bytes of data of the original data + return B_ERROR; + } + + status_t status = gBufferModule->read(buffer, offset, originalData, + originalSize); + if (status != B_OK) + return status; + + // RFC 1122 3.2.2: + // ICMP error message should not be sent on reception of + // an ICMP error message, + if (header->protocol == IPPROTO_ICMP) { + icmp_header* icmpHeader = (icmp_header*)originalData; + if (is_icmp_error(icmpHeader->code)) + return B_ERROR; + } + + // a datagram to an IP multicast or broadcast address, + if ((buffer->flags & (MSG_BCAST | MSG_MCAST)) != 0) + return B_ERROR; + + // a non-initial fragment + if ((header->FragmentOffset() & IP_FRAGMENT_OFFSET_MASK) != 0) + return B_ERROR; + + net_buffer* reply = gBufferModule->create(256); + if (reply == NULL) + return B_NO_MEMORY; + + memcpy(reply->source, buffer->destination, buffer->destination->sa_len); + memcpy(reply->destination, buffer->source, buffer->source->sa_len); + + // Now prepare the ICMP header + NetBufferPrepend icmpHeader(reply); + icmpHeader->type = icmpType; + icmpHeader->code = icmpCode; + icmpHeader->gateway = errorData ? *((uint32*)errorData) : 0; + icmpHeader->checksum = 0; + icmpHeader.Sync(); + *ICMPChecksumField(reply) + = gBufferModule->checksum(reply, 0, reply->size, true); + + // Append IP header + 64 bits of the original datagram + gBufferModule->append(reply, header, sizeof(ipv4_header)); + + net_domain* domain = get_domain(buffer); + if (domain == NULL) + return B_ERROR; + + status = domain->module->send_data(NULL, reply); + if (status != B_OK) + gBufferModule->free(reply); + + return status; } @@ -382,7 +543,7 @@ net_protocol_module_info sICMPModule = { icmp_get_mtu, icmp_receive_data, NULL, // deliver_data() - icmp_error, + icmp_error_received, icmp_error_reply, NULL, // add_ancillary_data() NULL, // process_ancillary_data() diff --git a/src/add-ons/kernel/network/protocols/ipv4/ipv4.cpp b/src/add-ons/kernel/network/protocols/ipv4/ipv4.cpp index 9c9a908533..9b7bbbb33e 100644 --- a/src/add-ons/kernel/network/protocols/ipv4/ipv4.cpp +++ b/src/add-ons/kernel/network/protocols/ipv4/ipv4.cpp @@ -7,9 +7,11 @@ */ +#include "ipv4.h" #include "ipv4_address.h" #include "multicast.h" +#include #include #include #include @@ -18,7 +20,6 @@ #include #include -#include #include #include #include @@ -48,42 +49,12 @@ #endif -struct ipv4_header { -#if B_HOST_IS_LENDIAN == 1 - uint8 header_length : 4; // header length in 32-bit words - uint8 version : 4; -#else - uint8 version : 4; - uint8 header_length : 4; -#endif - uint8 service_type; - uint16 total_length; - uint16 id; - uint16 fragment_offset; - uint8 time_to_live; - uint8 protocol; - uint16 checksum; - in_addr_t source; - in_addr_t destination; - - uint16 HeaderLength() const { return header_length << 2; } - uint16 TotalLength() const { return ntohs(total_length); } - uint16 FragmentOffset() const { return ntohs(fragment_offset); } -} _PACKED; - -#define IP_VERSION 4 - -// fragment flags -#define IP_RESERVED_FLAG 0x8000 -#define IP_DONT_FRAGMENT 0x4000 -#define IP_MORE_FRAGMENTS 0x2000 -#define IP_FRAGMENT_OFFSET_MASK 0x1fff - #define MAX_HASH_FRAGMENTS 64 // slots in the fragment packet's hash #define FRAGMENT_TIMEOUT 60000000LL // discard fragment after 60 seconds + typedef DoublyLinkedList > FragmentList; @@ -116,7 +87,7 @@ public: static void StaleTimer(struct net_timer* timer, void* data); private: - FragmentPacket *fNext; + FragmentPacket* fNext; struct ipv4_packet_key fKey; bool fReceivedLastFragment; int32 fBytesLeft; @@ -232,7 +203,7 @@ FragmentPacket::FragmentPacket(const ipv4_packet_key &key) fReceivedLastFragment(false), fBytesLeft(IP_MAXPACKET) { - gStackModule->init_timer(&fTimer, StaleTimer, this); + gStackModule->init_timer(&fTimer, FragmentPacket::StaleTimer, this); } @@ -450,8 +421,15 @@ FragmentPacket::StaleTimer(struct net_timer* timer, void* data) TRACE("Assembling FragmentPacket %p timed out!", packet); MutexLocker locker(&sFragmentLock); - hash_remove(sFragmentHash, packet); + locker.Unlock(); + + if (!packet->fFragments.IsEmpty()) { + // Send error: fragment reassembly time exceeded + sDomain->module->error_reply(NULL, packet->fFragments.First(), + icmp_encode(ICMP_TYPE_TIME_EXCEEDED, ICMP_CODE_TIMEEX_FRAG), NULL); + } + delete packet; } @@ -706,14 +684,14 @@ deliver_multicast(net_protocol_module_info* module, net_buffer* buffer, // as Multicast filters are installed with an IPv4 protocol // reference, we need to go and find the appropriate instance // related to the 'receiving protocol' with module 'module'. - net_protocol* proto + net_protocol* protocol = state->Parent()->Socket()->socket->first_protocol; - while (proto && proto->module != module) - proto = proto->next; + while (protocol != NULL && protocol->module != module) + protocol = protocol->next; - if (proto) - module->deliver_data(proto, buffer); + if (protocol != NULL) + module->deliver_data(protocol, buffer); } } @@ -721,13 +699,16 @@ deliver_multicast(net_protocol_module_info* module, net_buffer* buffer, } -static void +/*! Delivers the buffer to all listening raw sockets. + Returns \c true if there was any receiver, \c false if not. +*/ +static bool raw_receive_data(net_buffer* buffer) { MutexLocker locker(sRawSocketsLock); if (sRawSockets.IsEmpty()) - return; + return false; TRACE("RawReceiveData(%i)", buffer->protocol); @@ -748,6 +729,8 @@ raw_receive_data(net_buffer* buffer) raw->SocketEnqueue(buffer); } } + + return true; } @@ -1547,7 +1530,7 @@ ipv4_receive_data(net_buffer* buffer) if (bufferHeader.Status() != B_OK) return bufferHeader.Status(); - ipv4_header &header = bufferHeader.Data(); + ipv4_header& header = bufferHeader.Data(); //dump_ipv4_header(header); if (header.version != IP_VERSION) @@ -1563,7 +1546,8 @@ ipv4_receive_data(net_buffer* buffer) if (gBufferModule->checksum(buffer, 0, headerLength, true) != 0) return B_BAD_DATA; - // lower layers notion of Broadcast or Multicast have no relevance to us + // 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); sockaddr_in destination; @@ -1583,6 +1567,9 @@ ipv4_receive_data(net_buffer* buffer) buffer->destination, &buffer->interface)) { TRACE(" ReceiveData(): 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); return B_ERROR; } @@ -1603,7 +1590,7 @@ ipv4_receive_data(net_buffer* buffer) return status; // check for fragmentation - uint16 fragmentOffset = ntohs(header.fragment_offset); + uint16 fragmentOffset = header.FragmentOffset(); if ((fragmentOffset & IP_MORE_FRAGMENTS) != 0 || (fragmentOffset & IP_FRAGMENT_OFFSET_MASK) != 0) { // this is a fragment @@ -1620,19 +1607,32 @@ ipv4_receive_data(net_buffer* buffer) } } + // Preserve the ipv4 header for ICMP processing + // TODO: solve this differently, and discard net_buffer::network_header! + ipv4_header* clonedHeader = (ipv4_header*)malloc(sizeof(ipv4_header)); + if (clonedHeader == NULL) + return B_NO_MEMORY; + + memcpy(clonedHeader, &header, sizeof(ipv4_header)); + buffer->network_header = clonedHeader; + // Since the buffer might have been changed (reassembled fragment) // we must no longer access bufferHeader or header anymore after // this point - raw_receive_data(buffer); + bool rawDelivered = raw_receive_data(buffer); gBufferModule->remove_header(buffer, headerLength); // the header is of variable size and may include IP options - // (that we ignore for now) + // (TODO: that we ignore for now) net_protocol_module_info* module = receiving_protocol(protocol); if (module == NULL) { // no handler for this packet + if (!rawDelivered) { + sDomain->module->error_reply(NULL, buffer, + icmp_encode(ICMP_TYPE_UNREACH, ICMP_CODE_PROTO_UNREACH), NULL); + } return EAFNOSUPPORT; } @@ -1661,9 +1661,16 @@ ipv4_deliver_data(net_protocol* _protocol, net_buffer* buffer) status_t -ipv4_error(uint32 code, net_buffer* data) +ipv4_error_received(uint32 code, net_buffer* data) { - return B_ERROR; + // Extracts the IP header in the ICMP message + NetBufferFieldReader header(data); + net_protocol_module_info* protocol = receiving_protocol(header->protocol); + if (protocol == NULL) + return B_ERROR; + + // propagate error + return protocol->error_received(code, data); } @@ -1671,7 +1678,12 @@ status_t ipv4_error_reply(net_protocol* protocol, net_buffer* causedError, uint32 code, void* errorData) { - return B_ERROR; + // Directly obtain the ICMP protocol module + net_protocol_module_info* icmp = receiving_protocol(IPPROTO_ICMP); + if (icmp == NULL) + return B_ERROR; + + return icmp->error_reply(protocol, causedError, code, errorData); } @@ -1838,7 +1850,7 @@ net_protocol_module_info gIPv4Module = { ipv4_get_mtu, ipv4_receive_data, ipv4_deliver_data, - ipv4_error, + ipv4_error_received, ipv4_error_reply, NULL, // add_ancillary_data() NULL, // process_ancillary_data() diff --git a/src/add-ons/kernel/network/protocols/ipv4/ipv4.h b/src/add-ons/kernel/network/protocols/ipv4/ipv4.h new file mode 100644 index 0000000000..eb72dbd92b --- /dev/null +++ b/src/add-ons/kernel/network/protocols/ipv4/ipv4.h @@ -0,0 +1,47 @@ +/* + * Copyright 2006-2010, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef IPV4_H +#define IPV4_H + + +#include + +#include + + +#define IP_VERSION 4 + +// fragment flags +#define IP_RESERVED_FLAG 0x8000 +#define IP_DONT_FRAGMENT 0x4000 +#define IP_MORE_FRAGMENTS 0x2000 +#define IP_FRAGMENT_OFFSET_MASK 0x1fff + + +struct ipv4_header { +#if B_HOST_IS_LENDIAN == 1 + uint8 header_length : 4; // header length in 32-bit words + uint8 version : 4; +#else + uint8 version : 4; + uint8 header_length : 4; +#endif + uint8 service_type; + uint16 total_length; + uint16 id; + uint16 fragment_offset; + uint8 time_to_live; + uint8 protocol; + uint16 checksum; + in_addr_t source; + in_addr_t destination; + + uint16 HeaderLength() const { return header_length << 2; } + uint16 TotalLength() const { return ntohs(total_length); } + uint16 FragmentOffset() const { return ntohs(fragment_offset); } +} _PACKED; + + +#endif // IPV4_H diff --git a/src/add-ons/kernel/network/stack/net_buffer.cpp b/src/add-ons/kernel/network/stack/net_buffer.cpp index ede4337e74..df558d8452 100644 --- a/src/add-ons/kernel/network/stack/net_buffer.cpp +++ b/src/add-ons/kernel/network/stack/net_buffer.cpp @@ -1040,6 +1040,8 @@ copy_metadata(net_buffer* destination, const net_buffer* source) destination->protocol = source->protocol; destination->hoplimit = source->hoplimit; destination->type = source->type; + + destination->network_header = NULL; } @@ -1075,6 +1077,7 @@ create_buffer(size_t headerSpace) list_add_item(&buffer->buffers, node); buffer->ancillary_data = NULL; + buffer->network_header = NULL; buffer->source = (sockaddr*)&buffer->storage.source; buffer->destination = (sockaddr*)&buffer->storage.destination; @@ -1117,6 +1120,7 @@ free_buffer(net_buffer* _buffer) } delete_ancillary_data_container(buffer->ancillary_data); + free(buffer->network_header); release_data_header(buffer->allocation_header); @@ -1516,6 +1520,11 @@ prepend_size(net_buffer* _buffer, size_t size, void** _contiguousBuffer) { net_buffer_private* buffer = (net_buffer_private*)_buffer; data_node* node = (data_node*)list_get_first_item(&buffer->buffers); + if (node == NULL) { + node = add_first_data_node(buffer->allocation_header); + if (node == NULL) + return B_NO_MEMORY; + } T(PrependSize(buffer, size)); @@ -1628,6 +1637,11 @@ append_size(net_buffer* _buffer, size_t size, void** _contiguousBuffer) { net_buffer_private* buffer = (net_buffer_private*)_buffer; data_node* node = (data_node*)list_get_last_item(&buffer->buffers); + if (node == NULL) { + node = add_first_data_node(buffer->allocation_header); + if (node == NULL) + return B_NO_MEMORY; + } T(AppendSize(buffer, size));