diff --git a/headers/private/net/net_buffer.h b/headers/private/net/net_buffer.h
index f269f37f28..d5fcf30081 100644
--- a/headers/private/net/net_buffer.h
+++ b/headers/private/net/net_buffer.h
@@ -37,6 +37,12 @@ typedef struct net_buffer {
 	uint8	protocol;
 } net_buffer;
 
+typedef struct ancillary_data_header {
+	int		level;
+	int		type;
+	size_t	len;
+} ancillary_data_header;
+
 struct net_buffer_module_info {
 	module_info info;
 
@@ -68,6 +74,17 @@ struct net_buffer_module_info {
 
 	status_t		(*associate_data)(net_buffer *buffer, void *data);
 
+	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);
+	status_t		(*detach_ancillary_data)(net_buffer *buffer, void *data,
+						bool destroy);
+	void *			(*transfer_ancillary_data)(net_buffer *from,
+						net_buffer *to);
+	void *			(*next_ancillary_data)(net_buffer *buffer,
+						void *previousData, ancillary_data_header *_header);
+
 	status_t		(*direct_access)(net_buffer *buffer, uint32 offset,
 						size_t bytes, void **_data);
 	status_t 		(*read)(net_buffer *buffer, uint32 offset, void *data,
diff --git a/src/add-ons/kernel/network/stack/net_buffer.cpp b/src/add-ons/kernel/network/stack/net_buffer.cpp
index cf86804846..bd63907078 100644
--- a/src/add-ons/kernel/network/stack/net_buffer.cpp
+++ b/src/add-ons/kernel/network/stack/net_buffer.cpp
@@ -16,6 +16,7 @@
 #include <ByteOrder.h>
 #include <KernelExport.h>
 #include <util/AutoLock.h>
+#include <util/DoublyLinkedList.h>
 
 #include <algorithm>
 #include <stdlib.h>
@@ -58,11 +59,31 @@ struct data_header {
 	data_node	*first_node;
 };
 
+#define MAX_ANCILLARY_DATA_SIZE	128
+
+struct ancillary_data : DoublyLinkedListLinkImpl<ancillary_data> {
+	void* Data()
+	{
+		return (char*)this + _ALIGN(sizeof(ancillary_data));
+	}
+
+	static ancillary_data* FromData(void* data)
+	{
+		return (ancillary_data*)((char*)data - _ALIGN(sizeof(ancillary_data)));
+	}
+
+	ancillary_data_header	header;
+	void (*destructor)(const ancillary_data_header*, void*);
+};
+
+typedef DoublyLinkedList<ancillary_data> ancillary_data_list;
+
 #define MAX_FREE_BUFFER_SIZE (BUFFER_SIZE - sizeof(data_header))
 
 struct net_buffer_private : net_buffer {
-	struct list	buffers;
-	data_node	first_node;
+	struct list			buffers;
+	data_node			first_node;
+	ancillary_data_list	ancillary_data;
 
 	struct {
 		struct sockaddr_storage source;
@@ -353,6 +374,8 @@ create_buffer(size_t headerSpace)
 	list_init(&buffer->buffers);
 	list_add_item(&buffer->buffers, &buffer->first_node);
 
+	new(&buffer->ancillary_data) ancillary_data_list;
+
 	buffer->source = (sockaddr *)&buffer->storage.source;
 	buffer->destination = (sockaddr *)&buffer->storage.destination;
 
@@ -382,6 +405,12 @@ free_buffer(net_buffer *_buffer)
 		remove_data_node(node);
 	}
 
+	while (ancillary_data* data = buffer->ancillary_data.RemoveHead()) {
+		if (data->destructor != NULL)
+			data->destructor(&data->header, data->Data());
+		free(data);
+	}
+
 	free_net_buffer(buffer);
 }
 
@@ -1067,6 +1096,160 @@ append_cloned_data(net_buffer *_buffer, net_buffer *_source, uint32 offset,
 }
 
 
+/*!
+	Attaches ancillary data to the given buffer. The data are completely
+	orthogonal to the data the buffer stores.
+
+	\param buffer The buffer.
+	\param header Description of the data.
+	\param data If not \c NULL, the data are copied into the allocated storage.
+	\param destructor If not \c NULL, this function will be invoked with the
+		data as parameter when the buffer is destroyed.
+	\param _allocatedData Will be set to the storage allocated for the data.
+	\return \c B_OK when everything goes well, another error code otherwise.
+*/
+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)
+{
+	// TODO: Obviously it would be nice to allocate the memory for the
+	// ancillary data in the buffer.
+	net_buffer_private *buffer = (net_buffer_private *)_buffer;
+
+	// check parameters
+	if (header == NULL)
+		return B_BAD_VALUE;
+
+	if (header->len > MAX_ANCILLARY_DATA_SIZE)
+		return ENOBUFS;
+
+	// allocate buffer
+	void *dataBuffer = malloc(_ALIGN(sizeof(ancillary_data)) + header->len);
+	if (dataBuffer == NULL)
+		return B_NO_MEMORY;
+
+	// init and attach the structure
+	ancillary_data *ancillaryData = new(dataBuffer) ancillary_data;
+	ancillaryData->header = *header;
+	ancillaryData->destructor = destructor;
+
+	buffer->ancillary_data.Add(ancillaryData);
+
+	if (data != NULL)
+		memcpy(ancillaryData->Data(), data, header->len);
+
+	if (_allocatedData != NULL)
+		*_allocatedData = ancillaryData->Data();
+
+	return B_OK;
+}
+
+
+/*!
+	Detaches ancillary data from the given buffer. The associated memory is
+	free, i.e. the \a data pointer must no longer be used after calling this
+	function. Depending on \a destroy, the destructor is invoked before freeing
+	the data.
+
+	\param buffer The buffer.
+	\param data Pointer to the data to be removed (as returned by
+		attach_ancillary_data() or next_ancillary_data()).
+	\param destroy If \c true, the destructor, if one was passed to
+		attach_ancillary_data(), is invoked for the data.
+	\return \c B_OK when everything goes well, another error code otherwise.
+*/
+static status_t
+detach_ancillary_data(net_buffer *_buffer, void *data, bool destroy)
+{
+	net_buffer_private *buffer = (net_buffer_private *)_buffer;
+
+	if (data == NULL)
+		return B_BAD_VALUE;
+
+	ancillary_data *ancillaryData = ancillary_data::FromData(data);
+
+	buffer->ancillary_data.Remove(ancillaryData);
+
+	if (destroy && ancillaryData->destructor != NULL) {
+		ancillaryData->destructor(&ancillaryData->header,
+			ancillaryData->Data());
+	}
+
+	free(ancillaryData);
+
+	return B_OK;
+}
+
+
+/*!
+	Moves all ancillary data from buffer \c from to the end of the list of
+	ancillary data of buffer \c to. Note, that this is the only function that
+	transfers or copies ancillary data from one buffer to another.
+
+	\param from The buffer from which to remove the ancillary data.
+	\param to The buffer to which to add teh ancillary data.
+	\return A pointer to the first of the moved ancillary data, if any, \c NULL
+		otherwise.
+*/
+static void *
+transfer_ancillary_data(net_buffer *_from, net_buffer *_to)
+{
+	net_buffer_private *from = (net_buffer_private *)_from;
+	net_buffer_private *to = (net_buffer_private *)_to;
+
+	if (from == NULL || to == NULL)
+		return NULL;
+
+	ancillary_data *ancillaryData = from->ancillary_data.Head();
+	to->ancillary_data.MoveFrom(&from->ancillary_data);
+
+	return ancillaryData != NULL ? ancillaryData->Data() : NULL;
+}
+
+
+/*!
+	Returns the next ancillary data. When iterating over the data, initially
+	a \c NULL pointer shall be passed as \a previousData, subsequently the
+	previously returned data pointer. After the last item, \c NULL is returned.
+
+	Note, that it is not safe to call detach_ancillary_data() for a data item
+	and then pass that pointer to this function. First get the next item, then
+	detach the previous one.
+
+	\param buffer The buffer.
+	\param previousData The pointer to the previous data returned by this
+		function. Initially \c NULL shall be passed.
+	\param header Pointer to allocated storage into which the data description
+		is written. May be \c NULL.
+	\return A pointer to the next ancillary data in the buffer. \c NULL after
+		the last one.
+*/
+static void*
+next_ancillary_data(net_buffer *_buffer, void *previousData,
+	ancillary_data_header *_header)
+{
+	net_buffer_private *buffer = (net_buffer_private *)_buffer;
+
+	ancillary_data *ancillaryData;
+
+	if (previousData == NULL) {
+		ancillaryData = buffer->ancillary_data.Head();
+	} else {
+		ancillaryData = ancillary_data::FromData(previousData);
+		ancillaryData = buffer->ancillary_data.GetNext(ancillaryData);
+	}
+
+	if (ancillaryData == NULL)
+		return NULL;
+
+	if (_header != NULL)
+		*_header = ancillaryData->header;
+
+	return ancillaryData->Data();
+}
+
+
 /*!
 	Tries to directly access the requested space in the buffer.
 	If the space is contiguous, the function will succeed and place a pointer
@@ -1257,6 +1440,11 @@ net_buffer_module_info gNetBufferModule = {
 
 	NULL,	// associate_data
 
+	attach_ancillary_data,
+	detach_ancillary_data,
+	transfer_ancillary_data,
+	next_ancillary_data,
+
 	direct_access,
 	read_data,
 	write_data,