xref: /haiku/src/add-ons/kernel/network/stack/net_buffer.cpp (revision b671e9bbdbd10268a042b4f4cc4317ccd03d105e)
1 /*
2  * Copyright 2006-2009, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Axel Dörfler, axeld@pinc-software.de
7  *		Ingo Weinhold, ingo_weinhold@gmx.de
8  */
9 
10 #include "utility.h"
11 
12 #include <net_buffer.h>
13 #include <slab/Slab.h>
14 #include <tracing.h>
15 #include <util/list.h>
16 
17 #include <ByteOrder.h>
18 #include <debug.h>
19 #include <KernelExport.h>
20 #include <util/DoublyLinkedList.h>
21 
22 #include <algorithm>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/param.h>
26 #include <sys/uio.h>
27 
28 #include "ancillary_data.h"
29 
30 #include "paranoia_config.h"
31 
32 
33 //#define TRACE_BUFFER
34 #ifdef TRACE_BUFFER
35 #	define TRACE(x) dprintf x
36 #else
37 #	define TRACE(x) ;
38 #endif
39 
40 #define BUFFER_SIZE 2048
41 	// maximum implementation derived buffer size is 65536
42 
43 //#define ENABLE_DEBUGGER_COMMANDS	1
44 #define PARANOID_BUFFER_CHECK	NET_BUFFER_PARANOIA
45 
46 #define COMPONENT_PARANOIA_LEVEL	NET_BUFFER_PARANOIA
47 #include <debug_paranoia.h>
48 
49 #define DATA_NODE_READ_ONLY		0x1
50 
51 struct header_space {
52 	uint16	size;
53 	uint16	free;
54 };
55 
56 struct free_data {
57 	struct free_data* next;
58 	uint16			size;
59 };
60 
61 struct data_header {
62 	int32			ref_count;
63 	addr_t			physical_address;
64 	free_data*		first_free;
65 	uint8*			data_end;
66 	header_space	space;
67 	uint16			tail_space;
68 };
69 
70 struct data_node {
71 	struct list_link link;
72 	struct data_header* header;
73 	struct data_header* located;
74 	size_t			offset;		// the net_buffer-wide offset of this node
75 	uint8*			start;		// points to the start of the data
76 	uint16			flags;
77 	uint16			used;		// defines how much memory is used by this node
78 
79 	uint16 HeaderSpace() const
80 	{
81 		if ((flags & DATA_NODE_READ_ONLY) != 0)
82 			return 0;
83 		return header->space.free;
84 	}
85 
86 	void AddHeaderSpace(uint16 toAdd)
87 	{
88 		if ((flags & DATA_NODE_READ_ONLY) == 0) {
89 			header->space.size += toAdd;
90 			header->space.free += toAdd;
91 		}
92 	}
93 
94 	void SubtractHeaderSpace(uint16 toSubtract)
95 	{
96 		if ((flags & DATA_NODE_READ_ONLY) == 0) {
97 			header->space.size -= toSubtract;
98 			header->space.free -= toSubtract;
99 		}
100 	}
101 
102 	uint16 TailSpace() const
103 	{
104 		if ((flags & DATA_NODE_READ_ONLY) != 0)
105 			return 0;
106 		return header->tail_space;
107 	}
108 
109 	void SetTailSpace(uint16 space)
110 	{
111 		if ((flags & DATA_NODE_READ_ONLY) == 0)
112 			header->tail_space = space;
113 	}
114 
115 	void FreeSpace()
116 	{
117 		if ((flags & DATA_NODE_READ_ONLY) == 0) {
118 			uint16 space = used + header->tail_space;
119 			header->space.size += space;
120 			header->space.free += space;
121 			header->tail_space = 0;
122 		}
123 	}
124 };
125 
126 struct net_buffer_private : net_buffer {
127 	struct list					buffers;
128 	data_header*				allocation_header;
129 		// the current place where we allocate header space (nodes, ...)
130 	ancillary_data_container*	ancillary_data;
131 
132 	struct {
133 		struct sockaddr_storage	source;
134 		struct sockaddr_storage	destination;
135 	} storage;
136 };
137 
138 
139 #define DATA_HEADER_SIZE				_ALIGN(sizeof(data_header))
140 #define DATA_NODE_SIZE					_ALIGN(sizeof(data_node))
141 #define MAX_FREE_BUFFER_SIZE			(BUFFER_SIZE - DATA_HEADER_SIZE)
142 
143 
144 static object_cache* sNetBufferCache;
145 static object_cache* sDataNodeCache;
146 
147 
148 static status_t append_data(net_buffer* buffer, const void* data, size_t size);
149 static status_t trim_data(net_buffer* _buffer, size_t newSize);
150 static status_t remove_header(net_buffer* _buffer, size_t bytes);
151 static status_t remove_trailer(net_buffer* _buffer, size_t bytes);
152 static status_t append_cloned_data(net_buffer* _buffer, net_buffer* _source,
153 					uint32 offset, size_t bytes);
154 static status_t read_data(net_buffer* _buffer, size_t offset, void* data,
155 					size_t size);
156 
157 
158 #if ENABLE_DEBUGGER_COMMANDS
159 static vint32 sAllocatedDataHeaderCount = 0;
160 static vint32 sAllocatedNetBufferCount = 0;
161 static vint32 sEverAllocatedDataHeaderCount = 0;
162 static vint32 sEverAllocatedNetBufferCount = 0;
163 #endif
164 
165 
166 #if NET_BUFFER_TRACING
167 
168 
169 namespace NetBufferTracing {
170 
171 
172 class NetBufferTraceEntry : public AbstractTraceEntry {
173 public:
174 	NetBufferTraceEntry(net_buffer* buffer)
175 		:
176 		fBuffer(buffer)
177 	{
178 #if NET_BUFFER_TRACING_STACK_TRACE
179 	fStackTrace = capture_tracing_stack_trace(
180 		NET_BUFFER_TRACING_STACK_TRACE, 0, false);
181 #endif
182 	}
183 
184 #if NET_BUFFER_TRACING_STACK_TRACE
185 	virtual void DumpStackTrace(TraceOutput& out)
186 	{
187 		out.PrintStackTrace(fStackTrace);
188 	}
189 #endif
190 
191 protected:
192 	net_buffer*	fBuffer;
193 #if NET_BUFFER_TRACING_STACK_TRACE
194 	tracing_stack_trace* fStackTrace;
195 #endif
196 };
197 
198 
199 class Create : public NetBufferTraceEntry {
200 public:
201 	Create(size_t headerSpace, net_buffer* buffer)
202 		:
203 		NetBufferTraceEntry(buffer),
204 		fHeaderSpace(headerSpace)
205 	{
206 		Initialized();
207 	}
208 
209 	virtual void AddDump(TraceOutput& out)
210 	{
211 		out.Print("net buffer create: header space: %lu -> buffer: %p",
212 			fHeaderSpace, fBuffer);
213 	}
214 
215 private:
216 	size_t		fHeaderSpace;
217 };
218 
219 
220 class Free : public NetBufferTraceEntry {
221 public:
222 	Free(net_buffer* buffer)
223 		:
224 		NetBufferTraceEntry(buffer)
225 	{
226 		Initialized();
227 	}
228 
229 	virtual void AddDump(TraceOutput& out)
230 	{
231 		out.Print("net buffer free: buffer: %p", fBuffer);
232 	}
233 };
234 
235 
236 class Duplicate : public NetBufferTraceEntry {
237 public:
238 	Duplicate(net_buffer* buffer, net_buffer* clone)
239 		:
240 		NetBufferTraceEntry(buffer),
241 		fClone(clone)
242 	{
243 		Initialized();
244 	}
245 
246 	virtual void AddDump(TraceOutput& out)
247 	{
248 		out.Print("net buffer dup: buffer: %p -> %p", fBuffer, fClone);
249 	}
250 
251 private:
252 	net_buffer*		fClone;
253 };
254 
255 
256 class Clone : public NetBufferTraceEntry {
257 public:
258 	Clone(net_buffer* buffer, bool shareFreeSpace, net_buffer* clone)
259 		:
260 		NetBufferTraceEntry(buffer),
261 		fClone(clone),
262 		fShareFreeSpace(shareFreeSpace)
263 	{
264 		Initialized();
265 	}
266 
267 	virtual void AddDump(TraceOutput& out)
268 	{
269 		out.Print("net buffer clone: buffer: %p, share free space: %s "
270 			"-> %p", fBuffer, fShareFreeSpace ? "true" : "false", fClone);
271 	}
272 
273 private:
274 	net_buffer*		fClone;
275 	bool			fShareFreeSpace;
276 };
277 
278 
279 class Split : public NetBufferTraceEntry {
280 public:
281 	Split(net_buffer* buffer, uint32 offset, net_buffer* newBuffer)
282 		:
283 		NetBufferTraceEntry(buffer),
284 		fNewBuffer(newBuffer),
285 		fOffset(offset)
286 	{
287 		Initialized();
288 	}
289 
290 	virtual void AddDump(TraceOutput& out)
291 	{
292 		out.Print("net buffer split: buffer: %p, offset: %lu "
293 			"-> %p", fBuffer, fOffset, fNewBuffer);
294 	}
295 
296 private:
297 	net_buffer*		fNewBuffer;
298 	uint32			fOffset;
299 };
300 
301 
302 class Merge : public NetBufferTraceEntry {
303 public:
304 	Merge(net_buffer* buffer, net_buffer* otherBuffer, bool after)
305 		:
306 		NetBufferTraceEntry(buffer),
307 		fOtherBuffer(otherBuffer),
308 		fAfter(after)
309 	{
310 		Initialized();
311 	}
312 
313 	virtual void AddDump(TraceOutput& out)
314 	{
315 		out.Print("net buffer merge: buffers: %p + %p, after: %s "
316 			"-> %p", fBuffer, fOtherBuffer, fAfter ? "true" : "false",
317 			fOtherBuffer);
318 	}
319 
320 private:
321 	net_buffer*		fOtherBuffer;
322 	bool			fAfter;
323 };
324 
325 
326 class AppendCloned : public NetBufferTraceEntry {
327 public:
328 	AppendCloned(net_buffer* buffer, net_buffer* source, uint32 offset,
329 		size_t size)
330 		:
331 		NetBufferTraceEntry(buffer),
332 		fSource(source),
333 		fOffset(offset),
334 		fSize(size)
335 	{
336 		Initialized();
337 	}
338 
339 	virtual void AddDump(TraceOutput& out)
340 	{
341 		out.Print("net buffer append cloned: buffer: %p, from: %p, "
342 			"offset: %lu, size: %lu", fBuffer, fSource, fOffset, fSize);
343 	}
344 
345 private:
346 	net_buffer*		fSource;
347 	uint32			fOffset;
348 	size_t			fSize;
349 };
350 
351 
352 class PrependSize : public NetBufferTraceEntry {
353 public:
354 	PrependSize(net_buffer* buffer, size_t size)
355 		:
356 		NetBufferTraceEntry(buffer),
357 		fSize(size)
358 	{
359 		Initialized();
360 	}
361 
362 	virtual void AddDump(TraceOutput& out)
363 	{
364 		out.Print("net buffer prepend size: buffer: %p, size: %lu", fBuffer,
365 			fSize);
366 	}
367 
368 private:
369 	size_t			fSize;
370 };
371 
372 
373 class AppendSize : public NetBufferTraceEntry {
374 public:
375 	AppendSize(net_buffer* buffer, size_t size)
376 		:
377 		NetBufferTraceEntry(buffer),
378 		fSize(size)
379 	{
380 		Initialized();
381 	}
382 
383 	virtual void AddDump(TraceOutput& out)
384 	{
385 		out.Print("net buffer append size: buffer: %p, size: %lu", fBuffer,
386 			fSize);
387 	}
388 
389 private:
390 	size_t			fSize;
391 };
392 
393 
394 class RemoveHeader : public NetBufferTraceEntry {
395 public:
396 	RemoveHeader(net_buffer* buffer, size_t size)
397 		:
398 		NetBufferTraceEntry(buffer),
399 		fSize(size)
400 	{
401 		Initialized();
402 	}
403 
404 	virtual void AddDump(TraceOutput& out)
405 	{
406 		out.Print("net buffer remove header: buffer: %p, size: %lu",
407 			fBuffer, fSize);
408 	}
409 
410 private:
411 	size_t			fSize;
412 };
413 
414 
415 class Trim : public NetBufferTraceEntry {
416 public:
417 	Trim(net_buffer* buffer, size_t size)
418 		:
419 		NetBufferTraceEntry(buffer),
420 		fSize(size)
421 	{
422 		Initialized();
423 	}
424 
425 	virtual void AddDump(TraceOutput& out)
426 	{
427 		out.Print("net buffer trim: buffer: %p, size: %lu",
428 			fBuffer, fSize);
429 	}
430 
431 private:
432 	size_t			fSize;
433 };
434 
435 
436 class Read : public NetBufferTraceEntry {
437 public:
438 	Read(net_buffer* buffer, uint32 offset, void* data, size_t size)
439 		:
440 		NetBufferTraceEntry(buffer),
441 		fData(data),
442 		fOffset(offset),
443 		fSize(size)
444 	{
445 		Initialized();
446 	}
447 
448 	virtual void AddDump(TraceOutput& out)
449 	{
450 		out.Print("net buffer read: buffer: %p, offset: %lu, size: %lu, "
451 			"data: %p", fBuffer, fOffset, fSize, fData);
452 	}
453 
454 private:
455 	void*			fData;
456 	uint32			fOffset;
457 	size_t			fSize;
458 };
459 
460 
461 class Write : public NetBufferTraceEntry {
462 public:
463 	Write(net_buffer* buffer, uint32 offset, const void* data, size_t size)
464 		:
465 		NetBufferTraceEntry(buffer),
466 		fData(data),
467 		fOffset(offset),
468 		fSize(size)
469 	{
470 		Initialized();
471 	}
472 
473 	virtual void AddDump(TraceOutput& out)
474 	{
475 		out.Print("net buffer write: buffer: %p, offset: %lu, size: %lu, "
476 			"data: %p", fBuffer, fOffset, fSize, fData);
477 	}
478 
479 private:
480 	const void*		fData;
481 	uint32			fOffset;
482 	size_t			fSize;
483 };
484 
485 
486 #if NET_BUFFER_TRACING >= 2
487 
488 class DataHeaderTraceEntry : public AbstractTraceEntry {
489 public:
490 	DataHeaderTraceEntry(data_header* header)
491 		:
492 		fHeader(header)
493 	{
494 	}
495 
496 protected:
497 	data_header*	fHeader;
498 };
499 
500 
501 class CreateDataHeader : public DataHeaderTraceEntry {
502 public:
503 	CreateDataHeader(data_header* header)
504 		:
505 		DataHeaderTraceEntry(header)
506 	{
507 		Initialized();
508 	}
509 
510 	virtual void AddDump(TraceOutput& out)
511 	{
512 		out.Print("net buffer data header create:  header: %p", fHeader);
513 	}
514 };
515 
516 
517 class AcquireDataHeader : public DataHeaderTraceEntry {
518 public:
519 	AcquireDataHeader(data_header* header, int32 refCount)
520 		:
521 		DataHeaderTraceEntry(header),
522 		fRefCount(refCount)
523 	{
524 		Initialized();
525 	}
526 
527 	virtual void AddDump(TraceOutput& out)
528 	{
529 		out.Print("net buffer data header acquire: header: %p "
530 			"-> ref count: %ld", fHeader, fRefCount);
531 	}
532 
533 private:
534 	int32			fRefCount;
535 };
536 
537 
538 class ReleaseDataHeader : public DataHeaderTraceEntry {
539 public:
540 	ReleaseDataHeader(data_header* header, int32 refCount)
541 		:
542 		DataHeaderTraceEntry(header),
543 		fRefCount(refCount)
544 	{
545 		Initialized();
546 	}
547 
548 	virtual void AddDump(TraceOutput& out)
549 	{
550 		out.Print("net buffer data header release: header: %p "
551 			"-> ref count: %ld", fHeader, fRefCount);
552 	}
553 
554 private:
555 	int32			fRefCount;
556 };
557 
558 #	define T2(x)	new(std::nothrow) NetBufferTracing::x
559 #else
560 #	define T2(x)
561 #endif	// NET_BUFFER_TRACING >= 2
562 
563 }	// namespace NetBufferTracing
564 
565 #	define T(x)	new(std::nothrow) NetBufferTracing::x
566 
567 #else
568 #	define T(x)
569 #	define T2(x)
570 #endif	// NET_BUFFER_TRACING
571 
572 
573 #if 1
574 static void
575 dump_buffer(net_buffer* _buffer)
576 {
577 	net_buffer_private* buffer = (net_buffer_private*)_buffer;
578 
579 	dprintf("buffer %p, size %ld\n", buffer, buffer->size);
580 	data_node* node = NULL;
581 	while ((node = (data_node*)list_get_next_item(&buffer->buffers, node))
582 			!= NULL) {
583 		dprintf("  node %p, offset %lu, used %u, header %u, tail %u, "
584 			"header %p\n", node, node->offset, node->used, node->HeaderSpace(),
585 			node->TailSpace(), node->header);
586 		//dump_block((char*)node->start, node->used, "    ");
587 		dump_block((char*)node->start, min_c(node->used, 32), "    ");
588 	}
589 }
590 #endif
591 
592 
593 #if ENABLE_DEBUGGER_COMMANDS
594 
595 static int
596 dump_net_buffer_stats(int argc, char** argv)
597 {
598 	kprintf("allocated data headers: %7ld / %7ld\n", sAllocatedDataHeaderCount,
599 		sEverAllocatedDataHeaderCount);
600 	kprintf("allocated net buffers:  %7ld / %7ld\n", sAllocatedNetBufferCount,
601 		sEverAllocatedNetBufferCount);
602 	return 0;
603 }
604 
605 #endif	// ENABLE_DEBUGGER_COMMANDS
606 
607 
608 #if PARANOID_BUFFER_CHECK
609 
610 static void
611 check_buffer(net_buffer* _buffer)
612 {
613 	net_buffer_private* buffer = (net_buffer_private*)_buffer;
614 
615 	// sum up the size of all nodes
616 	size_t size = 0;
617 
618 	data_node* node = (data_node*)list_get_first_item(&buffer->buffers);
619 	while (node != NULL) {
620 		if (node->offset != size) {
621 			panic("net_buffer %p: bad node %p offset (%lu vs. %lu)",
622 				buffer, node, node->offset, size);
623 			return;
624 		}
625 		size += node->used;
626 		node = (data_node*)list_get_next_item(&buffer->buffers, node);
627 	}
628 
629 	if (size != buffer->size) {
630 		panic("net_buffer %p size != sum of its data node sizes (%lu vs. %lu)",
631 			buffer, buffer->size, size);
632 		return;
633 	}
634 }
635 
636 
637 #if 0
638 static void
639 check_buffer_contents(net_buffer* buffer, size_t offset, const void* data,
640 	size_t size)
641 {
642 	void* bufferData = malloc(size);
643 	if (bufferData == NULL)
644 		return;
645 
646 	if (read_data(buffer, offset, bufferData, size) == B_OK) {
647 		if (memcmp(bufferData, data, size) != 0) {
648 			int32 index = 0;
649 			while (((uint8*)data)[index] == ((uint8*)bufferData)[index])
650 				index++;
651 			panic("check_buffer_contents(): contents check failed at index "
652 				"%ld, buffer: %p, offset: %lu, size: %lu", index, buffer,
653 				offset, size);
654 		}
655 	} else {
656 		panic("failed to read from buffer %p, offset: %lu, size: %lu",
657 			buffer, offset, size);
658 	}
659 
660 	free(bufferData);
661 }
662 
663 
664 static void
665 check_buffer_contents(net_buffer* buffer, size_t offset, net_buffer* source,
666 	size_t sourceOffset, size_t size)
667 {
668 	void* bufferData = malloc(size);
669 	if (bufferData == NULL)
670 		return;
671 
672 	if (read_data(source, sourceOffset, bufferData, size) == B_OK) {
673 		check_buffer_contents(buffer, offset, bufferData, size);
674 	} else {
675 		panic("failed to read from source buffer %p, offset: %lu, size: %lu",
676 			source, sourceOffset, size);
677 	}
678 
679 	free(bufferData);
680 }
681 #endif
682 
683 
684 # 	define CHECK_BUFFER(buffer)	check_buffer(buffer)
685 #else
686 # 	define CHECK_BUFFER(buffer)	do {} while (false)
687 #endif	// !PARANOID_BUFFER_CHECK
688 
689 
690 static inline data_header*
691 allocate_data_header()
692 {
693 #if ENABLE_DEBUGGER_COMMANDS
694 	atomic_add(&sAllocatedDataHeaderCount, 1);
695 	atomic_add(&sEverAllocatedDataHeaderCount, 1);
696 #endif
697 	return (data_header*)object_cache_alloc(sDataNodeCache, CACHE_DONT_SLEEP);
698 }
699 
700 
701 static inline net_buffer_private*
702 allocate_net_buffer()
703 {
704 #if ENABLE_DEBUGGER_COMMANDS
705 	atomic_add(&sAllocatedNetBufferCount, 1);
706 	atomic_add(&sEverAllocatedNetBufferCount, 1);
707 #endif
708 	return (net_buffer_private*)object_cache_alloc(sNetBufferCache,
709 		CACHE_DONT_SLEEP);
710 }
711 
712 
713 static inline void
714 free_data_header(data_header* header)
715 {
716 #if ENABLE_DEBUGGER_COMMANDS
717 	if (header != NULL)
718 		atomic_add(&sAllocatedDataHeaderCount, -1);
719 #endif
720 	object_cache_free(sDataNodeCache, header);
721 }
722 
723 
724 static inline void
725 free_net_buffer(net_buffer_private* buffer)
726 {
727 #if ENABLE_DEBUGGER_COMMANDS
728 	if (buffer != NULL)
729 		atomic_add(&sAllocatedNetBufferCount, -1);
730 #endif
731 	object_cache_free(sNetBufferCache, buffer);
732 }
733 
734 
735 static data_header*
736 create_data_header(size_t headerSpace)
737 {
738 	data_header* header = allocate_data_header();
739 	if (header == NULL)
740 		return NULL;
741 
742 	header->ref_count = 1;
743 	header->physical_address = 0;
744 		// TODO: initialize this correctly
745 	header->space.size = headerSpace;
746 	header->space.free = headerSpace;
747 	header->data_end = (uint8*)header + DATA_HEADER_SIZE;
748 	header->tail_space = (uint8*)header + BUFFER_SIZE - header->data_end
749 		- headerSpace;
750 	header->first_free = NULL;
751 
752 	TRACE(("%ld:   create new data header %p\n", find_thread(NULL), header));
753 	T2(CreateDataHeader(header));
754 	return header;
755 }
756 
757 
758 static void
759 release_data_header(data_header* header)
760 {
761 	int32 refCount = atomic_add(&header->ref_count, -1);
762 	T2(ReleaseDataHeader(header, refCount - 1));
763 	if (refCount != 1)
764 		return;
765 
766 	TRACE(("%ld:   free header %p\n", find_thread(NULL), header));
767 	free_data_header(header);
768 }
769 
770 
771 inline void
772 acquire_data_header(data_header* header)
773 {
774 	int32 refCount = atomic_add(&header->ref_count, 1);
775 	(void)refCount;
776 	T2(AcquireDataHeader(header, refCount + 1));
777 }
778 
779 
780 static void
781 free_data_header_space(data_header* header, uint8* data, size_t size)
782 {
783 	if (size < sizeof(free_data))
784 		size = sizeof(free_data);
785 
786 	free_data* freeData = (free_data*)data;
787 	freeData->next = header->first_free;
788 	freeData->size = size;
789 
790 	header->first_free = freeData;
791 }
792 
793 
794 /*!	Tries to allocate \a size bytes from the free space in the header.
795 */
796 static uint8*
797 alloc_data_header_space(data_header* header, size_t size)
798 {
799 	if (size < sizeof(free_data))
800 		size = sizeof(free_data);
801 	size = _ALIGN(size);
802 
803 	if (header->first_free != NULL && header->first_free->size >= size) {
804 		// the first entry of the header space matches the allocation's needs
805 
806 		// TODO: If the free space is greater than what shall be allocated, we
807 		// leak the remainder of the space. We should only allocate multiples of
808 		// _ALIGN(sizeof(free_data)) and split free space in this case. It's not
809 		// that pressing, since the only thing allocated ATM are data_nodes, and
810 		// thus the free space entries will always have the right size.
811 		uint8* data = (uint8*)header->first_free;
812 		header->first_free = header->first_free->next;
813 		return data;
814 	}
815 
816 	if (header->space.free < size) {
817 		// there is no free space left, search free list
818 		free_data* freeData = header->first_free;
819 		free_data* last = NULL;
820 		while (freeData != NULL) {
821 			if (last != NULL && freeData->size >= size) {
822 				// take this one
823 				last->next = freeData->next;
824 				return (uint8*)freeData;
825 			}
826 
827 			last = freeData;
828 			freeData = freeData->next;
829 		}
830 
831 		return NULL;
832 	}
833 
834 	// allocate new space
835 
836 	uint8* data = header->data_end;
837 	header->data_end += size;
838 	header->space.free -= size;
839 
840 	return data;
841 }
842 
843 
844 static uint8*
845 alloc_data_header_space(net_buffer_private* buffer, size_t size,
846 	data_header** _header = NULL)
847 {
848 	// try to allocate in our current allocation header
849 	uint8* allocated = alloc_data_header_space(buffer->allocation_header, size);
850 	if (allocated == NULL) {
851 		// not enough header space left -- create a fresh buffer for headers
852 		data_header* header = create_data_header(MAX_FREE_BUFFER_SIZE);
853 		if (header == NULL)
854 			return NULL;
855 
856 		// release our reference to the old header -- it will will stay around
857 		// until the last reference to it is released
858 		release_data_header(buffer->allocation_header);
859 		buffer->allocation_header = header;
860 			// We keep the initial reference.
861 
862 		// now the allocation can only fail, if size is too big
863 		allocated = alloc_data_header_space(buffer->allocation_header, size);
864 	}
865 
866 	if (_header != NULL)
867 		*_header = buffer->allocation_header;
868 
869 	return allocated;
870 }
871 
872 
873 static data_node*
874 add_first_data_node(data_header* header)
875 {
876 	data_node* node = (data_node*)alloc_data_header_space(header,
877 		sizeof(data_node));
878 	if (node == NULL)
879 		return NULL;
880 
881 	TRACE(("%ld:   add first data node %p to header %p\n", find_thread(NULL),
882 		node, header));
883 
884 	acquire_data_header(header);
885 
886 	memset(node, 0, sizeof(struct data_node));
887 	node->located = header;
888 	node->header = header;
889 	node->offset = 0;
890 	node->start = header->data_end + header->space.free;
891 	node->used = 0;
892 	node->flags = 0;
893 
894 	return node;
895 }
896 
897 
898 static data_node*
899 add_data_node(net_buffer_private* buffer, data_header* header)
900 {
901 	data_header* located;
902 	data_node* node = (data_node*)alloc_data_header_space(buffer,
903 		sizeof(data_node), &located);
904 	if (node == NULL)
905 		return NULL;
906 
907 	TRACE(("%ld:   add data node %p to header %p\n", find_thread(NULL), node,
908 		header));
909 
910 	acquire_data_header(header);
911 	if (located != header)
912 		acquire_data_header(located);
913 
914 	memset(node, 0, sizeof(struct data_node));
915 	node->located = located;
916 	node->header = header;
917 	node->flags = 0;
918 	return node;
919 }
920 
921 
922 void
923 remove_data_node(data_node* node)
924 {
925 	data_header* located = node->located;
926 
927 	TRACE(("%ld:   remove data node %p from header %p (located %p)\n",
928 		find_thread(NULL), node, node->header, located));
929 
930 	// Move all used and tail space to the header space, which is useful in case
931 	// this is the first node of a buffer (i.e. the header is an allocation
932 	// header).
933 	node->FreeSpace();
934 
935 	if (located != node->header)
936 		release_data_header(node->header);
937 
938 	if (located == NULL)
939 		return;
940 
941 	free_data_header_space(located, (uint8*)node, sizeof(data_node));
942 
943 	release_data_header(located);
944 }
945 
946 
947 static inline data_node*
948 get_node_at_offset(net_buffer_private* buffer, size_t offset)
949 {
950 	data_node* node = (data_node*)list_get_first_item(&buffer->buffers);
951 	while (node->offset + node->used <= offset) {
952 		node = (data_node*)list_get_next_item(&buffer->buffers, node);
953 		if (node == NULL)
954 			return NULL;
955 	}
956 
957 	return node;
958 }
959 
960 
961 /*!	Appends up to \a size bytes from the data of the \a from net_buffer to the
962 	\a to net_buffer. The source buffer will remain unchanged.
963 */
964 static status_t
965 append_data_from_buffer(net_buffer* to, const net_buffer* from, size_t size)
966 {
967 	net_buffer_private* source = (net_buffer_private*)from;
968 	net_buffer_private* dest = (net_buffer_private*)to;
969 
970 	if (size > from->size)
971 		return B_BAD_VALUE;
972 	if (size == 0)
973 		return B_OK;
974 
975 	data_node* nodeTo = get_node_at_offset(source, size);
976 	if (nodeTo == NULL)
977 		return B_BAD_VALUE;
978 
979 	data_node* node = (data_node*)list_get_first_item(&source->buffers);
980 	if (node == NULL) {
981 		CHECK_BUFFER(source);
982 		return B_ERROR;
983 	}
984 
985 	while (node != nodeTo) {
986 		if (append_data(dest, node->start, node->used) < B_OK) {
987 			CHECK_BUFFER(dest);
988 			return B_ERROR;
989 		}
990 
991 		node = (data_node*)list_get_next_item(&source->buffers, node);
992 	}
993 
994 	int32 diff = node->offset + node->used - size;
995 	if (append_data(dest, node->start, node->used - diff) < B_OK) {
996 		CHECK_BUFFER(dest);
997 		return B_ERROR;
998 	}
999 
1000 	CHECK_BUFFER(dest);
1001 
1002 	return B_OK;
1003 }
1004 
1005 
1006 static void
1007 copy_metadata(net_buffer* destination, const net_buffer* source)
1008 {
1009 	memcpy(destination->source, source->source,
1010 		min_c(source->source->sa_len, sizeof(sockaddr_storage)));
1011 	memcpy(destination->destination, source->destination,
1012 		min_c(source->destination->sa_len, sizeof(sockaddr_storage)));
1013 
1014 	destination->flags = source->flags;
1015 	destination->interface = source->interface;
1016 	destination->offset = source->offset;
1017 	destination->size = source->size;
1018 	destination->protocol = source->protocol;
1019 	destination->type = source->type;
1020 }
1021 
1022 
1023 //	#pragma mark - module API
1024 
1025 
1026 static net_buffer*
1027 create_buffer(size_t headerSpace)
1028 {
1029 	net_buffer_private* buffer = allocate_net_buffer();
1030 	if (buffer == NULL)
1031 		return NULL;
1032 
1033 	TRACE(("%ld: create buffer %p\n", find_thread(NULL), buffer));
1034 
1035 	// Make sure headerSpace is valid and at least the initial node fits.
1036 	headerSpace = _ALIGN(headerSpace);
1037 	if (headerSpace < DATA_NODE_SIZE)
1038 		headerSpace = DATA_NODE_SIZE;
1039 	else if (headerSpace > MAX_FREE_BUFFER_SIZE)
1040 		headerSpace = MAX_FREE_BUFFER_SIZE;
1041 
1042 	data_header* header = create_data_header(headerSpace);
1043 	if (header == NULL) {
1044 		free_net_buffer(buffer);
1045 		return NULL;
1046 	}
1047 	buffer->allocation_header = header;
1048 
1049 	data_node* node = add_first_data_node(header);
1050 
1051 	list_init(&buffer->buffers);
1052 	list_add_item(&buffer->buffers, node);
1053 
1054 	buffer->ancillary_data = NULL;
1055 
1056 	buffer->source = (sockaddr*)&buffer->storage.source;
1057 	buffer->destination = (sockaddr*)&buffer->storage.destination;
1058 
1059 	buffer->storage.source.ss_len = 0;
1060 	buffer->storage.destination.ss_len = 0;
1061 
1062 	buffer->interface = NULL;
1063 	buffer->offset = 0;
1064 	buffer->flags = 0;
1065 	buffer->size = 0;
1066 
1067 	buffer->type = -1;
1068 
1069 	CHECK_BUFFER(buffer);
1070 	CREATE_PARANOIA_CHECK_SET(buffer, "net_buffer");
1071 	SET_PARANOIA_CHECK(PARANOIA_SUSPICIOUS, buffer, &buffer->size,
1072 		sizeof(buffer->size));
1073 
1074 	T(Create(headerSpace, buffer));
1075 
1076 	return buffer;
1077 }
1078 
1079 
1080 static void
1081 free_buffer(net_buffer* _buffer)
1082 {
1083 	net_buffer_private* buffer = (net_buffer_private*)_buffer;
1084 
1085 	TRACE(("%ld: free buffer %p\n", find_thread(NULL), buffer));
1086 	T(Free(buffer));
1087 
1088 	CHECK_BUFFER(buffer);
1089 	DELETE_PARANOIA_CHECK_SET(buffer);
1090 
1091 	while (data_node* node
1092 			= (data_node*)list_remove_head_item(&buffer->buffers)) {
1093 		remove_data_node(node);
1094 	}
1095 
1096 	delete_ancillary_data_container(buffer->ancillary_data);
1097 
1098 	release_data_header(buffer->allocation_header);
1099 
1100 	free_net_buffer(buffer);
1101 }
1102 
1103 
1104 /*!	Creates a duplicate of the \a buffer. The new buffer does not share internal
1105 	storage; they are completely independent from each other.
1106 */
1107 static net_buffer*
1108 duplicate_buffer(net_buffer* _buffer)
1109 {
1110 	net_buffer_private* buffer = (net_buffer_private*)_buffer;
1111 
1112 	ParanoiaChecker _(buffer);
1113 
1114 	TRACE(("%ld: duplicate_buffer(buffer %p)\n", find_thread(NULL), buffer));
1115 
1116 	// TODO: We might want to choose a better header space. The minimal
1117 	// one doesn't allow to prepend any data without allocating a new header.
1118 	// The same holds for appending cloned data.
1119 	net_buffer* duplicate = create_buffer(DATA_NODE_SIZE);
1120 	if (duplicate == NULL)
1121 		return NULL;
1122 
1123 	TRACE(("%ld:   duplicate: %p)\n", find_thread(NULL), duplicate));
1124 
1125 	// copy the data from the source buffer
1126 
1127 	data_node* node = (data_node*)list_get_first_item(&buffer->buffers);
1128 	while (node != NULL) {
1129 		if (append_data(duplicate, node->start, node->used) < B_OK) {
1130 			free_buffer(duplicate);
1131 			CHECK_BUFFER(buffer);
1132 			return NULL;
1133 		}
1134 
1135 		node = (data_node*)list_get_next_item(&buffer->buffers, node);
1136 	}
1137 
1138 	copy_metadata(duplicate, buffer);
1139 
1140 	CHECK_BUFFER(buffer);
1141 	CHECK_BUFFER(duplicate);
1142 	RUN_PARANOIA_CHECKS(duplicate);
1143 
1144 	T(Duplicate(buffer, duplicate));
1145 
1146 	return duplicate;
1147 }
1148 
1149 
1150 /*!	Clones the buffer by grabbing another reference to the underlying data.
1151 	If that data changes, it will be changed in the clone as well.
1152 
1153 	If \a shareFreeSpace is \c true, the cloned buffer may claim the free
1154 	space in the original buffer as the original buffer can still do. If you
1155 	are using this, it's your responsibility that only one of the buffers
1156 	will do this.
1157 */
1158 static net_buffer*
1159 clone_buffer(net_buffer* _buffer, bool shareFreeSpace)
1160 {
1161 	// TODO: See, if the commented out code can be fixed in a safe way. We could
1162 	// probably place cloned nodes on a header not belonging to our buffer, if
1163 	// we don't free the header space for the node when removing it. Otherwise we
1164 	// mess with the header's free list which might at the same time be accessed
1165 	// by another thread.
1166 	net_buffer_private* buffer = (net_buffer_private*)_buffer;
1167 
1168 	net_buffer* clone = create_buffer(MAX_FREE_BUFFER_SIZE);
1169 	if (clone == NULL)
1170 		return NULL;
1171 
1172 	if (append_cloned_data(clone, buffer, 0, buffer->size) != B_OK) {
1173 		free_buffer(clone);
1174 		return NULL;
1175 	}
1176 
1177 	copy_metadata(clone, buffer);
1178 
1179 	return clone;
1180 
1181 #if 0
1182 	ParanoiaChecker _(buffer);
1183 
1184 	TRACE(("%ld: clone_buffer(buffer %p)\n", find_thread(NULL), buffer));
1185 
1186 	net_buffer_private* clone = allocate_net_buffer();
1187 	if (clone == NULL)
1188 		return NULL;
1189 
1190 	TRACE(("%ld:   clone: %p\n", find_thread(NULL), buffer));
1191 
1192 	data_node* sourceNode = (data_node*)list_get_first_item(&buffer->buffers);
1193 	if (sourceNode == NULL) {
1194 		free_net_buffer(clone);
1195 		return NULL;
1196 	}
1197 
1198 	clone->source = (sockaddr*)&clone->storage.source;
1199 	clone->destination = (sockaddr*)&clone->storage.destination;
1200 
1201 	list_init(&clone->buffers);
1202 
1203 	// grab reference to this buffer - all additional nodes will get
1204 	// theirs in add_data_node()
1205 	acquire_data_header(sourceNode->header);
1206 	data_node* node = &clone->first_node;
1207 	node->header = sourceNode->header;
1208 	node->located = NULL;
1209 	node->used_header_space = &node->own_header_space;
1210 
1211 	while (sourceNode != NULL) {
1212 		node->start = sourceNode->start;
1213 		node->used = sourceNode->used;
1214 		node->offset = sourceNode->offset;
1215 
1216 		if (shareFreeSpace) {
1217 			// both buffers could claim the free space - note that this option
1218 			// has to be used carefully
1219 			node->used_header_space = &sourceNode->header->space;
1220 			node->tail_space = sourceNode->tail_space;
1221 		} else {
1222 			// the free space stays with the original buffer
1223 			node->used_header_space->size = 0;
1224 			node->used_header_space->free = 0;
1225 			node->tail_space = 0;
1226 		}
1227 
1228 		// add node to clone's list of buffers
1229 		list_add_item(&clone->buffers, node);
1230 
1231 		sourceNode = (data_node*)list_get_next_item(&buffer->buffers,
1232 			sourceNode);
1233 		if (sourceNode == NULL)
1234 			break;
1235 
1236 		node = add_data_node(sourceNode->header);
1237 		if (node == NULL) {
1238 			// There was not enough space left for another node in this buffer
1239 			// TODO: handle this case!
1240 			panic("clone buffer hits size limit... (fix me)");
1241 			free_net_buffer(clone);
1242 			return NULL;
1243 		}
1244 	}
1245 
1246 	copy_metadata(clone, buffer);
1247 
1248 	CREATE_PARANOIA_CHECK_SET(clone, "net_buffer");
1249 	SET_PARANOIA_CHECK(PARANOIA_SUSPICIOUS, clone, &clone->size,
1250 		sizeof(clone->size));
1251 	CHECK_BUFFER(buffer);
1252 	CHECK_BUFFER(clone);
1253 
1254 	T(Clone(buffer, shareFreeSpace, clone));
1255 
1256 	return clone;
1257 #endif
1258 }
1259 
1260 
1261 /*!	Split the buffer at offset, the header data
1262 	is returned as new buffer.
1263 */
1264 static net_buffer*
1265 split_buffer(net_buffer* from, uint32 offset)
1266 {
1267 	net_buffer* buffer = create_buffer(DATA_NODE_SIZE);
1268 	if (buffer == NULL)
1269 		return NULL;
1270 
1271 	copy_metadata(buffer, from);
1272 
1273 	ParanoiaChecker _(from);
1274 	ParanoiaChecker _2(buffer);
1275 
1276 	TRACE(("%ld: split_buffer(buffer %p -> %p, offset %ld)\n",
1277 		find_thread(NULL), from, buffer, offset));
1278 
1279 	if (append_data_from_buffer(buffer, from, offset) == B_OK) {
1280 		if (remove_header(from, offset) == B_OK) {
1281 			CHECK_BUFFER(from);
1282 			CHECK_BUFFER(buffer);
1283 			T(Split(from, offset, buffer));
1284 			return buffer;
1285 		}
1286 	}
1287 
1288 	free_buffer(buffer);
1289 	CHECK_BUFFER(from);
1290 	return NULL;
1291 }
1292 
1293 
1294 /*!	Merges the second buffer with the first. If \a after is \c true, the
1295 	second buffer's contents will be appended to the first ones, else they
1296 	will be prepended.
1297 	The second buffer will be freed if this function succeeds.
1298 */
1299 static status_t
1300 merge_buffer(net_buffer* _buffer, net_buffer* _with, bool after)
1301 {
1302 	net_buffer_private* buffer = (net_buffer_private*)_buffer;
1303 	net_buffer_private* with = (net_buffer_private*)_with;
1304 	if (with == NULL)
1305 		return B_BAD_VALUE;
1306 
1307 	TRACE(("%ld: merge buffer %p with %p (%s)\n", find_thread(NULL), buffer,
1308 		with, after ? "after" : "before"));
1309 	T(Merge(buffer, with, after));
1310 	//dump_buffer(buffer);
1311 	//dprintf("with:\n");
1312 	//dump_buffer(with);
1313 
1314 	ParanoiaChecker _(buffer);
1315 	CHECK_BUFFER(buffer);
1316 	CHECK_BUFFER(with);
1317 
1318 	// TODO: this is currently very simplistic, I really need to finish the
1319 	//	harder part of this implementation (data_node management per header)
1320 
1321 	data_node* before = NULL;
1322 
1323 	// TODO: Do allocating nodes (the only part that can fail) upfront. Put them
1324 	// in a list, so we can easily clean up, if necessary.
1325 
1326 	if (!after) {
1327 		// change offset of all nodes already in the buffer
1328 		data_node* node = NULL;
1329 		while (true) {
1330 			node = (data_node*)list_get_next_item(&buffer->buffers, node);
1331 			if (node == NULL)
1332 				break;
1333 
1334 			node->offset += with->size;
1335 			if (before == NULL)
1336 				before = node;
1337 		}
1338 	}
1339 
1340 	data_node* last = NULL;
1341 
1342 	while (true) {
1343 		data_node* node = (data_node*)list_get_next_item(&with->buffers, last);
1344 		if (node == NULL)
1345 			break;
1346 
1347 		if ((uint8*)node > (uint8*)node->header
1348 			&& (uint8*)node < (uint8*)node->header + BUFFER_SIZE) {
1349 			// The node is already in the buffer, we can just move it
1350 			// over to the new owner
1351 			list_remove_item(&with->buffers, node);
1352 		} else {
1353 			// we need a new place for this node
1354 			data_node* newNode = add_data_node(buffer, node->header);
1355 			if (newNode == NULL) {
1356 				// TODO: try to revert buffers to their initial state!!
1357 				return ENOBUFS;
1358 			}
1359 
1360 			last = node;
1361 			*newNode = *node;
1362 			node = newNode;
1363 				// the old node will get freed with its buffer
1364 		}
1365 
1366 		if (after) {
1367 			list_add_item(&buffer->buffers, node);
1368 			node->offset = buffer->size;
1369 		} else
1370 			list_insert_item_before(&buffer->buffers, before, node);
1371 
1372 		buffer->size += node->used;
1373 	}
1374 
1375 	SET_PARANOIA_CHECK(PARANOIA_SUSPICIOUS, buffer, &buffer->size,
1376 		sizeof(buffer->size));
1377 
1378 	// the data has been merged completely at this point
1379 	free_buffer(with);
1380 
1381 	//dprintf(" merge result:\n");
1382 	//dump_buffer(buffer);
1383 	CHECK_BUFFER(buffer);
1384 
1385 	return B_OK;
1386 }
1387 
1388 
1389 /*!	Writes into existing allocated memory.
1390 	\return B_BAD_VALUE if you write outside of the buffers current
1391 		bounds.
1392 */
1393 static status_t
1394 write_data(net_buffer* _buffer, size_t offset, const void* data, size_t size)
1395 {
1396 	net_buffer_private* buffer = (net_buffer_private*)_buffer;
1397 
1398 	T(Write(buffer, offset, data, size));
1399 
1400 	ParanoiaChecker _(buffer);
1401 
1402 	if (offset + size > buffer->size)
1403 		return B_BAD_VALUE;
1404 	if (size == 0)
1405 		return B_OK;
1406 
1407 	// find first node to write into
1408 	data_node* node = get_node_at_offset(buffer, offset);
1409 	if (node == NULL)
1410 		return B_BAD_VALUE;
1411 
1412 	offset -= node->offset;
1413 
1414 	while (true) {
1415 		size_t written = min_c(size, node->used - offset);
1416 		memcpy(node->start + offset, data, written);
1417 
1418 		size -= written;
1419 		if (size == 0)
1420 			break;
1421 
1422 		offset = 0;
1423 		data = (void*)((uint8*)data + written);
1424 
1425 		node = (data_node*)list_get_next_item(&buffer->buffers, node);
1426 		if (node == NULL)
1427 			return B_BAD_VALUE;
1428 	}
1429 
1430 	CHECK_BUFFER(buffer);
1431 
1432 	return B_OK;
1433 }
1434 
1435 
1436 static status_t
1437 read_data(net_buffer* _buffer, size_t offset, void* data, size_t size)
1438 {
1439 	net_buffer_private* buffer = (net_buffer_private*)_buffer;
1440 
1441 	T(Read(buffer, offset, data, size));
1442 
1443 	ParanoiaChecker _(buffer);
1444 
1445 	if (offset + size > buffer->size)
1446 		return B_BAD_VALUE;
1447 	if (size == 0)
1448 		return B_OK;
1449 
1450 	// find first node to read from
1451 	data_node* node = get_node_at_offset(buffer, offset);
1452 	if (node == NULL)
1453 		return B_BAD_VALUE;
1454 
1455 	offset -= node->offset;
1456 
1457 	while (true) {
1458 		size_t bytesRead = min_c(size, node->used - offset);
1459 		memcpy(data, node->start + offset, bytesRead);
1460 
1461 		size -= bytesRead;
1462 		if (size == 0)
1463 			break;
1464 
1465 		offset = 0;
1466 		data = (void*)((uint8*)data + bytesRead);
1467 
1468 		node = (data_node*)list_get_next_item(&buffer->buffers, node);
1469 		if (node == NULL)
1470 			return B_BAD_VALUE;
1471 	}
1472 
1473 	CHECK_BUFFER(buffer);
1474 
1475 	return B_OK;
1476 }
1477 
1478 
1479 static status_t
1480 prepend_size(net_buffer* _buffer, size_t size, void** _contiguousBuffer)
1481 {
1482 	net_buffer_private* buffer = (net_buffer_private*)_buffer;
1483 	data_node* node = (data_node*)list_get_first_item(&buffer->buffers);
1484 
1485 	T(PrependSize(buffer, size));
1486 
1487 	ParanoiaChecker _(buffer);
1488 
1489 	TRACE(("%ld: prepend_size(buffer %p, size %ld) [has %u]\n",
1490 		find_thread(NULL), buffer, size, node->HeaderSpace()));
1491 	//dump_buffer(buffer);
1492 
1493 	if (node->HeaderSpace() < size) {
1494 		// we need to prepend new buffers
1495 
1496 		size_t bytesLeft = size;
1497 		size_t sizePrepended = 0;
1498 		do {
1499 			if (node->HeaderSpace() == 0) {
1500 				size_t headerSpace = MAX_FREE_BUFFER_SIZE;
1501 				data_header* header = create_data_header(headerSpace);
1502 				if (header == NULL) {
1503 					remove_header(buffer, sizePrepended);
1504 					return B_NO_MEMORY;
1505 				}
1506 
1507 				data_node* previous = node;
1508 
1509 				node = (data_node*)add_first_data_node(header);
1510 
1511 				list_insert_item_before(&buffer->buffers, previous, node);
1512 
1513 				// Release the initial reference to the header, so that it will
1514 				// be deleted when the node is removed.
1515 				release_data_header(header);
1516 			}
1517 
1518 			size_t willConsume = min_c(bytesLeft, node->HeaderSpace());
1519 
1520 			node->SubtractHeaderSpace(willConsume);
1521 			node->start -= willConsume;
1522 			node->used += willConsume;
1523 			bytesLeft -= willConsume;
1524 			sizePrepended += willConsume;
1525 		} while (bytesLeft > 0);
1526 
1527 		// correct data offset in all nodes
1528 
1529 		size_t offset = 0;
1530 		node = NULL;
1531 		while ((node = (data_node*)list_get_next_item(&buffer->buffers,
1532 				node)) != NULL) {
1533 			node->offset = offset;
1534 			offset += node->used;
1535 		}
1536 
1537 		if (_contiguousBuffer)
1538 			*_contiguousBuffer = NULL;
1539 	} else {
1540 		// the data fits into this buffer
1541 		node->SubtractHeaderSpace(size);
1542 		node->start -= size;
1543 		node->used += size;
1544 
1545 		if (_contiguousBuffer)
1546 			*_contiguousBuffer = node->start;
1547 
1548 		// adjust offset of following nodes
1549 		while ((node = (data_node*)list_get_next_item(&buffer->buffers, node))
1550 				!= NULL) {
1551 			node->offset += size;
1552 		}
1553 	}
1554 
1555 	buffer->size += size;
1556 
1557 	SET_PARANOIA_CHECK(PARANOIA_SUSPICIOUS, buffer, &buffer->size,
1558 		sizeof(buffer->size));
1559 
1560 	//dprintf(" prepend_size result:\n");
1561 	//dump_buffer(buffer);
1562 	CHECK_BUFFER(buffer);
1563 	return B_OK;
1564 }
1565 
1566 
1567 static status_t
1568 prepend_data(net_buffer* buffer, const void* data, size_t size)
1569 {
1570 	void* contiguousBuffer;
1571 	status_t status = prepend_size(buffer, size, &contiguousBuffer);
1572 	if (status < B_OK)
1573 		return status;
1574 
1575 	if (contiguousBuffer)
1576 		memcpy(contiguousBuffer, data, size);
1577 	else
1578 		write_data(buffer, 0, data, size);
1579 
1580 	//dprintf(" prepend result:\n");
1581 	//dump_buffer(buffer);
1582 
1583 	return B_OK;
1584 }
1585 
1586 
1587 static status_t
1588 append_size(net_buffer* _buffer, size_t size, void** _contiguousBuffer)
1589 {
1590 	net_buffer_private* buffer = (net_buffer_private*)_buffer;
1591 	data_node* node = (data_node*)list_get_last_item(&buffer->buffers);
1592 
1593 	T(AppendSize(buffer, size));
1594 
1595 	ParanoiaChecker _(buffer);
1596 
1597 	TRACE(("%ld: append_size(buffer %p, size %ld)\n", find_thread(NULL),
1598 		buffer, size));
1599 	//dump_buffer(buffer);
1600 
1601 	if (node->TailSpace() < size) {
1602 		// we need to append at least one new buffer
1603 		uint32 previousTailSpace = node->TailSpace();
1604 		uint32 headerSpace = DATA_NODE_SIZE;
1605 		uint32 sizeUsed = MAX_FREE_BUFFER_SIZE - headerSpace;
1606 
1607 		// allocate space left in the node
1608 		node->SetTailSpace(0);
1609 		node->used += previousTailSpace;
1610 		buffer->size += previousTailSpace;
1611 		uint32 sizeAdded = previousTailSpace;
1612 		SET_PARANOIA_CHECK(PARANOIA_SUSPICIOUS, buffer, &buffer->size,
1613 			sizeof(buffer->size));
1614 
1615 		// allocate all buffers
1616 
1617 		while (sizeAdded < size) {
1618 			if (sizeAdded + sizeUsed > size) {
1619 				// last data_header and not all available space is used
1620 				sizeUsed = size - sizeAdded;
1621 			}
1622 
1623 			data_header* header = create_data_header(headerSpace);
1624 			if (header == NULL) {
1625 				remove_trailer(buffer, sizeAdded);
1626 				return B_NO_MEMORY;
1627 			}
1628 
1629 			node = add_first_data_node(header);
1630 
1631 			node->SetTailSpace(node->TailSpace() - sizeUsed);
1632 			node->used = sizeUsed;
1633 			node->offset = buffer->size;
1634 
1635 			buffer->size += sizeUsed;
1636 			sizeAdded += sizeUsed;
1637 			SET_PARANOIA_CHECK(PARANOIA_SUSPICIOUS, buffer, &buffer->size,
1638 				sizeof(buffer->size));
1639 
1640 			list_add_item(&buffer->buffers, node);
1641 
1642 			// Release the initial reference to the header, so that it will
1643 			// be deleted when the node is removed.
1644 			release_data_header(header);
1645 		}
1646 
1647 		if (_contiguousBuffer)
1648 			*_contiguousBuffer = NULL;
1649 
1650 		//dprintf(" append result 1:\n");
1651 		//dump_buffer(buffer);
1652 		CHECK_BUFFER(buffer);
1653 
1654 		return B_OK;
1655 	}
1656 
1657 	// the data fits into this buffer
1658 	node->SetTailSpace(node->TailSpace() - size);
1659 
1660 	if (_contiguousBuffer)
1661 		*_contiguousBuffer = node->start + node->used;
1662 
1663 	node->used += size;
1664 	buffer->size += size;
1665 	SET_PARANOIA_CHECK(PARANOIA_SUSPICIOUS, buffer, &buffer->size,
1666 		sizeof(buffer->size));
1667 
1668 	//dprintf(" append result 2:\n");
1669 	//dump_buffer(buffer);
1670 	CHECK_BUFFER(buffer);
1671 
1672 	return B_OK;
1673 }
1674 
1675 
1676 static status_t
1677 append_data(net_buffer* buffer, const void* data, size_t size)
1678 {
1679 	size_t used = buffer->size;
1680 
1681 	void* contiguousBuffer;
1682 	status_t status = append_size(buffer, size, &contiguousBuffer);
1683 	if (status < B_OK)
1684 		return status;
1685 
1686 	if (contiguousBuffer)
1687 		memcpy(contiguousBuffer, data, size);
1688 	else
1689 		write_data(buffer, used, data, size);
1690 
1691 	return B_OK;
1692 }
1693 
1694 
1695 /*!	Removes bytes from the beginning of the buffer.
1696 */
1697 static status_t
1698 remove_header(net_buffer* _buffer, size_t bytes)
1699 {
1700 	net_buffer_private* buffer = (net_buffer_private*)_buffer;
1701 
1702 	T(RemoveHeader(buffer, bytes));
1703 
1704 	ParanoiaChecker _(buffer);
1705 
1706 	if (bytes > buffer->size)
1707 		return B_BAD_VALUE;
1708 
1709 	TRACE(("%ld: remove_header(buffer %p, %ld bytes)\n", find_thread(NULL),
1710 		buffer, bytes));
1711 	//dump_buffer(buffer);
1712 
1713 	size_t left = bytes;
1714 	data_node* node = NULL;
1715 
1716 	while (left >= 0) {
1717 		node = (data_node*)list_get_first_item(&buffer->buffers);
1718 		if (node == NULL) {
1719 			if (left == 0)
1720 				break;
1721 			CHECK_BUFFER(buffer);
1722 			return B_ERROR;
1723 		}
1724 
1725 		if (node->used > left)
1726 			break;
1727 
1728 		// node will be removed completely
1729 		list_remove_item(&buffer->buffers, node);
1730 		left -= node->used;
1731 		remove_data_node(node);
1732 		node = NULL;
1733 	}
1734 
1735 	// cut remaining node, if any
1736 
1737 	if (node != NULL) {
1738 		size_t cut = min_c(node->used, left);
1739 		node->offset = 0;
1740 		node->start += cut;
1741 		node->AddHeaderSpace(cut);
1742 		node->used -= cut;
1743 
1744 		node = (data_node*)list_get_next_item(&buffer->buffers, node);
1745 	}
1746 
1747 	// adjust offset of following nodes
1748 	while (node != NULL) {
1749 		node->offset -= bytes;
1750 		node = (data_node*)list_get_next_item(&buffer->buffers, node);
1751 	}
1752 
1753 	buffer->size -= bytes;
1754 	SET_PARANOIA_CHECK(PARANOIA_SUSPICIOUS, buffer, &buffer->size,
1755 		sizeof(buffer->size));
1756 
1757 	//dprintf(" remove result:\n");
1758 	//dump_buffer(buffer);
1759 	CHECK_BUFFER(buffer);
1760 
1761 	return B_OK;
1762 }
1763 
1764 
1765 /*!	Removes bytes from the end of the buffer.
1766 */
1767 static status_t
1768 remove_trailer(net_buffer* buffer, size_t bytes)
1769 {
1770 	return trim_data(buffer, buffer->size - bytes);
1771 }
1772 
1773 
1774 /*!	Trims the buffer to the specified \a newSize by removing space from
1775 	the end of the buffer.
1776 */
1777 static status_t
1778 trim_data(net_buffer* _buffer, size_t newSize)
1779 {
1780 	net_buffer_private* buffer = (net_buffer_private*)_buffer;
1781 	TRACE(("%ld: trim_data(buffer %p, newSize = %ld, buffer size = %ld)\n",
1782 		find_thread(NULL), buffer, newSize, buffer->size));
1783 	T(Trim(buffer, newSize));
1784 	//dump_buffer(buffer);
1785 
1786 	ParanoiaChecker _(buffer);
1787 
1788 	if (newSize > buffer->size)
1789 		return B_BAD_VALUE;
1790 	if (newSize == buffer->size)
1791 		return B_OK;
1792 
1793 	data_node* node = get_node_at_offset(buffer, newSize);
1794 	if (node == NULL) {
1795 		// trim size greater than buffer size
1796 		return B_BAD_VALUE;
1797 	}
1798 
1799 	int32 diff = node->used + node->offset - newSize;
1800 	node->SetTailSpace(node->TailSpace() + diff);
1801 	node->used -= diff;
1802 
1803 	if (node->used > 0)
1804 		node = (data_node*)list_get_next_item(&buffer->buffers, node);
1805 
1806 	while (node != NULL) {
1807 		data_node* next = (data_node*)list_get_next_item(&buffer->buffers, node);
1808 		list_remove_item(&buffer->buffers, node);
1809 		remove_data_node(node);
1810 
1811 		node = next;
1812 	}
1813 
1814 	buffer->size = newSize;
1815 	SET_PARANOIA_CHECK(PARANOIA_SUSPICIOUS, buffer, &buffer->size,
1816 		sizeof(buffer->size));
1817 
1818 	//dprintf(" trim result:\n");
1819 	//dump_buffer(buffer);
1820 	CHECK_BUFFER(buffer);
1821 
1822 	return B_OK;
1823 }
1824 
1825 
1826 /*!	Appends data coming from buffer \a source to the buffer \a buffer. It only
1827 	clones the data, though, that is the data is not copied, just referenced.
1828 */
1829 static status_t
1830 append_cloned_data(net_buffer* _buffer, net_buffer* _source, uint32 offset,
1831 	size_t bytes)
1832 {
1833 	if (bytes == 0)
1834 		return B_OK;
1835 
1836 	net_buffer_private* buffer = (net_buffer_private*)_buffer;
1837 	net_buffer_private* source = (net_buffer_private*)_source;
1838 	TRACE(("%ld: append_cloned_data(buffer %p, source %p, offset = %ld, "
1839 		"bytes = %ld)\n", find_thread(NULL), buffer, source, offset, bytes));
1840 	T(AppendCloned(buffer, source, offset, bytes));
1841 
1842 	ParanoiaChecker _(buffer);
1843 	ParanoiaChecker _2(source);
1844 
1845 	if (source->size < offset + bytes || source->size < offset)
1846 		return B_BAD_VALUE;
1847 
1848 	// find data_node to start with from the source buffer
1849 	data_node* node = get_node_at_offset(source, offset);
1850 	if (node == NULL) {
1851 		// trim size greater than buffer size
1852 		return B_BAD_VALUE;
1853 	}
1854 
1855 	size_t sizeAppended = 0;
1856 
1857 	while (node != NULL && bytes > 0) {
1858 		data_node* clone = add_data_node(buffer, node->header);
1859 		if (clone == NULL) {
1860 			remove_trailer(buffer, sizeAppended);
1861 			return ENOBUFS;
1862 		}
1863 
1864 		if (offset)
1865 			offset -= node->offset;
1866 
1867 		clone->offset = buffer->size;
1868 		clone->start = node->start + offset;
1869 		clone->used = min_c(bytes, node->used - offset);
1870 		clone->flags |= DATA_NODE_READ_ONLY;
1871 
1872 		list_add_item(&buffer->buffers, clone);
1873 
1874 		offset = 0;
1875 		bytes -= clone->used;
1876 		buffer->size += clone->used;
1877 		sizeAppended += clone->used;
1878 		node = (data_node*)list_get_next_item(&source->buffers, node);
1879 	}
1880 
1881 	if (bytes != 0)
1882 		panic("add_cloned_data() failed, bytes != 0!\n");
1883 
1884 	//dprintf(" append cloned result:\n");
1885 	//dump_buffer(buffer);
1886 	CHECK_BUFFER(source);
1887 	CHECK_BUFFER(buffer);
1888 	SET_PARANOIA_CHECK(PARANOIA_SUSPICIOUS, buffer, &buffer->size,
1889 		sizeof(buffer->size));
1890 
1891 	return B_OK;
1892 }
1893 
1894 
1895 void
1896 set_ancillary_data(net_buffer* buffer, ancillary_data_container* container)
1897 {
1898 	((net_buffer_private*)buffer)->ancillary_data = container;
1899 }
1900 
1901 
1902 ancillary_data_container*
1903 get_ancillary_data(net_buffer* buffer)
1904 {
1905 	return ((net_buffer_private*)buffer)->ancillary_data;
1906 }
1907 
1908 
1909 /*!	Moves all ancillary data from buffer \c from to the end of the list of
1910 	ancillary data of buffer \c to. Note, that this is the only function that
1911 	transfers or copies ancillary data from one buffer to another.
1912 
1913 	\param from The buffer from which to remove the ancillary data.
1914 	\param to The buffer to which to add the ancillary data.
1915 	\return A pointer to the first of the moved ancillary data, if any, \c NULL
1916 		otherwise.
1917 */
1918 static void*
1919 transfer_ancillary_data(net_buffer* _from, net_buffer* _to)
1920 {
1921 	net_buffer_private* from = (net_buffer_private*)_from;
1922 	net_buffer_private* to = (net_buffer_private*)_to;
1923 
1924 	if (from == NULL || to == NULL)
1925 		return NULL;
1926 
1927 	if (from->ancillary_data == NULL)
1928 		return NULL;
1929 
1930 	if (to->ancillary_data == NULL) {
1931 		// no ancillary data in the target buffer
1932 		to->ancillary_data = from->ancillary_data;
1933 		from->ancillary_data = NULL;
1934 		return next_ancillary_data(to->ancillary_data, NULL, NULL);
1935 	}
1936 
1937 	// both have ancillary data
1938 	void* data = move_ancillary_data(from->ancillary_data,
1939 		to->ancillary_data);
1940 	delete_ancillary_data_container(from->ancillary_data);
1941 	from->ancillary_data = NULL;
1942 
1943 	return data;
1944 }
1945 
1946 
1947 /*!	Tries to directly access the requested space in the buffer.
1948 	If the space is contiguous, the function will succeed and place a pointer
1949 	to that space into \a _contiguousBuffer.
1950 
1951 	\return B_BAD_VALUE if the offset is outside of the buffer's bounds.
1952 	\return B_ERROR in case the buffer is not contiguous at that location.
1953 */
1954 static status_t
1955 direct_access(net_buffer* _buffer, uint32 offset, size_t size,
1956 	void** _contiguousBuffer)
1957 {
1958 	net_buffer_private* buffer = (net_buffer_private*)_buffer;
1959 
1960 	ParanoiaChecker _(buffer);
1961 
1962 	//TRACE(("direct_access(buffer %p, offset %ld, size %ld)\n", buffer, offset,
1963 	//	size));
1964 
1965 	if (offset + size > buffer->size)
1966 		return B_BAD_VALUE;
1967 
1968 	// find node to access
1969 	data_node* node = get_node_at_offset(buffer, offset);
1970 	if (node == NULL)
1971 		return B_BAD_VALUE;
1972 
1973 	offset -= node->offset;
1974 
1975 	if (size > node->used - offset)
1976 		return B_ERROR;
1977 
1978 	*_contiguousBuffer = node->start + offset;
1979 	return B_OK;
1980 }
1981 
1982 
1983 static int32
1984 checksum_data(net_buffer* _buffer, uint32 offset, size_t size, bool finalize)
1985 {
1986 	net_buffer_private* buffer = (net_buffer_private*)_buffer;
1987 
1988 	if (offset + size > buffer->size || size == 0)
1989 		return B_BAD_VALUE;
1990 
1991 	// find first node to read from
1992 	data_node* node = get_node_at_offset(buffer, offset);
1993 	if (node == NULL)
1994 		return B_ERROR;
1995 
1996 	offset -= node->offset;
1997 
1998 	// Since the maximum buffer size is 65536 bytes, it's impossible
1999 	// to overlap 32 bit - we don't need to handle this overlap in
2000 	// the loop, we can safely do it afterwards
2001 	uint32 sum = 0;
2002 
2003 	while (true) {
2004 		size_t bytes = min_c(size, node->used - offset);
2005 		if ((offset + node->offset) & 1) {
2006 			// if we're at an uneven offset, we have to swap the checksum
2007 			sum += __swap_int16(compute_checksum(node->start + offset, bytes));
2008 		} else
2009 			sum += compute_checksum(node->start + offset, bytes);
2010 
2011 		size -= bytes;
2012 		if (size == 0)
2013 			break;
2014 
2015 		offset = 0;
2016 
2017 		node = (data_node*)list_get_next_item(&buffer->buffers, node);
2018 		if (node == NULL)
2019 			return B_ERROR;
2020 	}
2021 
2022 	while (sum >> 16) {
2023 		sum = (sum & 0xffff) + (sum >> 16);
2024 	}
2025 
2026 	if (!finalize)
2027 		return (uint16)sum;
2028 
2029 	return (uint16)~sum;
2030 }
2031 
2032 
2033 static uint32
2034 get_iovecs(net_buffer* _buffer, struct iovec* iovecs, uint32 vecCount)
2035 {
2036 	net_buffer_private* buffer = (net_buffer_private*)_buffer;
2037 	data_node* node = (data_node*)list_get_first_item(&buffer->buffers);
2038 	uint32 count = 0;
2039 
2040 	while (node != NULL && count < vecCount) {
2041 		if (node->used > 0) {
2042 			iovecs[count].iov_base = node->start;
2043 			iovecs[count].iov_len = node->used;
2044 			count++;
2045 		}
2046 
2047 		node = (data_node*)list_get_next_item(&buffer->buffers, node);
2048 	}
2049 
2050 	return count;
2051 }
2052 
2053 
2054 static uint32
2055 count_iovecs(net_buffer* _buffer)
2056 {
2057 	net_buffer_private* buffer = (net_buffer_private*)_buffer;
2058 	data_node* node = (data_node*)list_get_first_item(&buffer->buffers);
2059 	uint32 count = 0;
2060 
2061 	while (node != NULL) {
2062 		if (node->used > 0)
2063 			count++;
2064 
2065 		node = (data_node*)list_get_next_item(&buffer->buffers, node);
2066 	}
2067 
2068 	return count;
2069 }
2070 
2071 
2072 static void
2073 swap_addresses(net_buffer* buffer)
2074 {
2075 	std::swap(buffer->source, buffer->destination);
2076 }
2077 
2078 
2079 static status_t
2080 std_ops(int32 op, ...)
2081 {
2082 	switch (op) {
2083 		case B_MODULE_INIT:
2084 			// TODO: improve our code a bit so we can add constructors
2085 			//	and keep around half-constructed buffers in the slab
2086 
2087 			sNetBufferCache = create_object_cache("net buffer cache",
2088 				sizeof(net_buffer_private), 8, NULL, NULL, NULL);
2089 			if (sNetBufferCache == NULL)
2090 				return B_NO_MEMORY;
2091 
2092 			sDataNodeCache = create_object_cache("data node cache", BUFFER_SIZE,
2093 				0, NULL, NULL, NULL);
2094 			if (sDataNodeCache == NULL) {
2095 				delete_object_cache(sNetBufferCache);
2096 				return B_NO_MEMORY;
2097 			}
2098 
2099 #if ENABLE_DEBUGGER_COMMANDS
2100 			add_debugger_command_etc("net_buffer_stats", &dump_net_buffer_stats,
2101 				"Print net buffer statistics",
2102 				"\nPrint net buffer statistics.\n", 0);
2103 #endif
2104 
2105 			return B_OK;
2106 
2107 		case B_MODULE_UNINIT:
2108 #if ENABLE_DEBUGGER_COMMANDS
2109 			remove_debugger_command("net_buffer_stats", &dump_net_buffer_stats);
2110 #endif
2111 			delete_object_cache(sNetBufferCache);
2112 			delete_object_cache(sDataNodeCache);
2113 			return B_OK;
2114 
2115 		default:
2116 			return B_ERROR;
2117 	}
2118 }
2119 
2120 
2121 net_buffer_module_info gNetBufferModule = {
2122 	{
2123 		NET_BUFFER_MODULE_NAME,
2124 		0,
2125 		std_ops
2126 	},
2127 	create_buffer,
2128 	free_buffer,
2129 
2130 	duplicate_buffer,
2131 	clone_buffer,
2132 	split_buffer,
2133 	merge_buffer,
2134 
2135 	prepend_size,
2136 	prepend_data,
2137 	append_size,
2138 	append_data,
2139 	NULL,	// insert
2140 	NULL,	// remove
2141 	remove_header,
2142 	remove_trailer,
2143 	trim_data,
2144 	append_cloned_data,
2145 
2146 	NULL,	// associate_data
2147 
2148 	set_ancillary_data,
2149 	get_ancillary_data,
2150 	transfer_ancillary_data,
2151 
2152 	direct_access,
2153 	read_data,
2154 	write_data,
2155 
2156 	checksum_data,
2157 
2158 	NULL,	// get_memory_map
2159 	get_iovecs,
2160 	count_iovecs,
2161 
2162 	swap_addresses,
2163 
2164 	dump_buffer,	// dump
2165 };
2166 
2167