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