xref: /haiku/src/add-ons/kernel/network/stack/simple_net_buffer.cpp (revision d96c90096f7d4f246127ad2ca92db58ef65e647f)
1 /*
2  * Copyright 2006-2008, 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 "simple_net_buffer.h"
11 
12 #include "utility.h"
13 
14 #include <net_buffer.h>
15 #include <slab/Slab.h>
16 #include <tracing.h>
17 #include <util/list.h>
18 
19 #include <ByteOrder.h>
20 #include <debug.h>
21 #include <KernelExport.h>
22 #include <util/AutoLock.h>
23 #include <util/DoublyLinkedList.h>
24 
25 #include <algorithm>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/uio.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 
41 #define MAX_ANCILLARY_DATA_SIZE	128
42 
43 struct ancillary_data : DoublyLinkedListLinkImpl<ancillary_data> {
Dataancillary_data44 	void* Data()
45 	{
46 		return (char*)this + _ALIGN(sizeof(ancillary_data));
47 	}
48 
FromDataancillary_data49 	static ancillary_data* FromData(void* data)
50 	{
51 		return (ancillary_data*)((char*)data - _ALIGN(sizeof(ancillary_data)));
52 	}
53 
54 	ancillary_data_header	header;
55 	void (*destructor)(const ancillary_data_header*, void*);
56 };
57 
58 typedef DoublyLinkedList<ancillary_data> ancillary_data_list;
59 
60 
61 struct net_buffer_private : simple_net_buffer {
62 	ancillary_data_list	ancillary_data;
63 };
64 
65 
66 static status_t append_data(net_buffer *buffer, const void *data, size_t size);
67 static status_t trim_data(net_buffer *_buffer, size_t newSize);
68 static status_t remove_header(net_buffer *_buffer, size_t bytes);
69 static status_t remove_trailer(net_buffer *_buffer, size_t bytes);
70 
71 
72 static void
copy_metadata(net_buffer * destination,const net_buffer * source)73 copy_metadata(net_buffer *destination, const net_buffer *source)
74 {
75 	memcpy(destination->source, source->source,
76 		min_c(source->source->sa_len, sizeof(sockaddr_storage)));
77 	memcpy(destination->destination, source->destination,
78 		min_c(source->destination->sa_len, sizeof(sockaddr_storage)));
79 
80 	destination->flags = source->flags;
81 	destination->interface = source->interface;
82 	destination->offset = source->offset;
83 	destination->size = source->size;
84 	destination->protocol = source->protocol;
85 	destination->type = source->type;
86 }
87 
88 
89 //	#pragma mark - module API
90 
91 
92 static net_buffer *
create_buffer(size_t headerSpace)93 create_buffer(size_t headerSpace)
94 {
95 	net_buffer_private *buffer = new(nothrow) net_buffer_private;
96 	if (buffer == NULL)
97 		return NULL;
98 
99 	TRACE(("%ld: create buffer %p\n", find_thread(NULL), buffer));
100 
101 	buffer->data = NULL;
102 	new(&buffer->ancillary_data) ancillary_data_list;
103 
104 	buffer->source = (sockaddr *)&buffer->storage.source;
105 	buffer->destination = (sockaddr *)&buffer->storage.destination;
106 
107 	buffer->storage.source.ss_len = 0;
108 	buffer->storage.destination.ss_len = 0;
109 
110 	buffer->interface = NULL;
111 	buffer->offset = 0;
112 	buffer->flags = 0;
113 	buffer->size = 0;
114 
115 	buffer->type = -1;
116 
117 	return buffer;
118 }
119 
120 
121 static void
free_buffer(net_buffer * _buffer)122 free_buffer(net_buffer *_buffer)
123 {
124 	net_buffer_private *buffer = (net_buffer_private *)_buffer;
125 
126 	free(buffer->data);
127 	delete buffer;
128 }
129 
130 
131 /*!	Creates a duplicate of the \a buffer. The new buffer does not share internal
132 	storage; they are completely independent from each other.
133 */
134 static net_buffer *
duplicate_buffer(net_buffer * _buffer)135 duplicate_buffer(net_buffer *_buffer)
136 {
137 	net_buffer_private *buffer = (net_buffer_private *)_buffer;
138 
139 	net_buffer* duplicate = create_buffer(0);
140 	if (duplicate == NULL)
141 		return NULL;
142 
143 	if (append_data(duplicate, buffer->data, buffer->size) != B_OK) {
144 		free_buffer(duplicate);
145 		return NULL;
146 	}
147 
148 	copy_metadata(duplicate, buffer);
149 
150 	return duplicate;
151 }
152 
153 
154 /*!	Clones the buffer by grabbing another reference to the underlying data.
155 	If that data changes, it will be changed in the clone as well.
156 
157 	If \a shareFreeSpace is \c true, the cloned buffer may claim the free
158 	space in the original buffer as the original buffer can still do. If you
159 	are using this, it's your responsibility that only one of the buffers
160 	will do this.
161 */
162 static net_buffer *
clone_buffer(net_buffer * _buffer,bool shareFreeSpace)163 clone_buffer(net_buffer *_buffer, bool shareFreeSpace)
164 {
165 	return duplicate_buffer(_buffer);
166 }
167 
168 
169 /*!
170 	Split the buffer at offset, the header data
171 	is returned as new buffer.
172 	TODO: optimize and avoid making a copy.
173 */
174 static net_buffer *
split_buffer(net_buffer * _from,uint32 offset)175 split_buffer(net_buffer *_from, uint32 offset)
176 {
177 	net_buffer_private *from = (net_buffer_private *)_from;
178 
179 	if (offset > from->size)
180 		return NULL;
181 
182 	net_buffer_private* buffer = (net_buffer_private*)create_buffer(0);
183 	if (buffer == NULL)
184 		return NULL;
185 
186 	// allocate space for the tail data
187 	size_t remaining = from->size - offset;
188 	uint8* tailData = (uint8*)malloc(remaining);
189 	if (tailData == NULL) {
190 		free_buffer(buffer);
191 		return NULL;
192 	}
193 
194 	memcpy(tailData, from->data + offset, remaining);
195 
196 	// truncate original data and move it to the new buffer
197 	buffer->data = (uint8*)realloc(from->data, offset);
198 	buffer->size = offset;
199 
200 	// the old buffer gets the newly allocated tail data
201 	from->data = tailData;
202 	from->size = remaining;
203 
204 	return buffer;
205 }
206 
207 
208 /*!
209 	Merges the second buffer with the first. If \a after is \c true, the
210 	second buffer's contents will be appended to the first ones, else they
211 	will be prepended.
212 	The second buffer will be freed if this function succeeds.
213 */
214 static status_t
merge_buffer(net_buffer * _buffer,net_buffer * _with,bool after)215 merge_buffer(net_buffer *_buffer, net_buffer *_with, bool after)
216 {
217 	net_buffer_private *buffer = (net_buffer_private *)_buffer;
218 	net_buffer_private *with = (net_buffer_private *)_with;
219 	if (with == NULL)
220 		return B_BAD_VALUE;
221 
222 	if (after) {
223 		// the simple case: just append the second buffer
224 		status_t error = append_data(buffer, with->data, with->size);
225 		if (error != B_OK)
226 			return error;
227 	} else {
228 		// append buffer to the second buffer, then switch the data
229 		status_t error = append_data(with, buffer->data, buffer->size);
230 		if (error != B_OK)
231 			return error;
232 
233 		free(buffer->data);
234 		buffer->data = with->data;
235 		buffer->size = with->size;
236 
237 		with->data = NULL;
238 	}
239 
240 	free_buffer(with);
241 
242 	return B_OK;
243 }
244 
245 
246 /*!	Writes into existing allocated memory.
247 	\return B_BAD_VALUE if you write outside of the buffers current
248 		bounds.
249 */
250 static status_t
write_data(net_buffer * _buffer,size_t offset,const void * data,size_t size)251 write_data(net_buffer *_buffer, size_t offset, const void *data, size_t size)
252 {
253 	net_buffer_private *buffer = (net_buffer_private *)_buffer;
254 
255 	if (offset + size > buffer->size)
256 		return B_BAD_VALUE;
257 	if (size == 0)
258 		return B_OK;
259 
260 	memcpy(buffer->data + offset, data, size);
261 
262 	return B_OK;
263 }
264 
265 
266 static status_t
read_data(net_buffer * _buffer,size_t offset,void * data,size_t size)267 read_data(net_buffer *_buffer, size_t offset, void *data, size_t size)
268 {
269 	net_buffer_private *buffer = (net_buffer_private *)_buffer;
270 
271 	if (offset + size > buffer->size)
272 		return B_BAD_VALUE;
273 	if (size == 0)
274 		return B_OK;
275 
276 	memcpy(data, buffer->data + offset, size);
277 
278 	return B_OK;
279 }
280 
281 
282 static status_t
prepend_size(net_buffer * _buffer,size_t size,void ** _contiguousBuffer)283 prepend_size(net_buffer *_buffer, size_t size, void **_contiguousBuffer)
284 {
285 	if (size == 0)
286 		return B_OK;
287 
288 	net_buffer_private *buffer = (net_buffer_private *)_buffer;
289 
290 	uint8* newData = (uint8*)malloc(buffer->size + size);
291 	if (newData == NULL)
292 		return B_NO_MEMORY;
293 
294 	memcpy(newData + size, buffer->data, buffer->size);
295 
296 	free(buffer->data);
297 	buffer->data = newData;
298 	buffer->size += size;
299 
300 	if (_contiguousBuffer != NULL)
301 		*_contiguousBuffer = buffer->data;
302 
303 	return B_OK;
304 }
305 
306 
307 static status_t
prepend_data(net_buffer * buffer,const void * data,size_t size)308 prepend_data(net_buffer *buffer, const void *data, size_t size)
309 {
310 	status_t status = prepend_size(buffer, size, NULL);
311 	if (status < B_OK)
312 		return status;
313 
314 	write_data(buffer, 0, data, size);
315 
316 	return B_OK;
317 }
318 
319 
320 static status_t
append_size(net_buffer * _buffer,size_t size,void ** _contiguousBuffer)321 append_size(net_buffer *_buffer, size_t size, void **_contiguousBuffer)
322 {
323 	if (size == 0)
324 		return B_OK;
325 
326 	net_buffer_private *buffer = (net_buffer_private *)_buffer;
327 
328 	uint8* newData = (uint8*)realloc(buffer->data, buffer->size + size);
329 	if (newData == NULL)
330 		return B_NO_MEMORY;
331 
332 	if (_contiguousBuffer != NULL)
333 		*_contiguousBuffer = newData + buffer->size;
334 
335 	buffer->data = newData;
336 	buffer->size += size;
337 
338 	return B_OK;
339 }
340 
341 
342 static status_t
append_data(net_buffer * buffer,const void * data,size_t size)343 append_data(net_buffer *buffer, const void *data, size_t size)
344 {
345 	size_t used = buffer->size;
346 
347 	status_t status = append_size(buffer, size, NULL);
348 	if (status < B_OK)
349 		return status;
350 
351 	write_data(buffer, used, data, size);
352 
353 	return B_OK;
354 }
355 
356 
357 /*!
358 	Removes bytes from the beginning of the buffer.
359 */
360 static status_t
remove_header(net_buffer * _buffer,size_t bytes)361 remove_header(net_buffer *_buffer, size_t bytes)
362 {
363 	net_buffer_private *buffer = (net_buffer_private *)_buffer;
364 
365 	if (bytes > buffer->size)
366 		return B_BAD_VALUE;
367 	if (bytes == 0)
368 		return B_OK;
369 
370 	buffer->size -= bytes;
371 	memmove(buffer->data, buffer->data + bytes, buffer->size);
372 	buffer->data = (uint8*)realloc(buffer->data, buffer->size);
373 
374 	return B_OK;
375 }
376 
377 
378 /*!
379 	Removes bytes from the end of the buffer.
380 */
381 static status_t
remove_trailer(net_buffer * buffer,size_t bytes)382 remove_trailer(net_buffer *buffer, size_t bytes)
383 {
384 	return trim_data(buffer, buffer->size - bytes);
385 }
386 
387 
388 /*!
389 	Trims the buffer to the specified \a newSize by removing space from
390 	the end of the buffer.
391 */
392 static status_t
trim_data(net_buffer * _buffer,size_t newSize)393 trim_data(net_buffer *_buffer, size_t newSize)
394 {
395 	net_buffer_private *buffer = (net_buffer_private *)_buffer;
396 
397 	if (newSize > buffer->size)
398 		return B_BAD_VALUE;
399 	if (newSize == buffer->size)
400 		return B_OK;
401 
402 	buffer->data = (uint8*)realloc(buffer->data, newSize);
403 	buffer->size = newSize;
404 
405 	return B_OK;
406 }
407 
408 
409 /*!
410 	Appends data coming from buffer \a source to the buffer \a buffer. It only
411 	clones the data, though, that is the data is not copied, just referenced.
412 */
413 static status_t
append_cloned_data(net_buffer * _buffer,net_buffer * _source,uint32 offset,size_t bytes)414 append_cloned_data(net_buffer *_buffer, net_buffer *_source, uint32 offset,
415 	size_t bytes)
416 {
417 	if (bytes == 0)
418 		return B_OK;
419 
420 	net_buffer_private *buffer = (net_buffer_private *)_buffer;
421 	net_buffer_private *source = (net_buffer_private *)_source;
422 
423 	if (offset + bytes > source->size)
424 		return B_BAD_VALUE;
425 
426 	return append_data(buffer, source->data + offset, bytes);
427 }
428 
429 
430 /*!
431 	Attaches ancillary data to the given buffer. The data are completely
432 	orthogonal to the data the buffer stores.
433 
434 	\param buffer The buffer.
435 	\param header Description of the data.
436 	\param data If not \c NULL, the data are copied into the allocated storage.
437 	\param destructor If not \c NULL, this function will be invoked with the
438 		data as parameter when the buffer is destroyed.
439 	\param _allocatedData Will be set to the storage allocated for the data.
440 	\return \c B_OK when everything goes well, another error code otherwise.
441 */
442 static status_t
attach_ancillary_data(net_buffer * _buffer,const ancillary_data_header * header,const void * data,void (* destructor)(const ancillary_data_header *,void *),void ** _allocatedData)443 attach_ancillary_data(net_buffer *_buffer, const ancillary_data_header *header,
444 	const void *data, void (*destructor)(const ancillary_data_header*, void*),
445 	void **_allocatedData)
446 {
447 	// TODO: Obviously it would be nice to allocate the memory for the
448 	// ancillary data in the buffer.
449 	net_buffer_private *buffer = (net_buffer_private *)_buffer;
450 
451 	// check parameters
452 	if (header == NULL)
453 		return B_BAD_VALUE;
454 
455 	if (header->len > MAX_ANCILLARY_DATA_SIZE)
456 		return ENOBUFS;
457 
458 	// allocate buffer
459 	void *dataBuffer = malloc(_ALIGN(sizeof(ancillary_data)) + header->len);
460 	if (dataBuffer == NULL)
461 		return B_NO_MEMORY;
462 
463 	// init and attach the structure
464 	ancillary_data *ancillaryData = new(dataBuffer) ancillary_data;
465 	ancillaryData->header = *header;
466 	ancillaryData->destructor = destructor;
467 
468 	buffer->ancillary_data.Add(ancillaryData);
469 
470 	if (data != NULL)
471 		memcpy(ancillaryData->Data(), data, header->len);
472 
473 	if (_allocatedData != NULL)
474 		*_allocatedData = ancillaryData->Data();
475 
476 	return B_OK;
477 }
478 
479 
480 /*!
481 	Detaches ancillary data from the given buffer. The associated memory is
482 	free, i.e. the \a data pointer must no longer be used after calling this
483 	function. Depending on \a destroy, the destructor is invoked before freeing
484 	the data.
485 
486 	\param buffer The buffer.
487 	\param data Pointer to the data to be removed (as returned by
488 		attach_ancillary_data() or next_ancillary_data()).
489 	\param destroy If \c true, the destructor, if one was passed to
490 		attach_ancillary_data(), is invoked for the data.
491 	\return \c B_OK when everything goes well, another error code otherwise.
492 */
493 static status_t
detach_ancillary_data(net_buffer * _buffer,void * data,bool destroy)494 detach_ancillary_data(net_buffer *_buffer, void *data, bool destroy)
495 {
496 	net_buffer_private *buffer = (net_buffer_private *)_buffer;
497 
498 	if (data == NULL)
499 		return B_BAD_VALUE;
500 
501 	ancillary_data *ancillaryData = ancillary_data::FromData(data);
502 
503 	buffer->ancillary_data.Remove(ancillaryData);
504 
505 	if (destroy && ancillaryData->destructor != NULL) {
506 		ancillaryData->destructor(&ancillaryData->header,
507 			ancillaryData->Data());
508 	}
509 
510 	free(ancillaryData);
511 
512 	return B_OK;
513 }
514 
515 
516 /*!
517 	Moves all ancillary data from buffer \c from to the end of the list of
518 	ancillary data of buffer \c to. Note, that this is the only function that
519 	transfers or copies ancillary data from one buffer to another.
520 
521 	\param from The buffer from which to remove the ancillary data.
522 	\param to The buffer to which to add teh ancillary data.
523 	\return A pointer to the first of the moved ancillary data, if any, \c NULL
524 		otherwise.
525 */
526 static void *
transfer_ancillary_data(net_buffer * _from,net_buffer * _to)527 transfer_ancillary_data(net_buffer *_from, net_buffer *_to)
528 {
529 	net_buffer_private *from = (net_buffer_private *)_from;
530 	net_buffer_private *to = (net_buffer_private *)_to;
531 
532 	if (from == NULL || to == NULL)
533 		return NULL;
534 
535 	ancillary_data *ancillaryData = from->ancillary_data.Head();
536 	to->ancillary_data.MoveFrom(&from->ancillary_data);
537 
538 	return ancillaryData != NULL ? ancillaryData->Data() : NULL;
539 }
540 
541 
542 /*!
543 	Returns the next ancillary data. When iterating over the data, initially
544 	a \c NULL pointer shall be passed as \a previousData, subsequently the
545 	previously returned data pointer. After the last item, \c NULL is returned.
546 
547 	Note, that it is not safe to call detach_ancillary_data() for a data item
548 	and then pass that pointer to this function. First get the next item, then
549 	detach the previous one.
550 
551 	\param buffer The buffer.
552 	\param previousData The pointer to the previous data returned by this
553 		function. Initially \c NULL shall be passed.
554 	\param header Pointer to allocated storage into which the data description
555 		is written. May be \c NULL.
556 	\return A pointer to the next ancillary data in the buffer. \c NULL after
557 		the last one.
558 */
559 static void*
next_ancillary_data(net_buffer * _buffer,void * previousData,ancillary_data_header * _header)560 next_ancillary_data(net_buffer *_buffer, void *previousData,
561 	ancillary_data_header *_header)
562 {
563 	net_buffer_private *buffer = (net_buffer_private *)_buffer;
564 
565 	ancillary_data *ancillaryData;
566 
567 	if (previousData == NULL) {
568 		ancillaryData = buffer->ancillary_data.Head();
569 	} else {
570 		ancillaryData = ancillary_data::FromData(previousData);
571 		ancillaryData = buffer->ancillary_data.GetNext(ancillaryData);
572 	}
573 
574 	if (ancillaryData == NULL)
575 		return NULL;
576 
577 	if (_header != NULL)
578 		*_header = ancillaryData->header;
579 
580 	return ancillaryData->Data();
581 }
582 
583 
584 /*!
585 	Tries to directly access the requested space in the buffer.
586 	If the space is contiguous, the function will succeed and place a pointer
587 	to that space into \a _contiguousBuffer.
588 
589 	\return B_BAD_VALUE if the offset is outside of the buffer's bounds.
590 	\return B_ERROR in case the buffer is not contiguous at that location.
591 */
592 static status_t
direct_access(net_buffer * _buffer,uint32 offset,size_t size,void ** _contiguousBuffer)593 direct_access(net_buffer *_buffer, uint32 offset, size_t size,
594 	void **_contiguousBuffer)
595 {
596 	net_buffer_private *buffer = (net_buffer_private *)_buffer;
597 
598 	if (offset + size > buffer->size)
599 		return B_BAD_VALUE;
600 
601 	*_contiguousBuffer = buffer->data + offset;
602 	return B_OK;
603 }
604 
605 
606 static int32
checksum_data(net_buffer * _buffer,uint32 offset,size_t size,bool finalize)607 checksum_data(net_buffer *_buffer, uint32 offset, size_t size, bool finalize)
608 {
609 	net_buffer_private *buffer = (net_buffer_private *)_buffer;
610 
611 	if (offset + size > buffer->size || size == 0)
612 		return B_BAD_VALUE;
613 
614 	uint16 sum = compute_checksum(buffer->data + offset, size);
615 	if ((offset & 1) != 0) {
616 		// if we're at an uneven offset, we have to swap the checksum
617 		sum = __swap_int16(sum);
618 	}
619 
620 	if (!finalize)
621 		return (uint16)sum;
622 
623 	return (uint16)~sum;
624 }
625 
626 
627 static uint32
get_iovecs(net_buffer * _buffer,struct iovec * iovecs,uint32 vecCount)628 get_iovecs(net_buffer *_buffer, struct iovec *iovecs, uint32 vecCount)
629 {
630 	net_buffer_private *buffer = (net_buffer_private *)_buffer;
631 
632 	iovecs[0].iov_base = buffer->data;
633 	iovecs[0].iov_len = buffer->size;
634 
635 	return 1;
636 }
637 
638 
639 static uint32
count_iovecs(net_buffer * _buffer)640 count_iovecs(net_buffer *_buffer)
641 {
642 	return 1;
643 }
644 
645 
646 static void
swap_addresses(net_buffer * buffer)647 swap_addresses(net_buffer *buffer)
648 {
649 	std::swap(buffer->source, buffer->destination);
650 }
651 
652 
653 static void
dump_buffer(net_buffer * _buffer)654 dump_buffer(net_buffer *_buffer)
655 {
656 	net_buffer_private *buffer = (net_buffer_private *)_buffer;
657 
658 	dprintf("buffer %p, size %ld, data: %p\n", buffer, buffer->size,
659 		buffer->data);
660 	dump_block((char*)buffer->data, min_c(buffer->size, 32), "    ");
661 }
662 
663 
664 static status_t
std_ops(int32 op,...)665 std_ops(int32 op, ...)
666 {
667 	switch (op) {
668 		case B_MODULE_INIT:
669 			return B_OK;
670 
671 		case B_MODULE_UNINIT:
672 			return B_OK;
673 
674 		default:
675 			return B_ERROR;
676 	}
677 }
678 
679 
680 net_buffer_module_info gSimpleNetBufferModule = {
681 //net_buffer_module_info gNetBufferModule = {
682 	{
683 		NET_BUFFER_MODULE_NAME,
684 		0,
685 		std_ops
686 	},
687 	create_buffer,
688 	free_buffer,
689 
690 	duplicate_buffer,
691 	clone_buffer,
692 	split_buffer,
693 	merge_buffer,
694 
695 	prepend_size,
696 	prepend_data,
697 	append_size,
698 	append_data,
699 	NULL,	// insert
700 	NULL,	// remove
701 	remove_header,
702 	remove_trailer,
703 	trim_data,
704 	append_cloned_data,
705 
706 	NULL,	// associate_data
707 
708 	attach_ancillary_data,
709 	detach_ancillary_data,
710 	transfer_ancillary_data,
711 	next_ancillary_data,
712 
713 	direct_access,
714 	read_data,
715 	write_data,
716 
717 	checksum_data,
718 
719 	NULL,	// get_memory_map
720 	get_iovecs,
721 	count_iovecs,
722 
723 	swap_addresses,
724 
725 	dump_buffer,	// dump
726 };
727 
728