[haiku-commits] r37688 - in haiku/trunk: headers/private/net src/add-ons/kernel/network/protocols/icmp src/add-ons/kernel/network/protocols/ipv4 src/add-ons/kernel/network/stack

  • From: axeld@xxxxxxxxxxxxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Thu, 22 Jul 2010 14:26:46 +0200 (CEST)

Author: axeld
Date: 2010-07-22 14:26:46 +0200 (Thu, 22 Jul 2010)
New Revision: 37688
Changeset: http://dev.haiku-os.org/changeset/37688

Modified:
   haiku/trunk/headers/private/net/net_buffer.h
   haiku/trunk/src/add-ons/kernel/network/protocols/icmp/icmp.cpp
   haiku/trunk/src/add-ons/kernel/network/protocols/ipv4/ipv4.cpp
   haiku/trunk/src/add-ons/kernel/network/protocols/ipv4/ipv4.h
   haiku/trunk/src/add-ons/kernel/network/stack/net_buffer.cpp
Log:
* Implemented a way to preserve header data while passing along a buffer to the
  upper layers: you use the store_header() function to mark the header you want
  to preserve. All subsequent remove_header() calls won't claim the actual
  data, but only move the node start around.
* This header can then be restored by restore_header(). However, a call to
  prepend_data() will destroy the stored header. Also, if remove_header() cuts
  off a whole node, restoring the header won't succeed anymore.
* Discarded the no longer needed net_buffer::network_header field.
* Also discarded the hoplimit field which temporarily breaks the IPv6 build
  until Atis reworks it.
* IPv4 now also dumps the IP header in the send path if debug output is enabled.
* icmp_error_reply() might be called so early that the net_buffer's addresses
  do not point to the reply address; this is now detected, and the addresses are
  taken out of the IP header in that case.
* Improved dumping the net_buffer to also include its address, and flags.


Modified: haiku/trunk/headers/private/net/net_buffer.h
===================================================================
--- haiku/trunk/headers/private/net/net_buffer.h        2010-07-22 12:20:45 UTC 
(rev 37687)
+++ haiku/trunk/headers/private/net/net_buffer.h        2010-07-22 12:26:46 UTC 
(rev 37688)
@@ -16,31 +16,27 @@
 
 
 typedef struct net_buffer {
-       struct list_link link;
+       struct list_link                link;
 
        // TODO: we should think about moving the address fields into the buffer
        // data itself via associated data or something like this. Or this
        // structure as a whole, too...
 
-       struct sockaddr *source;
-       struct sockaddr *destination;
-       struct net_interface *interface;
-       int32 type;
+       struct sockaddr*                source;
+       struct sockaddr*                destination;
+       struct net_interface*   interface;
+       int32                                   type;
        union {
                struct {
-                       uint16  start;
-                       uint16  end;
-               }               fragment;
-               uint32  sequence;
-               uint32  offset;
+                       uint16                  start;
+                       uint16                  end;
+               }                                       fragment;
+               uint32                          sequence;
+               uint32                          offset;
        };
-       uint32  flags;
-       uint32  size;
-       uint8   protocol;
-       
-       // TODO: these two should go away again
-       uint8   hoplimit;
-       void *  network_header;
+       uint32                                  flags;
+       uint32                                  size;
+       uint8                                   protocol;
 } net_buffer;
 
 struct ancillary_data_container;
