* 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
This commit is contained in:
Axel Dörfler
2010-07-21 12:00:27 +00:00
parent f6a57629c3
commit 1978fb81ee
8 changed files with 386 additions and 105 deletions
+59
View File
@@ -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
+6 -1
View File
@@ -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
+1 -1
View File
@@ -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);
@@ -1,25 +1,8 @@
SubDir HAIKU_TOP src add-ons kernel network protocols icmp ;
SetSubDirSupportedPlatformsBeOSCompatible ;
if $(TARGET_PLATFORM) != haiku {
UseHeaders [ FStandardOSHeaders ] : true ;
# Needed for <support/Errors.h> 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 ;
@@ -7,24 +7,36 @@
*/
#include <net_datalink.h>
#include <net_protocol.h>
#include <net_stack.h>
#include <NetBufferUtilities.h>
/*! RFC 792 details the ICMP protocol, RFC 1122 lists when an ICMP error must,
shall, or must not be sent.
*/
#include <KernelExport.h>
#include <util/list.h>
#include <algorithm>
#include <netinet/in.h>
#include <new>
#include <stdlib.h>
#include <string.h>
//#define TRACE_ICMP
#include <KernelExport.h>
#include <OS.h>
#include <icmp.h>
#include <net_datalink.h>
#include <net_protocol.h>
#include <net_stack.h>
#include <NetBufferUtilities.h>
//#include <util/list.h>
#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<icmp_header> 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<icmp_header> header(reply);
NetBufferHeaderReader<icmp_header> 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<ipv4_header> 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<icmp_header> 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()
@@ -7,9 +7,11 @@
*/
#include "ipv4.h"
#include "ipv4_address.h"
#include "multicast.h"
#include <icmp.h>
#include <net_datalink.h>
#include <net_datalink_protocol.h>
#include <net_device.h>
@@ -18,7 +20,6 @@
#include <NetBufferUtilities.h>
#include <ProtocolUtilities.h>
#include <ByteOrder.h>
#include <KernelExport.h>
#include <util/AutoLock.h>
#include <util/list.h>
@@ -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<struct net_buffer,
DoublyLinkedListCLink<struct net_buffer> > 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<ipv4_header, 8> 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()
@@ -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 <netinet/in.h>
#include <ByteOrder.h>
#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
@@ -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));