Index: uspace/lib/socket/packet/packet.c
===================================================================
--- uspace/lib/socket/packet/packet.c	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
+++ uspace/lib/socket/packet/packet.c	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
@@ -0,0 +1,330 @@
+/*
+ * Copyright (c) 2009 Lukas Mejdrech
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup packet
+ *  @{
+ */
+
+/** @file
+ *  Packet map and queue implementation.
+ *  This file has to be compiled with both the packet server and the client.
+ */
+
+#include <errno.h>
+#include <malloc.h>
+#include <mem.h>
+#include <fibril_synch.h>
+#include <unistd.h>
+
+#include <sys/mman.h>
+
+#include <net_err.h>
+#include <adt/generic_field.h>
+#include <packet/packet.h>
+#include <packet/packet_header.h>
+
+/** Packet map page size.
+ */
+#define PACKET_MAP_SIZE	100
+
+/** Returns the packet map page index.
+ *  @param[in] packet_id The packet identifier.
+ */
+#define PACKET_MAP_PAGE(packet_id)	(((packet_id) - 1) / PACKET_MAP_SIZE)
+
+/** Returns the packet index in the corresponding packet map page.
+ *  @param[in] packet_id The packet identifier.
+ */
+#define PACKET_MAP_INDEX(packet_id)	(((packet_id) - 1) % PACKET_MAP_SIZE)
+
+/** Type definition of the packet map page.
+ */
+typedef packet_t packet_map_t[PACKET_MAP_SIZE];
+/** Type definition of the packet map page pointer.
+ */
+typedef packet_map_t * packet_map_ref;
+
+/** Packet map.
+ *  Maps packet identifiers to the packet references.
+ *  @see generic_field.h
+ */
+GENERIC_FIELD_DECLARE(gpm, packet_map_t);
+
+/** Releases the packet.
+ *  @param[in] packet The packet to be released.
+ *  @returns EOK on success.
+ *  @returns EINVAL if the packet is not valid.
+ */
+int packet_destroy(packet_t packet);
+
+/** Packet map global data.
+ */
+static struct{
+	/** Safety lock.
+	 */
+	fibril_rwlock_t lock;
+	/** Packet map.
+	 */
+	gpm_t packet_map;
+} pm_globals;
+
+GENERIC_FIELD_IMPLEMENT(gpm, packet_map_t);
+
+int packet_destroy(packet_t packet){
+	if(! packet_is_valid(packet)){
+		return EINVAL;
+	}
+	return munmap(packet, packet->length);
+}
+
+int pm_init(void){
+	ERROR_DECLARE;
+
+	fibril_rwlock_initialize(&pm_globals.lock);
+	fibril_rwlock_write_lock(&pm_globals.lock);
+	ERROR_PROPAGATE(gpm_initialize(&pm_globals.packet_map));
+	fibril_rwlock_write_unlock(&pm_globals.lock);
+	return EOK;
+}
+
+packet_t pm_find(packet_id_t packet_id){
+	packet_map_ref map;
+	packet_t packet;
+
+	if(! packet_id){
+		return NULL;
+	}
+	fibril_rwlock_read_lock(&pm_globals.lock);
+	if(packet_id > PACKET_MAP_SIZE * gpm_count(&pm_globals.packet_map)){
+		fibril_rwlock_read_unlock(&pm_globals.lock);
+		return NULL;
+	}
+	map = gpm_get_index(&pm_globals.packet_map, PACKET_MAP_PAGE(packet_id));
+	if(! map){
+		fibril_rwlock_read_unlock(&pm_globals.lock);
+		return NULL;
+	}
+	packet = (*map)[PACKET_MAP_INDEX(packet_id)];
+	fibril_rwlock_read_unlock(&pm_globals.lock);
+	return packet;
+}
+
+int pm_add(packet_t packet){
+	ERROR_DECLARE;
+
+	packet_map_ref map;
+
+	if(! packet_is_valid(packet)){
+		return EINVAL;
+	}
+	fibril_rwlock_write_lock(&pm_globals.lock);
+	if(PACKET_MAP_PAGE(packet->packet_id) < gpm_count(&pm_globals.packet_map)){
+		map = gpm_get_index(&pm_globals.packet_map, PACKET_MAP_PAGE(packet->packet_id));
+	}else{
+		do{
+			map = (packet_map_ref) malloc(sizeof(packet_map_t));
+			if(! map){
+				fibril_rwlock_write_unlock(&pm_globals.lock);
+				return ENOMEM;
+			}
+			bzero(map, sizeof(packet_map_t));
+			if((ERROR_CODE = gpm_add(&pm_globals.packet_map, map)) < 0){
+				fibril_rwlock_write_unlock(&pm_globals.lock);
+				free(map);
+				return ERROR_CODE;
+			}
+		}while(PACKET_MAP_PAGE(packet->packet_id) >= gpm_count(&pm_globals.packet_map));
+	}
+	(*map)[PACKET_MAP_INDEX(packet->packet_id)] = packet;
+	fibril_rwlock_write_unlock(&pm_globals.lock);
+	return EOK;
+}
+
+void pm_destroy(void){
+	int count;
+	int index;
+	packet_map_ref map;
+	packet_t packet;
+
+	fibril_rwlock_write_lock(&pm_globals.lock);
+	count = gpm_count(&pm_globals.packet_map);
+	while(count > 0){
+		map = gpm_get_index(&pm_globals.packet_map, count - 1);
+		for(index = PACKET_MAP_SIZE - 1; index >= 0; -- index){
+			packet = (*map)[index];
+			if(packet_is_valid(packet)){
+				munmap(packet, packet->length);
+			}
+		}
+	}
+	gpm_destroy(&pm_globals.packet_map);
+	// leave locked
+}
+
+int pq_add(packet_t * first, packet_t packet, size_t order, size_t metric){
+	packet_t item;
+
+	if((! first) || (! packet_is_valid(packet))){
+		return EINVAL;
+	}
+	pq_set_order(packet, order, metric);
+	if(packet_is_valid(*first)){
+		item = * first;
+		do{
+			if(item->order < order){
+				if(item->next){
+					item = pm_find(item->next);
+				}else{
+					item->next = packet->packet_id;
+					packet->previous = item->packet_id;
+					return EOK;
+				}
+			}else{
+				packet->previous = item->previous;
+				packet->next = item->packet_id;
+				item->previous = packet->packet_id;
+				item = pm_find(packet->previous);
+				if(item){
+					item->next = packet->packet_id;
+				}else{
+					*first = packet;
+				}
+				return EOK;
+			}
+		}while(packet_is_valid(item));
+	}
+	*first = packet;
+	return EOK;
+}
+
+packet_t pq_find(packet_t packet, size_t order){
+	packet_t item;
+
+	if(! packet_is_valid(packet)){
+		return NULL;
+	}
+	item = packet;
+	do{
+		if(item->order == order){
+			return item;
+		}
+		item = pm_find(item->next);
+	}while(item && (item != packet) && packet_is_valid(item));
+	return NULL;
+}
+
+int pq_insert_after(packet_t packet, packet_t new_packet){
+	packet_t item;
+
+	if(!(packet_is_valid(packet) && packet_is_valid(new_packet))){
+		return EINVAL;
+	}
+	new_packet->previous = packet->packet_id;
+	new_packet->next = packet->next;
+	item = pm_find(packet->next);
+	if(item){
+		item->previous = new_packet->packet_id;
+	}
+	packet->next = new_packet->packet_id;
+	return EOK;
+}
+
+packet_t pq_detach(packet_t packet){
+	packet_t next;
+	packet_t previous;
+
+	if(! packet_is_valid(packet)){
+		return NULL;
+	}
+	next = pm_find(packet->next);
+	if(next){
+		next->previous = packet->previous;
+		previous = pm_find(next->previous);
+		if(previous){
+			previous->next = next->packet_id;
+		}
+	}
+	packet->previous = 0;
+	packet->next = 0;
+	return next;
+}
+
+int pq_set_order(packet_t packet, size_t order, size_t metric){
+	if(! packet_is_valid(packet)){
+		return EINVAL;
+	}
+	packet->order = order;
+	packet->metric = metric;
+	return EOK;
+}
+
+int pq_get_order(packet_t packet, size_t * order, size_t * metric){
+	if(! packet_is_valid(packet)){
+		return EINVAL;
+	}
+	if(order){
+		*order = packet->order;
+	}
+	if(metric){
+		*metric = packet->metric;
+	}
+	return EOK;
+}
+
+void pq_destroy(packet_t first, void (*packet_release)(packet_t packet)){
+	packet_t actual;
+	packet_t next;
+
+	actual = first;
+	while(packet_is_valid(actual)){
+		next = pm_find(actual->next);
+		actual->next = 0;
+		actual->previous = 0;
+		if(packet_release){
+			packet_release(actual);
+		}
+		actual = next;
+	}
+}
+
+packet_t pq_next(packet_t packet){
+	if(! packet_is_valid(packet)){
+		return NULL;
+	}
+	return pm_find(packet->next);
+}
+
+packet_t pq_previous(packet_t packet){
+	if(! packet_is_valid(packet)){
+		return NULL;
+	}
+	return pm_find(packet->previous);
+}
+
+/** @}
+ */
Index: uspace/lib/socket/packet/packet_client.c
===================================================================
--- uspace/lib/socket/packet/packet_client.c	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
+++ uspace/lib/socket/packet/packet_client.c	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2009 Lukas Mejdrech
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup packet
+ *  @{
+ */
+
+/** @file
+ *  Packet client implementation.
+ */
+
+#include <errno.h>
+#include <mem.h>
+#include <unistd.h>
+
+#include <sys/mman.h>
+
+#include <net_messages.h>
+#include <packet/packet.h>
+#include <packet/packet_header.h>
+#include <packet/packet_client.h>
+
+int packet_copy_data(packet_t packet, const void * data, size_t length){
+	if(! packet_is_valid(packet)){
+		return EINVAL;
+	}
+	if(packet->data_start + length >= packet->length){
+		return ENOMEM;
+	}
+	memcpy((void *) packet + packet->data_start, data, length);
+	if(packet->data_start + length > packet->data_end){
+		packet->data_end = packet->data_start + length;
+	}
+	return EOK;
+}
+
+void * packet_prefix(packet_t packet, size_t length){
+	if((! packet_is_valid(packet)) || (packet->data_start - sizeof(struct packet) - 2 * (packet->dest_addr - packet->src_addr) < length)){
+		return NULL;
+	}
+	packet->data_start -= length;
+	return (void *) packet + packet->data_start;
+}
+
+void * packet_suffix(packet_t packet, size_t length){
+	if((! packet_is_valid(packet)) || (packet->data_end + length >= packet->length)){
+		return NULL;
+	}
+	packet->data_end += length;
+	return (void *) packet + packet->data_end - length;
+}
+
+int packet_trim(packet_t packet, size_t prefix, size_t suffix){
+	if(! packet_is_valid(packet)){
+		return EINVAL;
+	}
+	if(prefix + suffix > PACKET_DATA_LENGTH(packet)){
+		return ENOMEM;
+	}
+	packet->data_start += prefix;
+	packet->data_end -= suffix;
+	return EOK;
+}
+
+packet_id_t packet_get_id(const packet_t packet){
+	return packet_is_valid(packet) ? packet->packet_id : 0;
+}
+
+int packet_get_addr(const packet_t packet, uint8_t ** src, uint8_t ** dest){
+	if(! packet_is_valid(packet)){
+		return EINVAL;
+	}
+	if(! packet->addr_len){
+		return 0;
+	}
+	if(src){
+		*src = (void *) packet + packet->src_addr;
+	}
+	if(dest){
+		*dest = (void *) packet + packet->dest_addr;
+	}
+	return packet->addr_len;
+}
+
+size_t packet_get_data_length(const packet_t packet){
+	if(! packet_is_valid(packet)){
+		return 0;
+	}
+	return PACKET_DATA_LENGTH(packet);
+}
+
+void * packet_get_data(const packet_t packet){
+	if(! packet_is_valid(packet)){
+		return NULL;
+	}
+	return (void *) packet + packet->data_start;
+}
+
+int packet_set_addr(packet_t packet, const uint8_t * src, const uint8_t * dest, size_t addr_len){
+	size_t padding;
+	size_t allocated;
+
+	if(! packet_is_valid(packet)){
+		return EINVAL;
+	}
+	allocated = PACKET_MAX_ADDRESS_LENGTH(packet);
+	if(allocated < addr_len){
+		return ENOMEM;
+	}
+	padding = allocated - addr_len;
+	packet->addr_len = addr_len;
+	if(src){
+		memcpy((void *) packet + packet->src_addr, src, addr_len);
+		if(padding){
+			bzero((void *) packet + packet->src_addr + addr_len, padding);
+		}
+	}else{
+		bzero((void *) packet + packet->src_addr, allocated);
+	}
+	if(dest){
+		memcpy((void *) packet + packet->dest_addr, dest, addr_len);
+		if(padding){
+			bzero((void *) packet + packet->dest_addr + addr_len, padding);
+		}
+	}else{
+		bzero((void *) packet + packet->dest_addr, allocated);
+	}
+	return EOK;
+}
+
+packet_t packet_get_copy(int phone, packet_t packet){
+	packet_t copy;
+	uint8_t * src;
+	uint8_t * dest;
+	size_t addrlen;
+
+	if(! packet_is_valid(packet)){
+		return NULL;
+	}
+	// get a new packet
+	copy = packet_get_4(phone, PACKET_DATA_LENGTH(packet), PACKET_MAX_ADDRESS_LENGTH(packet), packet->max_prefix, PACKET_MIN_SUFFIX(packet));
+	if(! copy){
+		return NULL;
+	}
+	// get addresses
+	addrlen = packet_get_addr(packet, &src, &dest);
+	// copy data
+	if((packet_copy_data(copy, packet_get_data(packet), PACKET_DATA_LENGTH(packet)) == EOK)
+	// copy addresses if present
+		&& ((addrlen <= 0) || (packet_set_addr(copy, src, dest, addrlen) == EOK))){
+		copy->order = packet->order;
+		copy->metric = packet->metric;
+		return copy;
+	}else{
+		pq_release(phone, copy->packet_id);
+		return NULL;
+	}
+}
+
+/** @}
+ */
Index: uspace/lib/socket/packet/packet_server.c
===================================================================
--- uspace/lib/socket/packet/packet_server.c	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
+++ uspace/lib/socket/packet/packet_server.c	(revision 849ed54afbef3ad0ec3af831e93a1353f9eaaf0f)
@@ -0,0 +1,321 @@
+/*
+ * Copyright (c) 2009 Lukas Mejdrech
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup packet
+ *  @{
+ */
+
+/** @file
+ *  Packet server implementation.
+ */
+
+#include <align.h>
+#include <assert.h>
+#include <async.h>
+#include <errno.h>
+#include <fibril_synch.h>
+#include <unistd.h>
+
+#include <ipc/ipc.h>
+#include <sys/mman.h>
+
+#include <net_err.h>
+#include <net_messages.h>
+#include <packet/packet.h>
+#include <packet/packet_client.h>
+#include <packet/packet_header.h>
+#include <packet/packet_messages.h>
+#include <packet/packet_server.h>
+
+#define FREE_QUEUES_COUNT	7
+
+/** The default address length reserved for new packets.
+ */
+#define DEFAULT_ADDR_LEN	32
+
+/** The default prefix reserved for new packets.
+ */
+#define DEFAULT_PREFIX		64
+
+/** The default suffix reserved for new packets.
+ */
+#define DEFAULT_SUFFIX		64
+
+/** Packet server global data.
+ */
+static struct{
+	/** Safety lock.
+	 */
+	fibril_mutex_t lock;
+	/** Free packet queues.
+	 */
+	packet_t free[FREE_QUEUES_COUNT];
+	/** Packet length upper bounds of the free packet queues.
+	 *  The maximal lengths of packets in each queue in the ascending order.
+	 *  The last queue is not limited.
+	 */
+	size_t sizes[FREE_QUEUES_COUNT];
+	/** Total packets allocated.
+	 */
+	unsigned int count;
+} ps_globals = {
+	.lock = {
+		.counter = 1,
+		.waiters = {
+			.prev = &ps_globals.lock.waiters,
+			.next = &ps_globals.lock.waiters,
+		}
+	},
+	.free = {NULL, NULL, NULL, NULL, NULL, NULL, NULL},
+	.sizes = {PAGE_SIZE, PAGE_SIZE * 2, PAGE_SIZE * 4, PAGE_SIZE * 8, PAGE_SIZE * 16, PAGE_SIZE * 32, PAGE_SIZE * 64},
+	.count = 0
+};
+
+int packet_translate(int phone, packet_ref packet, packet_id_t packet_id){
+	if(! packet){
+		return EINVAL;
+	}
+	*packet = pm_find(packet_id);
+	return (*packet) ? EOK : ENOENT;
+}
+
+/** Clears and initializes the packet according to the given dimensions.
+ *  @param[in] packet The packet to be initialized.
+ *  @param[in] addr_len The source and destination addresses maximal length in bytes.
+ *  @param[in] max_prefix The maximal prefix length in bytes.
+ *  @param[in] max_content The maximal content length in bytes.
+ *  @param[in] max_suffix The maximal suffix length in bytes.
+ */
+static void packet_init(packet_t packet, size_t addr_len, size_t max_prefix, size_t max_content, size_t max_suffix){
+	// clear the packet content
+	bzero(((void *) packet) + sizeof(struct packet), packet->length - sizeof(struct packet));
+	// clear the packet header
+	packet->order = 0;
+	packet->metric = 0;
+	packet->previous = 0;
+	packet->next = 0;
+	packet->addr_len = 0;
+	packet->src_addr = sizeof(struct packet);
+	packet->dest_addr = packet->src_addr + addr_len;
+	packet->max_prefix = max_prefix;
+	packet->max_content = max_content;
+	packet->data_start = packet->dest_addr + addr_len + packet->max_prefix;
+	packet->data_end = packet->data_start;
+}
+
+/** Creates a&nbsp;new packet of dimensions at least as given.
+ *  Should be used only when the global data are locked.
+ *  @param[in] length The total length of the packet, including the header, the addresses and the data of the packet.
+ *  @param[in] addr_len The source and destination addresses maximal length in bytes.
+ *  @param[in] max_prefix The maximal prefix length in bytes.
+ *  @param[in] max_content The maximal content length in bytes.
+ *  @param[in] max_suffix The maximal suffix length in bytes.
+ *  @returns The packet of dimensions at least as given.
+ *  @returns NULL if there is not enough memory left.
+ */
+static packet_t packet_create(size_t length, size_t addr_len, size_t max_prefix, size_t max_content, size_t max_suffix){
+	ERROR_DECLARE;
+
+	packet_t packet;
+
+	// already locked
+	packet = (packet_t) mmap(NULL, length, PROTO_READ | PROTO_WRITE, MAP_SHARED | MAP_ANONYMOUS, 0, 0);
+	if(packet == MAP_FAILED){
+		return NULL;
+	}
+	++ ps_globals.count;
+	packet->packet_id = ps_globals.count;
+	packet->length = length;
+	packet_init(packet, addr_len, max_prefix, max_content, max_suffix);
+	packet->magic_value = PACKET_MAGIC_VALUE;
+	if(ERROR_OCCURRED(pm_add(packet))){
+		munmap(packet, packet->length);
+		return NULL;
+	}
+	return packet;
+}
+
+/** Returns the packet of dimensions at least as given.
+ *  Tries to reuse free packets first.
+ *  Creates a&nbsp;new packet aligned to the memory page size if none available.
+ *  Locks the global data during its processing.
+ *  @param[in] addr_len The source and destination addresses maximal length in bytes.
+ *  @param[in] max_prefix The maximal prefix length in bytes.
+ *  @param[in] max_content The maximal content length in bytes.
+ *  @param[in] max_suffix The maximal suffix length in bytes.
+ *  @returns The packet of dimensions at least as given.
+ *  @returns NULL if there is not enough memory left.
+ */
+static packet_t packet_get(size_t addr_len, size_t max_prefix, size_t max_content, size_t max_suffix){
+	int index;
+	packet_t packet;
+	size_t length;
+
+	length = ALIGN_UP(sizeof(struct packet) + 2 * addr_len + max_prefix + max_content + max_suffix, PAGE_SIZE);
+	fibril_mutex_lock(&ps_globals.lock);
+	for(index = 0; index < FREE_QUEUES_COUNT - 1; ++ index){
+		if(length <= ps_globals.sizes[index]){
+			packet = ps_globals.free[index];
+			while(packet_is_valid(packet) && (packet->length < length)){
+				packet = pm_find(packet->next);
+			}
+			if(packet_is_valid(packet)){
+				if(packet == ps_globals.free[index]){
+					ps_globals.free[index] = pq_detach(packet);
+				}else{
+					pq_detach(packet);
+				}
+				packet_init(packet, addr_len, max_prefix, max_content, max_suffix);
+				fibril_mutex_unlock(&ps_globals.lock);
+				// remove debug dump
+//				printf("packet %d got\n", packet->packet_id);
+				return packet;
+			}
+		}
+	}
+	packet = packet_create(length, addr_len, max_prefix, max_content, max_suffix);
+	fibril_mutex_unlock(&ps_globals.lock);
+	// remove debug dump
+//	printf("packet %d created\n", packet->packet_id);
+	return packet;
+}
+
+packet_t packet_get_4(int phone, size_t max_content, size_t addr_len, size_t max_prefix, size_t max_suffix){
+	return packet_get(addr_len, max_prefix, max_content, max_suffix);
+}
+
+packet_t packet_get_1(int phone, size_t content){
+	return packet_get(DEFAULT_ADDR_LEN, DEFAULT_PREFIX, content, DEFAULT_SUFFIX);
+}
+
+/** Releases the packet and returns it to the appropriate free packet queue.
+ *  Should be used only when the global data are locked.
+ *  @param[in] packet The packet to be released.
+ */
+static void packet_release(packet_t packet){
+	int index;
+	int result;
+
+	// remove debug dump
+//	printf("packet %d released\n", packet->packet_id);
+	for(index = 0; (index < FREE_QUEUES_COUNT - 1) && (packet->length > ps_globals.sizes[index]); ++ index);
+	result = pq_add(&ps_globals.free[index], packet, packet->length, packet->length);
+	assert(result == EOK);
+}
+
+/** Releases the packet queue.
+ *  @param[in] packet_id The first packet identifier.
+ *  @returns EOK on success.
+ *  @returns ENOENT if there is no such packet.
+ */
+static int packet_release_wrapper(packet_id_t packet_id){
+	packet_t packet;
+
+	packet = pm_find(packet_id);
+	if(! packet_is_valid(packet)){
+		return ENOENT;
+	}
+	fibril_mutex_lock(&ps_globals.lock);
+	pq_destroy(packet, packet_release);
+	fibril_mutex_unlock(&ps_globals.lock);
+	return EOK;
+}
+
+void pq_release(int phone, packet_id_t packet_id){
+	(void) packet_release_wrapper(packet_id);
+}
+
+/** Shares the packet memory block.
+ *  @param[in] packet The packet to be shared.
+ *  @returns EOK on success.
+ *  @returns EINVAL if the packet is not valid.
+ *  @returns EINVAL if the calling module does not accept the memory.
+ *  @returns ENOMEM if the desired and actual sizes differ.
+ *  @returns Other error codes as defined for the async_share_in_finalize() function.
+ */
+static int packet_reply(const packet_t packet){
+	ipc_callid_t callid;
+	size_t size;
+
+	if(! packet_is_valid(packet)){
+		return EINVAL;
+	}
+	if(async_share_in_receive(&callid, &size) <= 0) return EINVAL;
+	if(size != packet->length){
+		return ENOMEM;
+	}
+	return async_share_in_finalize(callid, packet, PROTO_READ | PROTO_WRITE);
+}
+
+int packet_server_message(ipc_callid_t callid, ipc_call_t * call, ipc_call_t * answer, int * answer_count){
+	packet_t packet;
+
+	*answer_count = 0;
+	switch(IPC_GET_METHOD(*call)){
+		case IPC_M_PHONE_HUNGUP:
+			return EOK;
+		case NET_PACKET_CREATE_1:
+			packet = packet_get(DEFAULT_ADDR_LEN, DEFAULT_PREFIX, IPC_GET_CONTENT(call), DEFAULT_SUFFIX);
+			if(! packet){
+				return ENOMEM;
+			}
+			*answer_count = 2;
+			IPC_SET_ARG1(*answer, (ipcarg_t) packet->packet_id);
+			IPC_SET_ARG2(*answer, (ipcarg_t) packet->length);
+			return EOK;
+		case NET_PACKET_CREATE_4:
+			packet = packet_get(((DEFAULT_ADDR_LEN < IPC_GET_ADDR_LEN(call)) ? IPC_GET_ADDR_LEN(call) : DEFAULT_ADDR_LEN), DEFAULT_PREFIX + IPC_GET_PREFIX(call), IPC_GET_CONTENT(call), DEFAULT_SUFFIX + IPC_GET_SUFFIX(call));
+			if(! packet){
+				return ENOMEM;
+			}
+			*answer_count = 2;
+			IPC_SET_ARG1(*answer, (ipcarg_t) packet->packet_id);
+			IPC_SET_ARG2(*answer, (ipcarg_t) packet->length);
+			return EOK;
+		case NET_PACKET_GET:
+			packet = pm_find(IPC_GET_ID(call));
+			if(! packet_is_valid(packet)){
+				return ENOENT;
+			}
+			return packet_reply(packet);
+		case NET_PACKET_GET_SIZE:
+			packet = pm_find(IPC_GET_ID(call));
+			if(! packet_is_valid(packet)){
+				return ENOENT;
+			}
+			IPC_SET_ARG1(*answer, (ipcarg_t) packet->length);
+			*answer_count = 1;
+			return EOK;
+		case NET_PACKET_RELEASE:
+			return packet_release_wrapper(IPC_GET_ID(call));
+	}
+	return ENOTSUP;
+}
+
+/** @}
+ */