@@ -48,58 +44,65 @@
 struct net_buffer_module_info {
        module_info info;
 
-       net_buffer *    (*create)(size_t headerSpace);
-       void                    (*free)(net_buffer *buffer);
+       net_buffer*             (*create)(size_t headerSpace);
+       void                    (*free)(net_buffer* buffer);
 
-       net_buffer *    (*duplicate)(net_buffer *from);
-       net_buffer *    (*clone)(net_buffer *from, bool shareFreeSpace);
-       net_buffer *    (*split)(net_buffer *from, uint32 offset);
-       status_t                (*merge)(net_buffer *buffer, net_buffer *with, 
bool after);
+       net_buffer*             (*duplicate)(net_buffer* from);
+       net_buffer*             (*clone)(net_buffer* from, bool shareFreeSpace);
+       net_buffer*             (*split)(net_buffer* from, uint32 offset);
+       status_t                (*merge)(net_buffer* buffer, net_buffer* with, 
bool after);
 
-       status_t                (*prepend_size)(net_buffer *buffer, size_t size,
-                                               void **_contiguousBuffer);
-       status_t                (*prepend)(net_buffer *buffer, const void *data,
+       status_t                (*prepend_size)(net_buffer* buffer, size_t size,
+                                               void** _contiguousBuffer);
+       status_t                (*prepend)(net_buffer* buffer, const void* data,
                                                size_t bytes);
-       status_t                (*append_size)(net_buffer *buffer, size_t size,
-                                               void **_contiguousBuffer);
-       status_t                (*append)(net_buffer *buffer, const void *data,
+       status_t                (*append_size)(net_buffer* buffer, size_t size,
+                                               void** _contiguousBuffer);
+       status_t                (*append)(net_buffer* buffer, const void* data,
                                                size_t bytes);
-       status_t                (*insert)(net_buffer *buffer, uint32 offset,
-                                               const void *data, size_t bytes, 
uint32 flags);
-       status_t                (*remove)(net_buffer *buffer, uint32 offset,
+       status_t                (*insert)(net_buffer* buffer, uint32 offset,
+                                               const void* data, size_t bytes, 
uint32 flags);
+       status_t                (*remove)(net_buffer* buffer, uint32 offset,
                                                size_t bytes);
-       status_t                (*remove_header)(net_buffer *buffer, size_t 
bytes);
-       status_t                (*remove_trailer)(net_buffer *buffer, size_t 
bytes);
-       status_t                (*trim)(net_buffer *buffer, size_t newSize);
-       status_t                (*append_cloned)(net_buffer *buffer, net_buffer 
*source,
+       status_t                (*remove_header)(net_buffer* buffer, size_t 
bytes);
+       status_t                (*remove_trailer)(net_buffer* buffer, size_t 
bytes);
+       status_t                (*trim)(net_buffer* buffer, size_t newSize);
+       status_t                (*append_cloned)(net_buffer* buffer, 
net_buffer* source,
                                                uint32 offset, size_t bytes);
 
-       status_t                (*associate_data)(net_buffer *buffer, void 
*data);
+       status_t                (*associate_data)(net_buffer* buffer, void* 
data);
 
-       void                    (*set_ancillary_data)(net_buffer *buffer,
-                                               struct ancillary_data_container 
*container);
-       struct ancillary_data_container* (*get_ancillary_data)(net_buffer 
*buffer);
-       void *                  (*transfer_ancillary_data)(net_buffer *from,
-                                               net_buffer *to);
+       void                    (*set_ancillary_data)(net_buffer* buffer,
+                                               struct 
ancillary_data_container* container);
+       struct ancillary_data_container* (*get_ancillary_data)(net_buffer* 
buffer);
+       void*                   (*transfer_ancillary_data)(net_buffer* from,
+                                               net_buffer* to);
 
-       status_t                (*direct_access)(net_buffer *buffer, uint32 
offset,
-                                               size_t bytes, void **_data);
-       status_t                (*read)(net_buffer *buffer, uint32 offset, void 
*data,
+       status_t                (*store_header)(net_buffer* buffer);
+       ssize_t                 (*stored_header_length)(net_buffer* buffer);
+       status_t                (*restore_header)(net_buffer* buffer, uint32 
offset,
+                                               void* data, size_t bytes);
+       status_t                (*append_restored_header)(net_buffer* buffer,
+                                               net_buffer* source, uint32 
offset, size_t bytes);
+
+       status_t                (*direct_access)(net_buffer* buffer, uint32 
offset,
+                                               size_t bytes, void** _data);
+       status_t                (*read)(net_buffer* buffer, uint32 offset, 
void* data,
                                                size_t bytes);
-       status_t                (*write)(net_buffer *buffer, uint32 offset,
-                                               const void *data, size_t bytes);
+       status_t                (*write)(net_buffer* buffer, uint32 offset,
+                                               const void* data, size_t bytes);
 
-       int32                   (*checksum)(net_buffer *buffer, uint32 offset, 
size_t bytes,
+       int32                   (*checksum)(net_buffer* buffer, uint32 offset, 
size_t bytes,
                                                bool finalize);
-       status_t                (*get_memory_map)(net_buffer *buffer,
-                                               struct iovec *iovecs, uint32 
vecCount);
-       uint32                  (*get_iovecs)(net_buffer *buffer,
-                                               struct iovec *iovecs, uint32 
vecCount);
-       uint32                  (*count_iovecs)(net_buffer *buffer);
+       status_t                (*get_memory_map)(net_buffer* buffer,
+                                               struct iovec* iovecs, uint32 
vecCount);
+       uint32                  (*get_iovecs)(net_buffer* buffer,
+                                               struct iovec* iovecs, uint32 
vecCount);
+       uint32                  (*count_iovecs)(net_buffer* buffer);
 
-       void                    (*swap_addresses)(net_buffer *buffer);
+       void                    (*swap_addresses)(net_buffer* buffer);
 
-       void                    (*dump)(net_buffer *buffer);
+       void                    (*dump)(net_buffer* buffer);
 };
 
 

Modified: haiku/trunk/src/add-ons/kernel/network/protocols/icmp/icmp.cpp
===================================================================
--- haiku/trunk/src/add-ons/kernel/network/protocols/icmp/icmp.cpp      
2010-07-22 12:20:45 UTC (rev 37687)
+++ haiku/trunk/src/add-ons/kernel/network/protocols/icmp/icmp.cpp      
2010-07-22 12:26:46 UTC (rev 37688)
@@ -26,6 +26,7 @@
 #include <net_protocol.h>
 #include <net_stack.h>
 #include <NetBufferUtilities.h>
+#include <NetUtilities.h>
 
 #include "ipv4.h"
 
@@ -97,6 +98,16 @@
 }
 
 
+static void
+fill_sockaddr_in(sockaddr_in* target, in_addr_t address)
+{
+       target->sin_family = AF_INET;
+       target->sin_len = sizeof(sockaddr_in);
+       target->sin_port = 0;
+       target->sin_addr.s_addr = address;
+}
+
+
 static bool
 is_icmp_error(uint8 type)
 {
@@ -403,38 +414,25 @@
        icmp_decode(code, icmpType, icmpCode);
        TRACE("  icmp type %u, code %u\n", icmpType, icmpCode);
 
-       NetBufferHeaderReader<ipv4_header> bufferHeader(buffer);
-       size_t offset = 0;
+       ipv4_header header;
+       if (gBufferModule->restore_header(buffer, 0, &header, 
sizeof(ipv4_header))
+                       != B_OK)
+               return B_BAD_VALUE;
 
-       // 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();
+       // Check if we actually have an IPv4 header now
+       if (header.version != IPV4_VERSION
+               || header.HeaderLength() < sizeof(ipv4_header)) {
+               TRACE("  no IPv4 header found\n");
+               return B_BAD_VALUE;
        }
 
-       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))
+       if (header.protocol == IPPROTO_ICMP) {
+               uint8 type;
+               if (gBufferModule->restore_header(buffer, 
header.HeaderLength(), &type,
+                               1) != B_OK || is_icmp_error(type))
                        return B_ERROR;
        }
 
@@ -443,15 +441,20 @@
                return B_ERROR;
 
        // a non-initial fragment
-       if ((header->FragmentOffset() & IP_FRAGMENT_OFFSET_MASK) != 0)
+       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);
+       
+       if (buffer->destination->sa_family == AF_INET) {
+               memcpy(reply->source, buffer->destination, 
buffer->destination->sa_len);
+               memcpy(reply->destination, buffer->source, 
buffer->source->sa_len);
+       } else {
+               fill_sockaddr_in((sockaddr_in*)reply->source, 
header.destination);
+               fill_sockaddr_in((sockaddr_in*)reply->destination, 
header.source);
+       }
 
        // Now prepare the ICMP header
        NetBufferPrepend<icmp_header> icmpHeader(reply);
@@ -463,14 +466,19 @@
        *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));
+       // Append IP header + 8 byte of the original datagram
+       status_t status = gBufferModule->append_restored_header(reply, buffer, 
0,
+               std::min(header.HeaderLength() + 8, (int)header.TotalLength()));
+       if (status == B_OK) {
+               net_domain* domain = get_domain(buffer);
+               if (domain == NULL)
+                       return B_ERROR;
 
-       net_domain* domain = get_domain(buffer);
-       if (domain == NULL)
-               return B_ERROR;
+               TRACE("  send ICMP message to %s\n", AddressString(
+                               domain->address_module, reply->destination, 
true).Data());
 
-       status = domain->module->send_data(NULL, reply);
+               status = domain->module->send_data(NULL, reply);
+       }
        if (status != B_OK)
                gBufferModule->free(reply);
 

Modified: haiku/trunk/src/add-ons/kernel/network/protocols/ipv4/ipv4.cpp
===================================================================
--- haiku/trunk/src/add-ons/kernel/network/protocols/ipv4/ipv4.cpp      
2010-07-22 12:20:45 UTC (rev 37687)
+++ haiku/trunk/src/add-ons/kernel/network/protocols/ipv4/ipv4.cpp      
2010-07-22 12:26:46 UTC (rev 37688)
@@ -1378,7 +1378,7 @@
                if (header.Status() != B_OK)
                        return header.Status();
 
-               header->version = IP_VERSION;
+               header->version = IPV4_VERSION;
                header->header_length = sizeof(ipv4_header) / 4;
                header->service_type = protocol ? protocol->service_type : 0;
                header->total_length = htons(buffer->size);
@@ -1397,6 +1397,8 @@
 
                header->source = source.sin_addr.s_addr;
                header->destination = destination.sin_addr.s_addr;
+
+               TRACE_ONLY(dump_ipv4_header(*header));
        } else {
                // if IP_HDRINCL, check if the source address is set
                NetBufferHeaderReader<ipv4_header> header(buffer);
@@ -1409,6 +1411,9 @@
                        header.Sync();
                } else
                        checksumNeeded = false;
+
+               TRACE("  Header was already supplied:");
+               TRACE_ONLY(dump_ipv4_header(*header));
        }
 
        if (buffer->size > 0xffff)
@@ -1444,7 +1449,7 @@
 
        TRACE_SK(protocol, "SendData(%p [%ld bytes])", buffer, buffer->size);
 
-       if (protocol && (protocol->flags & IP_FLAG_HEADER_INCLUDED)) {
+       if (protocol != NULL && (protocol->flags & IP_FLAG_HEADER_INCLUDED)) {
                if (buffer->size < sizeof(ipv4_header))
                        return B_BAD_VALUE;
 
@@ -1551,7 +1556,7 @@
        ipv4_header& header = bufferHeader.Data();
        TRACE_ONLY(dump_ipv4_header(header));
 
-       if (header.version != IP_VERSION)
+       if (header.version != IPV4_VERSION)
                return B_BAD_TYPE;
 
        uint16 packetLength = header.TotalLength();
@@ -1585,6 +1590,7 @@
                                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);
@@ -1600,7 +1606,6 @@
        memcpy(buffer->destination, &destination, sizeof(sockaddr_in));
 
        uint8 protocol = buffer->protocol = header.protocol;
-       buffer->hoplimit = header.time_to_live;
 
        // remove any trailing/padding data
        status_t status = gBufferModule->trim(buffer, packetLength);
@@ -1625,21 +1630,15 @@
                }
        }
 
-       // 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
 
        bool rawDelivered = raw_receive_data(buffer);
 
+       // Preserve the ipv4 header for ICMP processing
+       gBufferModule->store_header(buffer);
+
        gBufferModule->remove_header(buffer, headerLength);
                // the header is of variable size and may include IP options
                // (TODO: that we ignore for now)

Modified: haiku/trunk/src/add-ons/kernel/network/protocols/ipv4/ipv4.h
===================================================================
--- haiku/trunk/src/add-ons/kernel/network/protocols/ipv4/ipv4.h        
2010-07-22 12:20:45 UTC (rev 37687)
+++ haiku/trunk/src/add-ons/kernel/network/protocols/ipv4/ipv4.h        
2010-07-22 12:26:46 UTC (rev 37688)
@@ -11,7 +11,7 @@
 #include <ByteOrder.h>
 
 
-#define IP_VERSION     4
+#define IPV4_VERSION                   4
 
 // fragment flags
 #define IP_RESERVED_FLAG               0x8000

Modified: haiku/trunk/src/add-ons/kernel/network/stack/net_buffer.cpp
===================================================================
--- haiku/trunk/src/add-ons/kernel/network/stack/net_buffer.cpp 2010-07-22 
12:20:45 UTC (rev 37687)
+++ haiku/trunk/src/add-ons/kernel/network/stack/net_buffer.cpp 2010-07-22 
12:26:46 UTC (rev 37688)
@@ -50,6 +50,7 @@
 #include <debug_paranoia.h>
 
 #define DATA_NODE_READ_ONLY            0x1
+#define DATA_NODE_STORED_HEADER        0x2
 
 struct header_space {
        uint16  size;
@@ -131,6 +132,7 @@
        data_header*                            allocation_header;
                // the current place where we allocate header space (nodes, ...)
        ancillary_data_container*       ancillary_data;
+       size_t                                          stored_header_length;
 
        struct {
                struct sockaddr_storage source;
@@ -576,11 +578,28 @@
 
 
 static void
+dump_address(const char* prefix, sockaddr* address)
+{
+       if (address == NULL || address->sa_len == 0)
+               return;
+
+       dprintf("  %s: length %u, family %u\n", prefix, address->sa_len,
+               address->sa_family);
+
+       dump_block((char*)address + 2, address->sa_len - 2, "    ");
+}
+
+
+static void
 dump_buffer(net_buffer* _buffer)
 {
        net_buffer_private* buffer = (net_buffer_private*)_buffer;
 
-       dprintf("buffer %p, size %ld\n", buffer, buffer->size);
+       dprintf("buffer %p, size %ld, flags %lx\n", buffer, buffer->size,
+               buffer->flags);
+       dump_address("source", buffer->source);
+       dump_address("destination", buffer->destination);
+
        data_node* node = NULL;
        while ((node = (data_node*)list_get_next_item(&buffer->buffers, node))
                        != NULL) {
@@ -1038,10 +1057,7 @@
        destination->interface = source->interface;
        destination->offset = source->offset;
        destination->protocol = source->protocol;
-       destination->hoplimit = source->hoplimit;
        destination->type = source->type;
-
-       destination->network_header = NULL;
 }
 
 
@@ -1077,7 +1093,7 @@
        list_add_item(&buffer->buffers, node);
 
        buffer->ancillary_data = NULL;
-       buffer->network_header = NULL;
+       buffer->stored_header_length = 0;
 
        buffer->source = (sockaddr*)&buffer->storage.source;
        buffer->destination = (sockaddr*)&buffer->storage.destination;
@@ -1120,7 +1136,6 @@
        }
 
        delete_ancillary_data_container(buffer->ancillary_data);
-       free(buffer->network_header);
 
        release_data_header(buffer->allocation_header);
 
@@ -1534,6 +1549,13 @@
                find_thread(NULL), buffer, size, node->HeaderSpace()));
        //dump_buffer(buffer);
 
+       if ((node->flags & DATA_NODE_STORED_HEADER) != 0) {
+               // throw any stored headers away
+               node->AddHeaderSpace(buffer->stored_header_length);
+               node->flags &= ~DATA_NODE_STORED_HEADER;
+               buffer->stored_header_length = 0;
+       }
+
        if (node->HeaderSpace() < size) {
                // we need to prepend new buffers
 
@@ -1791,6 +1813,7 @@
                left -= node->used;
                remove_data_node(node);
                node = NULL;
+               buffer->stored_header_length = 0;
        }
 
        // cut remaining node, if any
@@ -1799,7 +1822,10 @@
                size_t cut = min_c(node->used, left);
                node->offset = 0;
                node->start += cut;
-               node->AddHeaderSpace(cut);
+               if ((node->flags & DATA_NODE_STORED_HEADER) != 0)
+                       buffer->stored_header_length += cut;
+               else
+                       node->AddHeaderSpace(cut);
                node->used -= cut;
 
                node = (data_node*)list_get_next_item(&buffer->buffers, node);
@@ -2005,6 +2031,107 @@
 }
 
 
+/*!    Stores the current header position; even if the header is removed with
+       remove_header(), you can still reclaim it later using restore_header(),
+       unless you prepended different data (in which case restoring will fail).
+*/
+status_t
+store_header(net_buffer* _buffer)
+{
+       net_buffer_private* buffer = (net_buffer_private*)_buffer;
+       data_node* node = (data_node*)list_get_first_item(&buffer->buffers);
+       if (node == NULL)
+               return B_ERROR;
+
+       if ((node->flags & DATA_NODE_STORED_HEADER) != 0) {
+               // Someone else already stored the header - since we cannot
+               // differentiate between them, we throw away everything
+               node->AddHeaderSpace(buffer->stored_header_length);
+               node->flags &= ~DATA_NODE_STORED_HEADER;
+               buffer->stored_header_length = 0;
+
+               return B_ERROR;
+       }
+
+       buffer->stored_header_length = 0;
+       node->flags |= DATA_NODE_STORED_HEADER;
+
+       return B_OK;
+}
+
+
+ssize_t
+stored_header_length(net_buffer* _buffer)
+{
+       net_buffer_private* buffer = (net_buffer_private*)_buffer;
+       data_node* node = (data_node*)list_get_first_item(&buffer->buffers);
+       if (node == NULL || (node->flags & DATA_NODE_STORED_HEADER) == 0)
+               return B_BAD_VALUE;
+
+       return buffer->stored_header_length;
+}
+
+
+/*!    Reads from the complete buffer with an eventually stored header.
+       This function does not care whether or not there is a stored header at
+       all - you have to use the stored_header_length() function to find out.
+*/
+status_t
+restore_header(net_buffer* _buffer, uint32 offset, void* data, size_t bytes)
+{
+       net_buffer_private* buffer = (net_buffer_private*)_buffer;
+       data_node* node = (data_node*)list_get_first_item(&buffer->buffers);
+       if (node == NULL
+               || offset + bytes > buffer->stored_header_length + buffer->size)
+               return B_BAD_VALUE;
+
+       // We have the data, so copy it out
+
+       memcpy(data, node->start - buffer->stored_header_length,
+               std::min(bytes, buffer->stored_header_length));
+       
+       if (bytes <= buffer->stored_header_length)
+               return B_OK;
+
+       data = (uint8*)data + buffer->stored_header_length;
+       bytes -= buffer->stored_header_length;
+
+       return read_data(_buffer, 0, data, bytes);
+}
+
+
+/*!    Copies from the complete \a source buffer with an eventually stored 
header
+       to the specified target \a buffer.
+       This function does not care whether or not there is a stored header at
+       all - you have to use the stored_header_length() function to find out.
+*/
+status_t
+append_restored_header(net_buffer* buffer, net_buffer* _source, uint32 offset,
+       size_t bytes)
+{
+       net_buffer_private* source = (net_buffer_private*)_source;
+       data_node* node = (data_node*)list_get_first_item(&source->buffers);
+       if (node == NULL
+               || offset + bytes > source->stored_header_length + source->size)
+               return B_BAD_VALUE;
+
+       // We have the data, so copy it out
+
+       status_t status = append_data(buffer,
+               node->start - source->stored_header_length,
+               std::min(bytes, source->stored_header_length));
+       if (status != B_OK)
+               return status;
+
+       if (bytes <= source->stored_header_length)
+               return B_OK;
+
+       bytes -= source->stored_header_length;
+
+       return append_cloned_data(buffer, source, 0, bytes);
+}
+
+
 /*!    Tries to directly access the requested space in the buffer.
        If the space is contiguous, the function will succeed and place a 
pointer
        to that space into \a _contiguousBuffer.
@@ -2217,6 +2344,11 @@
        get_ancillary_data,
        transfer_ancillary_data,
 
+       store_header,
+       stored_header_length,
+       restore_header,
+       append_restored_header,
+
        direct_access,
        read_data,
        write_data,


Other related posts:

  • » [haiku-commits] r37688 - in haiku/trunk: headers/private/net src/add-ons/kernel/network/protocols/icmp src/add-ons/kernel/network/protocols/ipv4 src/add-ons/kernel/network/stack - axeld