Index: uspace/lib/c/Makefile
===================================================================
--- uspace/lib/c/Makefile	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ uspace/lib/c/Makefile	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -67,5 +67,7 @@
 	generic/devman.c \
 	generic/device/hw_res.c \
+	generic/device/hw_res_parsed.c \
 	generic/device/char_dev.c \
+	generic/device/nic.c \
 	generic/elf/elf_load.c \
 	generic/event.c \
@@ -103,4 +105,5 @@
 	generic/adt/list.c \
 	generic/adt/hash_table.c \
+	generic/adt/hash_set.c \
 	generic/adt/dynamic_fifo.c \
 	generic/adt/measured_strings.c \
Index: uspace/lib/c/generic/adt/hash_set.c
===================================================================
--- uspace/lib/c/generic/adt/hash_set.c	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
+++ uspace/lib/c/generic/adt/hash_set.c	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -0,0 +1,382 @@
+/*
+ * Copyright (c) 2008 Jakub Jermar
+ * Copyright (c) 2011 Radim Vansa
+ * 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 libc
+ * @{
+ */
+/** @file
+ */
+
+#include <adt/hash_set.h>
+#include <adt/list.h>
+#include <unistd.h>
+#include <malloc.h>
+#include <assert.h>
+#include <str.h>
+
+/** Create chained hash set
+ *
+ * @param     h         Hash set structure to be initialized.
+ * @param[in] hash      Hash function
+ * @param[in] equals    Equals function
+ * @param[in] init_size Initial hash set size
+ *
+ * @return True on success
+ *
+ */
+int hash_set_init(hash_set_t *h, hash_set_hash hash, hash_set_equals equals,
+    size_t init_size)
+{
+	assert(h);
+	assert(hash);
+	assert(equals);
+	
+	if (init_size < HASH_SET_MIN_SIZE)
+		init_size = HASH_SET_MIN_SIZE;
+	
+	h->table = malloc(init_size * sizeof(link_t));
+	if (!h->table)
+		return false;
+	
+	for (size_t i = 0; i < init_size; i++)
+		list_initialize(&h->table[i]);
+	
+	h->size = init_size;
+	h->count = 0;
+	h->hash = hash;
+	h->equals = equals;
+	
+	return true;
+}
+
+/** Destroy a hash table instance.
+ *
+ * @param h Hash table to be destroyed.
+ *
+ */
+void hash_set_destroy(hash_set_t *h)
+{
+	assert(h);
+	free(h->table);
+}
+
+/** Rehash the internal table to new table
+ *
+ * @param h         Original hash set
+ * @param new_table Memory for the new table
+ * @param new_size  Size of the new table
+ */
+static void hash_set_rehash(hash_set_t *h, list_t *new_table,
+    size_t new_size)
+{
+	assert(new_size >= HASH_SET_MIN_SIZE);
+	
+	for (size_t bucket = 0; bucket < new_size; bucket++)
+		list_initialize(&new_table[bucket]);
+	
+	for (size_t bucket = 0; bucket < h->size; bucket++) {
+		link_t *cur;
+		link_t *next;
+		
+		for (cur = h->table[bucket].head.next;
+		    cur != &h->table[bucket].head;
+		    cur = next) {
+			next = cur->next;
+			list_append(cur, &new_table[h->hash(cur) % new_size]);
+		}
+	}
+	
+	list_t *old_table = h->table;
+	h->table = new_table;
+	free(old_table);
+	h->size = new_size;
+}
+
+/** Insert item into the set.
+ *
+ * If the set already contains equivalent object,
+ * the function fails.
+ *
+ * @param h    Hash table.
+ * @param key  Array of all keys necessary to compute hash index.
+ * @param item Item to be inserted into the hash table.
+ *
+ * @return True if the object was inserted
+ * @return Ffalse if the set already contained equivalent object.
+ *
+ */
+int hash_set_insert(hash_set_t *h, link_t *item)
+{
+	assert(item);
+	assert(h);
+	assert(h->hash);
+	assert(h->equals);
+	
+	unsigned long hash = h->hash(item);
+	unsigned long chain = hash % h->size;
+	
+	list_foreach(h->table[chain], cur) {
+		if (h->equals(cur, item))
+			return false;
+	}
+	
+	if (h->count + 1 > h->size) {
+		size_t new_size = h->size * 2;
+		list_t *temp = malloc(new_size * sizeof(list_t));
+		if (temp != NULL)
+			hash_set_rehash(h, temp, new_size);
+		
+		/*
+		 * If the allocation fails, just use the same
+		 * old table and try to rehash next time.
+		 */
+		chain = hash % h->size;
+	}
+	
+	h->count++;
+	list_append(item, &h->table[chain]);
+	
+	return true;
+}
+
+/** Search the hash set for a matching object and return it
+ *
+ * @param h    Hash set
+ * @param item The item that should equal to the matched object
+ *
+ * @return Matching item on success, NULL if there is no such item.
+ *
+ */
+link_t *hash_set_find(hash_set_t *h, const link_t *item)
+{
+	assert(h);
+	assert(h->hash);
+	assert(h->equals);
+	
+	unsigned long chain = h->hash(item) % h->size;
+	
+	list_foreach(h->table[chain], cur) {
+		if (h->equals(cur, item))
+			return cur;
+	}
+	
+	return NULL;
+}
+
+/** Remove first matching object from the hash set and return it
+ *
+ * @param h    Hash set.
+ * @param item The item that should be equal to the matched object
+ *
+ * @return The removed item or NULL if this is not found.
+ *
+ */
+link_t *hash_set_remove(hash_set_t *h, const link_t *item)
+{
+	assert(h);
+	assert(h->hash);
+	assert(h->equals);
+	
+	link_t *cur = hash_set_find(h, item);
+	if (cur) {
+		list_remove(cur);
+		
+		h->count--;
+		if (4 * h->count < h->size && h->size > HASH_SET_MIN_SIZE) {
+			size_t new_size = h->size / 2;
+			if (new_size < HASH_SET_MIN_SIZE)
+				/* possible e.g. if init_size == HASH_SET_MIN_SIZE + 1 */
+				new_size = HASH_SET_MIN_SIZE;
+			
+			list_t *temp = malloc(new_size * sizeof (list_t));
+			if (temp != NULL)
+				hash_set_rehash(h, temp, new_size);
+		}
+	}
+	
+	return cur;
+}
+
+/** Remove all elements for which the function returned non-zero
+ *
+ * The function can also destroy the element.
+ *
+ * @param h   Hash set.
+ * @param f   Function to be applied.
+ * @param arg Argument to be passed to the function.
+ *
+ */
+void hash_set_remove_selected(hash_set_t *h, int (*f)(link_t *, void *),
+    void *arg)
+{
+	assert(h);
+	assert(h->table);
+	
+	for (size_t bucket = 0; bucket < h->size; bucket++) {
+		link_t *prev = &h->table[bucket].head;
+		link_t *cur;
+		link_t *next;
+		
+		for (cur = h->table[bucket].head.next;
+		    cur != &h->table[bucket].head;
+		    cur = next) {
+			next = cur->next;
+			if (f(cur, arg)) {
+				prev->next = next;
+				next->prev = prev;
+				h->count--;
+			} else
+				prev = cur;
+		}
+	}
+	
+	if (4 * h->count < h->size && h->size > HASH_SET_MIN_SIZE) {
+		size_t new_size = h->size / 2;
+		if (new_size < HASH_SET_MIN_SIZE)
+			/* possible e.g. if init_size == HASH_SET_MIN_SIZE + 1 */
+			new_size = HASH_SET_MIN_SIZE;
+		
+		list_t *temp = malloc(new_size * sizeof (list_t));
+		if (temp != NULL)
+			hash_set_rehash(h, temp, new_size);
+	}
+}
+
+/** Apply function to all items in hash set
+ *
+ * @param h   Hash set.
+ * @param f   Function to be applied.
+ * @param arg Argument to be passed to the function.
+ *
+ */
+void hash_set_apply(hash_set_t *h, void (*f)(link_t *, void *), void *arg)
+{
+	assert(h);
+	assert(h->table);
+	
+	for (size_t bucket = 0; bucket < h->size; bucket++) {
+		link_t *cur;
+		link_t *next;
+		
+		for (cur = h->table[bucket].head.next;
+		    cur != &h->table[bucket].head;
+		    cur = next) {
+			
+			/*
+			 * The next pointer must be stored prior to the functor
+			 * call to allow using destructor as the functor (the
+			 * free function could overwrite the cur->next pointer).
+			 */
+			next = cur->next;
+			f(cur, arg);
+		}
+	}
+}
+
+/** Remove all elements from the set.
+ *
+ * The table is reallocated to the minimum size.
+ *
+ * @param h   Hash set
+ * @param f   Function (destructor?) applied to all element. Can be NULL.
+ * @param arg Argument to the destructor.
+ *
+ */
+void hash_set_clear(hash_set_t *h, void (*f)(link_t *, void *), void *arg)
+{
+	assert(h);
+	assert(h->table);
+	
+	for (size_t bucket = 0; bucket < h->size; bucket++) {
+		link_t *cur;
+		link_t *next;
+		
+		for (cur = h->table[bucket].head.next;
+		    cur != &h->table[bucket].head;
+		    cur = next) {
+			next = cur->next;
+			list_remove(cur);
+			if (f != NULL)
+				f(cur, arg);
+		}
+	}
+	
+	assert(h->size >= HASH_SET_MIN_SIZE);
+	list_t *new_table =
+	    realloc(h->table, HASH_SET_MIN_SIZE * sizeof(list_t));
+	
+	/* We are shrinking, therefore we shouldn't get NULL */
+	assert(new_table);
+	
+	if (h->table != new_table) {
+		/* Init the lists, pointers to itself are used in them */
+		for (size_t bucket = 0; bucket < HASH_SET_MIN_SIZE; ++bucket)
+			list_initialize(&new_table[bucket]);
+		
+		h->table = new_table;
+	}
+	
+	h->count = 0;
+	h->size = HASH_SET_MIN_SIZE;
+}
+
+/** Get hash set size
+ *
+ * @param hHash set
+ *
+ * @return Number of elements in the set.
+ *
+ */
+size_t hash_set_count(const hash_set_t *h)
+{
+	assert(h);
+	return h->count;
+}
+
+/** Check whether element is contained in the hash set
+ *
+ * @param h    Hash set
+ * @param item Item that should be equal to the matched object
+ *
+ * @return True if the hash set contains equal object
+ * @return False otherwise
+ *
+ */
+int hash_set_contains(const hash_set_t *h, const link_t *item)
+{
+	/*
+	 * The hash_set_find cannot accept constant hash set,
+	 * because we can modify the returned element. But in
+	 * this case we are using it safely.
+	 */
+	return hash_set_find((hash_set_t *) h, item) != NULL;
+}
+
+/** @}
+ */
Index: uspace/lib/c/generic/adt/hash_table.c
===================================================================
--- uspace/lib/c/generic/adt/hash_table.c	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ uspace/lib/c/generic/adt/hash_table.c	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -76,4 +76,24 @@
 	
 	return true;
+}
+
+/** Remove all elements from the hash table
+ *
+ * @param h Hash table to be cleared
+ */
+void hash_table_clear(hash_table_t *h)
+{
+	for (hash_count_t chain = 0; chain < h->entries; ++chain) {
+		link_t *cur;
+		link_t *next;
+		
+		for (cur = h->entry[chain].head.next;
+		    cur != &h->entry[chain].head;
+		    cur = next) {
+			next = cur->next;
+			list_remove(cur);
+			h->op->remove_callback(cur);
+		}
+	}
 }
 
@@ -198,9 +218,17 @@
  */
 void hash_table_apply(hash_table_t *h, void (*f)(link_t *, void *), void *arg)
-{
-	hash_index_t bucket;
-	
-	for (bucket = 0; bucket < h->entries; bucket++) {
-		list_foreach(h->entry[bucket], cur) {
+{	
+	for (hash_index_t bucket = 0; bucket < h->entries; bucket++) {
+		link_t *cur;
+		link_t *next;
+
+		for (cur = h->entry[bucket].head.next; cur != &h->entry[bucket].head;
+		    cur = next) {
+			/*
+			 * The next pointer must be stored prior to the functor
+			 * call to allow using destructor as the functor (the
+			 * free function could overwrite the cur->next pointer).
+			 */
+			next = cur->next;
 			f(cur, arg);
 		}
Index: uspace/lib/c/generic/device/hw_res_parsed.c
===================================================================
--- uspace/lib/c/generic/device/hw_res_parsed.c	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
+++ uspace/lib/c/generic/device/hw_res_parsed.c	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2011 Jiri Michalec
+ * 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 libc
+ * @{
+ */
+/** @file
+ */
+
+#include <device/hw_res_parsed.h>
+#include <malloc.h>
+#include <assert.h>
+#include <errno.h>
+
+static void hw_res_parse_add_irq(hw_res_list_parsed_t *out, hw_resource_t *res,
+    int flags)
+{
+	assert(res && (res->type == INTERRUPT));
+	
+	int irq = res->res.interrupt.irq;
+	size_t count = out->irqs.count;
+	int keep_duplicit = flags & HW_RES_KEEP_DUPLICIT;
+	
+	if (!keep_duplicit) {
+		for (size_t i = 0; i < count; i++) {
+			if (out->irqs.irqs[i] == irq)
+				return;
+		}
+	}
+	
+	out->irqs.irqs[count] = irq;
+	out->irqs.count++;
+}
+
+static void hw_res_parse_add_io_range(hw_res_list_parsed_t *out,
+    hw_resource_t *res, int flags)
+{
+	assert(res && (res->type == IO_RANGE));
+	
+	uint64_t address = res->res.io_range.address;
+	endianness_t endianness = res->res.io_range.endianness;
+	size_t size = res->res.io_range.size;
+	
+	if ((size == 0) && (!(flags & HW_RES_KEEP_ZERO_AREA)))
+		return;
+	
+	int keep_duplicit = flags & HW_RES_KEEP_DUPLICIT;
+	size_t count = out->io_ranges.count;
+	
+	if (!keep_duplicit) {
+		for (size_t i = 0; i < count; i++) {
+			uint64_t s_address = out->io_ranges.ranges[i].address;
+			size_t s_size = out->io_ranges.ranges[i].size;
+			
+			if ((address == s_address) && (size == s_size))
+				return;
+		}
+	}
+	
+	out->io_ranges.ranges[count].address = address;
+	out->io_ranges.ranges[count].endianness = endianness;
+	out->io_ranges.ranges[count].size = size;
+	out->io_ranges.count++;
+}
+
+static void hw_res_parse_add_mem_range(hw_res_list_parsed_t *out,
+    hw_resource_t *res, int flags)
+{
+	assert(res && (res->type == MEM_RANGE));
+	
+	uint64_t address = res->res.mem_range.address;
+	endianness_t endianness = res->res.mem_range.endianness;
+	size_t size = res->res.mem_range.size;
+	
+	if ((size == 0) && (!(flags & HW_RES_KEEP_ZERO_AREA)))
+		return;
+	
+	int keep_duplicit = flags & HW_RES_KEEP_DUPLICIT;
+	size_t count = out->mem_ranges.count;
+	
+	if (!keep_duplicit) {
+		for (size_t i = 0; i < count; ++i) {
+			uint64_t s_address = out->mem_ranges.ranges[i].address;
+			size_t s_size = out->mem_ranges.ranges[i].size;
+			
+			if ((address == s_address) && (size == s_size))
+				return;
+		}
+	}
+	
+	out->mem_ranges.ranges[count].address = address;
+	out->mem_ranges.ranges[count].endianness = endianness;
+	out->mem_ranges.ranges[count].size = size;
+	out->mem_ranges.count++;
+}
+
+/** Parse list of hardware resources
+ *
+ * @param      hw_resources Original structure resource
+ * @param[out] out          Output parsed resources
+ * @param      flags        Flags of the parsing.
+ *                          HW_RES_KEEP_ZERO_AREA for keeping
+ *                          zero-size areas, HW_RES_KEEP_DUPLICITIES
+ *                          for keep duplicit areas
+ *
+ * @return EOK if succeed, error code otherwise.
+ *
+ */
+int hw_res_list_parse(hw_resource_list_t *hw_resources,
+    hw_res_list_parsed_t *out, int flags)
+{
+	if ((!hw_resources) || (!out))
+		return EINVAL;
+	
+	size_t res_count = hw_resources->count;
+	hw_res_list_parsed_clean(out);
+	
+	out->irqs.irqs = malloc(res_count * sizeof(int));
+	out->io_ranges.ranges = malloc(res_count * sizeof(io_range_t));
+	out->mem_ranges.ranges = malloc(res_count * sizeof(mem_range_t));
+	
+	for (size_t i = 0; i < res_count; ++i) {
+		hw_resource_t *resource = &(hw_resources->resources[i]);
+		
+		switch (resource->type) {
+		case INTERRUPT:
+			hw_res_parse_add_irq(out, resource, flags);
+			break;
+		case IO_RANGE:
+			hw_res_parse_add_io_range(out, resource, flags);
+			break;
+		case MEM_RANGE:
+			hw_res_parse_add_mem_range(out, resource, flags);
+			break;
+		default:
+			return EINVAL;
+		}
+	}
+	
+	return EOK;
+};
+
+/** Get hw_resources from the parent device.
+ *
+ * The output must be inited, will be cleared
+ *
+ * @see get_hw_resources
+ * @see hw_resources_parse
+ *
+ * @param sess                Session to the parent device
+ * @param hw_resources_parsed Output list
+ * @param flags               Parsing flags
+ *
+ * @return EOK if succeed, error code otherwise
+ *
+ */
+int hw_res_get_list_parsed(async_sess_t *sess,
+    hw_res_list_parsed_t *hw_res_parsed, int flags)
+{
+	if (!hw_res_parsed)
+		return EBADMEM;
+	
+	hw_resource_list_t hw_resources;
+	hw_res_list_parsed_clean(hw_res_parsed);
+	bzero(&hw_resources, sizeof(hw_resource_list_t));
+	
+	int rc = hw_res_get_resource_list(sess, &hw_resources);
+	if (rc != EOK)
+		return rc;
+	
+	rc = hw_res_list_parse(&hw_resources, hw_res_parsed, flags);
+	hw_res_clean_resource_list(&hw_resources);
+	
+	return rc;
+};
+
+/** @}
+ */
Index: uspace/lib/c/generic/device/nic.c
===================================================================
--- uspace/lib/c/generic/device/nic.c	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
+++ uspace/lib/c/generic/device/nic.c	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -0,0 +1,1271 @@
+/*
+ * Copyright (c) 2011 Radim Vansa
+ * 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 libc
+ * @{
+ */
+/**
+ * @file
+ * @brief Client-side RPC stubs for DDF NIC
+ */
+
+#include <ipc/dev_iface.h>
+#include <assert.h>
+#include <device/nic.h>
+#include <errno.h>
+#include <async.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <ipc/services.h>
+
+/** Send a packet through the device
+ *
+ * @param[in] dev_sess
+ * @param[in] packet_id Id of the sent packet
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_send_message(async_sess_t *dev_sess, packet_id_t packet_id)
+{
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_2_0(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_SEND_MESSAGE, packet_id);
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+/** Connect the driver to the NET and NIL services
+ *
+ * @param[in] dev_sess
+ * @param[in] nil_service Service identifier for the NIL service
+ * @param[in] device_id
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_connect_to_nil(async_sess_t *dev_sess, services_t nil_service,
+    nic_device_id_t device_id)
+{
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_3_0(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_CONNECT_TO_NIL, nil_service, device_id);
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+/** Get the current state of the device
+ *
+ * @param[in]  dev_sess
+ * @param[out] state    Current state
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_get_state(async_sess_t *dev_sess, nic_device_state_t *state)
+{
+	assert(state);
+	
+	sysarg_t _state;
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_1_1(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_GET_STATE, &_state);
+	async_exchange_end(exch);
+	
+	*state = (nic_device_state_t) _state;
+	
+	return rc;
+}
+
+/** Request the device to change its state
+ *
+ * @param[in] dev_sess
+ * @param[in] state    New state
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_set_state(async_sess_t *dev_sess, nic_device_state_t state)
+{
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_2_0(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_SET_STATE, state);
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+/** Request the MAC address of the device
+ *
+ * @param[in]  dev_sess
+ * @param[out] address  Structure with buffer for the address
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_get_address(async_sess_t *dev_sess, nic_address_t *address)
+{
+	assert(address);
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	aid_t aid = async_send_1(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_GET_ADDRESS, NULL);
+	int rc = async_data_read_start(exch, address, sizeof(nic_address_t));
+	async_exchange_end(exch);
+	
+	sysarg_t res;
+	async_wait_for(aid, &res);
+	
+	if (rc != EOK)
+		return rc;
+	
+	return (int) res;
+}
+
+/** Set the address of the device (e.g. MAC on Ethernet)
+ *
+ * @param[in] dev_sess
+ * @param[in] address  Pointer to the address
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_set_address(async_sess_t *dev_sess, const nic_address_t *address)
+{
+	assert(address);
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	aid_t aid = async_send_1(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_SET_ADDRESS, NULL);
+	int rc = async_data_write_start(exch, address, sizeof(nic_address_t));
+	async_exchange_end(exch);
+	
+	sysarg_t res;
+	async_wait_for(aid, &res);
+	
+	if (rc != EOK)
+		return rc;
+	
+	return (int) res;
+}
+
+/** Request statistic data about NIC operation.
+ *
+ * @param[in]  dev_sess
+ * @param[out] stats    Structure with the statistics
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_get_stats(async_sess_t *dev_sess, nic_device_stats_t *stats)
+{
+	assert(stats);
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	
+	int rc = async_req_1_0(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_GET_STATS);
+	if (rc != EOK) {
+		async_exchange_end(exch);
+		return rc;
+	}
+	
+	rc = async_data_read_start(exch, stats, sizeof(nic_device_stats_t));
+	
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+/** Request information about the device.
+ *
+ * @see nic_device_info_t
+ *
+ * @param[in]  dev_sess
+ * @param[out] device_info Information about the device
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_get_device_info(async_sess_t *dev_sess, nic_device_info_t *device_info)
+{
+	assert(device_info);
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	
+	int rc = async_req_1_0(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_GET_DEVICE_INFO);
+	if (rc != EOK) {
+		async_exchange_end(exch);
+		return rc;
+	}
+	
+	rc = async_data_read_start(exch, device_info, sizeof(nic_device_info_t));
+	
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+/** Request status of the cable (plugged/unplugged)
+ *
+ * @param[in]  dev_sess
+ * @param[out] cable_state Current cable state
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_get_cable_state(async_sess_t *dev_sess, nic_cable_state_t *cable_state)
+{
+	assert(cable_state);
+	
+	sysarg_t _cable_state;
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_1_1(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_GET_CABLE_STATE, &_cable_state);
+	async_exchange_end(exch);
+	
+	*cable_state = (nic_cable_state_t) _cable_state;
+	
+	return rc;
+}
+
+/** Request current operation mode.
+ *
+ * @param[in]  dev_sess
+ * @param[out] speed    Current operation speed in Mbps. Can be NULL.
+ * @param[out] duplex   Full duplex/half duplex. Can be NULL.
+ * @param[out] role     Master/slave/auto. Can be NULL.
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_get_operation_mode(async_sess_t *dev_sess, int *speed,
+   nic_channel_mode_t *duplex, nic_role_t *role)
+{
+	sysarg_t _speed;
+	sysarg_t _duplex;
+	sysarg_t _role;
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_1_3(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_GET_OPERATION_MODE, &_speed, &_duplex, &_role);
+	async_exchange_end(exch);
+	
+	if (speed)
+		*speed = (int) _speed;
+	
+	if (duplex)
+		*duplex = (nic_channel_mode_t) _duplex;
+	
+	if (role)
+		*role = (nic_role_t) _role;
+	
+	return rc;
+}
+
+/** Set current operation mode.
+ *
+ * If the NIC has auto-negotiation enabled, this command
+ * disables auto-negotiation and sets the operation mode.
+ *
+ * @param[in] dev_sess
+ * @param[in] speed    Operation speed in Mbps
+ * @param[in] duplex   Full duplex/half duplex
+ * @param[in] role     Master/slave/auto (e.g. in Gbit Ethernet]
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_set_operation_mode(async_sess_t *dev_sess, int speed,
+    nic_channel_mode_t duplex, nic_role_t role)
+{
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_4_0(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_SET_OPERATION_MODE, (sysarg_t) speed, (sysarg_t) duplex,
+	    (sysarg_t) role);
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+/** Enable auto-negotiation.
+ *
+ * The advertisement argument can only limit some modes,
+ * it can never force the NIC to advertise unsupported modes.
+ *
+ * The allowed modes are defined in "net/eth_phys.h" in the C library.
+ *
+ * @param[in] dev_sess
+ * @param[in] advertisement Allowed advertised modes. Use 0 for all modes.
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_autoneg_enable(async_sess_t *dev_sess, uint32_t advertisement)
+{
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_2_0(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_AUTONEG_ENABLE, (sysarg_t) advertisement);
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+/** Disable auto-negotiation.
+ *
+ * @param[in] dev_sess
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_autoneg_disable(async_sess_t *dev_sess)
+{
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_1_0(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_AUTONEG_DISABLE);
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+/** Probe current state of auto-negotiation.
+ *
+ * Modes are defined in the "net/eth_phys.h" in the C library.
+ *
+ * @param[in]  dev_sess
+ * @param[out] our_advertisement   Modes advertised by this NIC.
+ *                                 Can be NULL.
+ * @param[out] their_advertisement Modes advertised by the other side.
+ *                                 Can be NULL.
+ * @param[out] result              General state of auto-negotiation.
+ *                                 Can be NULL.
+ * @param[out]  their_result       State of other side auto-negotiation.
+ *                                 Can be NULL.
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_autoneg_probe(async_sess_t *dev_sess, uint32_t *our_advertisement,
+    uint32_t *their_advertisement, nic_result_t *result,
+    nic_result_t *their_result)
+{
+	sysarg_t _our_advertisement;
+	sysarg_t _their_advertisement;
+	sysarg_t _result;
+	sysarg_t _their_result;
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_1_4(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_AUTONEG_PROBE, &_our_advertisement, &_their_advertisement,
+	    &_result, &_their_result);
+	async_exchange_end(exch);
+	
+	if (our_advertisement)
+		*our_advertisement = (uint32_t) _our_advertisement;
+	
+	if (*their_advertisement)
+		*their_advertisement = (uint32_t) _their_advertisement;
+	
+	if (result)
+		*result = (nic_result_t) _result;
+	
+	if (their_result)
+		*their_result = (nic_result_t) _their_result;
+	
+	return rc;
+}
+
+/** Restart the auto-negotiation process.
+ *
+ * @param[in] dev_sess
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_autoneg_restart(async_sess_t *dev_sess)
+{
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_1_0(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_AUTONEG_RESTART);
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+/** Query party's sending and reception of the PAUSE frame.
+ *
+ * @param[in]  dev_sess
+ * @param[out] we_send    This NIC sends the PAUSE frame (true/false)
+ * @param[out] we_receive This NIC receives the PAUSE frame (true/false)
+ * @param[out] pause      The time set to transmitted PAUSE frames.
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_get_pause(async_sess_t *dev_sess, nic_result_t *we_send,
+    nic_result_t *we_receive, uint16_t *pause)
+{
+	sysarg_t _we_send;
+	sysarg_t _we_receive;
+	sysarg_t _pause;
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_1_3(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_GET_PAUSE, &_we_send, &_we_receive, &_pause);
+	async_exchange_end(exch);
+	
+	if (we_send)
+		*we_send = _we_send;
+	
+	if (we_receive)
+		*we_receive = _we_receive;
+	
+	if (pause)
+		*pause = _pause;
+	
+	return rc;
+}
+
+/** Control sending and reception of the PAUSE frame.
+ *
+ * @param[in] dev_sess
+ * @param[in] allow_send    Allow sending the PAUSE frame (true/false)
+ * @param[in] allow_receive Allow reception of the PAUSE frame (true/false)
+ * @param[in] pause         Pause length in 512 bit units written
+ *                          to transmitted frames. The value 0 means
+ *                          auto value (the best). If the requested
+ *                          time cannot be set the driver is allowed
+ *                          to set the nearest supported value.
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_set_pause(async_sess_t *dev_sess, int allow_send, int allow_receive,
+    uint16_t pause)
+{
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_4_0(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_SET_PAUSE, allow_send, allow_receive, pause);
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+/** Retrieve current settings of unicast frames reception.
+ *
+ * Note: In case of mode != NIC_UNICAST_LIST the contents of
+ * address_list and address_count are undefined.
+ *
+ * @param[in]   dev_sess
+ * @param[out]  mode          Current operation mode
+ * @param[in]   max_count     Maximal number of addresses that could
+ *                            be written into the list buffer.
+ * @param[out]  address_list  Buffer for the list (array). Can be NULL.
+ * @param[out]  address_count Number of addresses in the list before
+ *                            possible truncation due to the max_count.
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_unicast_get_mode(async_sess_t *dev_sess, nic_unicast_mode_t *mode,
+    size_t max_count, nic_address_t *address_list, size_t *address_count)
+{
+	assert(mode);
+	
+	sysarg_t _mode;
+	sysarg_t _address_count;
+	
+	if (!address_list)
+		max_count = 0;
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	
+	int rc = async_req_2_2(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_UNICAST_GET_MODE, max_count, &_mode, &_address_count);
+	if (rc != EOK) {
+		async_exchange_end(exch);
+		return rc;
+	}
+	
+	*mode = (nic_unicast_mode_t) _mode;
+	if (address_count)
+		*address_count = (size_t) _address_count;
+	
+	if ((max_count) && (_address_count))
+		rc = async_data_read_start(exch, address_list,
+		    max_count * sizeof(nic_address_t));
+	
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+/** Set which unicast frames are received.
+ *
+ * @param[in] dev_sess
+ * @param[in] mode          Current operation mode
+ * @param[in] address_list  The list of addresses. Can be NULL.
+ * @param[in] address_count Number of addresses in the list.
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_unicast_set_mode(async_sess_t *dev_sess, nic_unicast_mode_t mode,
+    const nic_address_t *address_list, size_t address_count)
+{
+	if (address_list == NULL)
+		address_count = 0;
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	
+	aid_t message_id = async_send_3(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_UNICAST_SET_MODE, (sysarg_t) mode, address_count, NULL);
+	
+	int rc;
+	if (address_count)
+		rc = async_data_write_start(exch, address_list,
+		    address_count * sizeof(nic_address_t));
+	else
+		rc = EOK;
+	
+	async_exchange_end(exch);
+	
+	sysarg_t res;
+	async_wait_for(message_id, &res);
+	
+	if (rc != EOK)
+		return rc;
+	
+	return (int) res;
+}
+
+/** Retrieve current settings of multicast frames reception.
+ *
+ * Note: In case of mode != NIC_MULTICAST_LIST the contents of
+ * address_list and address_count are undefined.
+ *
+ * @param[in]  dev_sess
+ * @param[out] mode          Current operation mode
+ * @param[in]  max_count     Maximal number of addresses that could
+ *                           be written into the list buffer.
+ * @param[out] address_list  Buffer for the list (array). Can be NULL.
+ * @param[out] address_count Number of addresses in the list before
+ *                           possible truncation due to the max_count.
+ *                           Can be NULL.
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_multicast_get_mode(async_sess_t *dev_sess, nic_multicast_mode_t *mode,
+    size_t max_count, nic_address_t *address_list, size_t *address_count)
+{
+	assert(mode);
+	
+	sysarg_t _mode;
+	
+	if (!address_list)
+		max_count = 0;
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	
+	sysarg_t ac;
+	int rc = async_req_2_2(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_MULTICAST_GET_MODE, max_count, &_mode, &ac);
+	if (rc != EOK) {
+		async_exchange_end(exch);
+		return rc;
+	}
+	
+	*mode = (nic_multicast_mode_t) _mode;
+	if (address_count)
+		*address_count = (size_t) ac;
+	
+	if ((max_count) && (ac))
+		rc = async_data_read_start(exch, address_list,
+		    max_count * sizeof(nic_address_t));
+	
+	async_exchange_end(exch);
+	return rc;
+}
+
+/** Set which multicast frames are received.
+ *
+ * @param[in] dev_sess
+ * @param[in] mode          Current operation mode
+ * @param[in] address_list  The list of addresses. Can be NULL.
+ * @param[in] address_count Number of addresses in the list.
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_multicast_set_mode(async_sess_t *dev_sess, nic_multicast_mode_t mode,
+    const nic_address_t *address_list, size_t address_count)
+{
+	if (address_list == NULL)
+		address_count = 0;
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	
+	aid_t message_id = async_send_3(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_MULTICAST_SET_MODE, (sysarg_t) mode, address_count, NULL);
+	
+	int rc;
+	if (address_count)
+		rc = async_data_write_start(exch, address_list,
+		    address_count * sizeof(nic_address_t));
+	else
+		rc = EOK;
+	
+	async_exchange_end(exch);
+	
+	sysarg_t res;
+	async_wait_for(message_id, &res);
+	
+	if (rc != EOK)
+		return rc;
+	
+	return (int) res;
+}
+
+/** Determine if broadcast packets are received.
+ *
+ * @param[in]  dev_sess
+ * @param[out] mode     Current operation mode
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_broadcast_get_mode(async_sess_t *dev_sess, nic_broadcast_mode_t *mode)
+{
+	assert(mode);
+	
+	sysarg_t _mode;
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_1_1(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_BROADCAST_GET_MODE, &_mode);
+	async_exchange_end(exch);
+	
+	*mode = (nic_broadcast_mode_t) _mode;
+	
+	return rc;
+}
+
+/** Set whether broadcast packets are received.
+ *
+ * @param[in] dev_sess
+ * @param[in] mode     Current operation mode
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_broadcast_set_mode(async_sess_t *dev_sess, nic_broadcast_mode_t mode)
+{
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_2_0(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_BROADCAST_SET_MODE, mode);
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+/** Determine if defective (erroneous) packets are received.
+ *
+ * @param[in]  dev_sess
+ * @param[out] mode     Bitmask specifying allowed errors
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_defective_get_mode(async_sess_t *dev_sess, uint32_t *mode)
+{
+	assert(mode);
+	
+	sysarg_t _mode;
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_1_1(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_DEFECTIVE_GET_MODE, &_mode);
+	async_exchange_end(exch);
+	
+	*mode = (uint32_t) _mode;
+	
+	return rc;
+}
+
+/** Set whether defective (erroneous) packets are received.
+ *
+ * @param[in]  dev_sess
+ * @param[out] mode     Bitmask specifying allowed errors
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_defective_set_mode(async_sess_t *dev_sess, uint32_t mode)
+{
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_2_0(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_DEFECTIVE_SET_MODE, mode);
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+/** Retrieve the currently blocked source MAC addresses.
+ *
+ * @param[in]  dev_sess
+ * @param[in]  max_count     Maximal number of addresses that could
+ *                           be written into the list buffer.
+ * @param[out] address_list  Buffer for the list (array). Can be NULL.
+ * @param[out] address_count Number of addresses in the list before
+ *                           possible truncation due to the max_count.
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_blocked_sources_get(async_sess_t *dev_sess, size_t max_count,
+    nic_address_t *address_list, size_t *address_count)
+{
+	if (!address_list)
+		max_count = 0;
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	
+	sysarg_t ac;
+	int rc = async_req_2_1(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_BLOCKED_SOURCES_GET, max_count, &ac);
+	if (rc != EOK) {
+		async_exchange_end(exch);
+		return rc;
+	}
+	
+	if (address_count)
+		*address_count = (size_t) ac;
+	
+	if ((max_count) && (ac))
+		rc = async_data_read_start(exch, address_list,
+		    max_count * sizeof(nic_address_t));
+	
+	async_exchange_end(exch);
+	return rc;
+}
+
+/** Set which source MACs are blocked
+ *
+ * @param[in] dev_sess
+ * @param[in] address_list  The list of addresses. Can be NULL.
+ * @param[in] address_count Number of addresses in the list.
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_blocked_sources_set(async_sess_t *dev_sess,
+    const nic_address_t *address_list, size_t address_count)
+{
+	if (address_list == NULL)
+		address_count = 0;
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	
+	aid_t message_id = async_send_2(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_BLOCKED_SOURCES_SET, address_count, NULL);
+	
+	int rc;
+	if (address_count)
+		rc = async_data_write_start(exch, address_list,
+			address_count * sizeof(nic_address_t));
+	else
+		rc = EOK;
+	
+	async_exchange_end(exch);
+	
+	sysarg_t res;
+	async_wait_for(message_id, &res);
+	
+	if (rc != EOK)
+		return rc;
+	
+	return (int) res;
+}
+
+/** Request current VLAN filtering mask.
+ *
+ * @param[in]  dev_sess
+ * @param[out] stats    Structure with the statistics
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_vlan_get_mask(async_sess_t *dev_sess, nic_vlan_mask_t *mask)
+{
+	assert(mask);
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_1_0(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_VLAN_GET_MASK);
+	if (rc != EOK) {
+		async_exchange_end(exch);
+		return rc;
+	}
+	
+	rc = async_data_read_start(exch, mask, sizeof(nic_vlan_mask_t));
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+/** Set the mask used for VLAN filtering.
+ *
+ * If NULL, VLAN filtering is disabled.
+ *
+ * @param[in] dev_sess
+ * @param[in] mask     Pointer to mask structure or NULL to disable.
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_vlan_set_mask(async_sess_t *dev_sess, const nic_vlan_mask_t *mask)
+{
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	
+	aid_t message_id = async_send_2(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_VLAN_SET_MASK, mask != NULL, NULL);
+	
+	int rc;
+	if (mask != NULL)
+		rc = async_data_write_start(exch, mask, sizeof(nic_vlan_mask_t));
+	else
+		rc = EOK;
+	
+	async_exchange_end(exch);
+	
+	sysarg_t res;
+	async_wait_for(message_id, &res);
+	
+	if (rc != EOK)
+		return rc;
+	
+	return (int) res;
+}
+
+/** Set VLAN (802.1q) tag.
+ *
+ * Set whether the tag is to be signaled in offload info and
+ * if the tag should be stripped from received frames and added
+ * to sent frames automatically. Not every combination of add
+ * and strip must be supported.
+ *
+ * @param[in] dev_sess
+ * @param[in] tag      VLAN priority (top 3 bits) and
+ *                     the VLAN tag (bottom 12 bits)
+ * @param[in] add      Add the VLAN tag automatically (boolean)
+ * @param[in] strip    Strip the VLAN tag automatically (boolean)
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_vlan_set_tag(async_sess_t *dev_sess, uint16_t tag, int add, int strip)
+{
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_4_0(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_VLAN_SET_TAG, (sysarg_t) tag, (sysarg_t) add, (sysarg_t) strip);
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+/** Add new Wake-On-LAN virtue.
+ *
+ * @param[in]  dev_sess
+ * @param[in]  type     Type of the virtue
+ * @param[in]  data     Data required for this virtue
+ *                      (depends on type)
+ * @param[in]  length   Length of the data
+ * @param[out] id       Identifier of the new virtue
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_wol_virtue_add(async_sess_t *dev_sess, nic_wv_type_t type,
+    const void *data, size_t length, nic_wv_id_t *id)
+{
+	assert(id);
+	
+	bool send_data = ((data != NULL) && (length != 0));
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	
+	ipc_call_t result;
+	aid_t message_id = async_send_3(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_WOL_VIRTUE_ADD, (sysarg_t) type, send_data, &result);
+	
+	sysarg_t res;
+	if (send_data) {
+		int rc = async_data_write_start(exch, data, length);
+		if (rc != EOK) {
+			async_exchange_end(exch);
+			async_wait_for(message_id, &res);
+			return rc;
+		}
+	}
+	
+	async_exchange_end(exch);
+	async_wait_for(message_id, &res);
+	
+	*id = IPC_GET_ARG1(result);
+	return (int) res;
+}
+
+/** Remove Wake-On-LAN virtue.
+ *
+ * @param[in] dev_sess
+ * @param[in] id       Virtue identifier
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_wol_virtue_remove(async_sess_t *dev_sess, nic_wv_id_t id)
+{
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_2_0(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_WOL_VIRTUE_REMOVE, (sysarg_t) id);
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+/** Get information about virtue.
+ *
+ * @param[in]  dev_sess
+ * @param[in]  id         Virtue identifier
+ * @param[out] type       Type of the filter. Can be NULL.
+ * @param[out] max_length Size of the data buffer.
+ * @param[out] data       Buffer for data used when the
+ *                        virtue was created. Can be NULL.
+ * @param[out] length     Length of the data. Can be NULL.
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_wol_virtue_probe(async_sess_t *dev_sess, nic_wv_id_t id,
+    nic_wv_type_t *type, size_t max_length, void *data, size_t *length)
+{
+	sysarg_t _type;
+	sysarg_t _length;
+	
+	if (data == NULL)
+		max_length = 0;
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	
+	int rc = async_req_3_2(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_WOL_VIRTUE_PROBE, (sysarg_t) id, max_length,
+	    &_type, &_length);
+	if (rc != EOK) {
+		async_exchange_end(exch);
+		return rc;
+	}
+	
+	if (type)
+		*type = _type;
+	
+	if (length)
+		*length = _length;
+	
+	if ((max_length) && (_length != 0))
+		rc = async_data_read_start(exch, data, max_length);
+	
+	async_exchange_end(exch);
+	return rc;
+}
+
+/** Get a list of all virtues of the specified type.
+ *
+ * When NIC_WV_NONE is specified as the virtue type the function
+ * lists virtues of all types.
+ *
+ * @param[in]  dev_sess
+ * @param[in]  type      Type of the virtues
+ * @param[in]  max_count Maximum number of ids that can be
+ *                       written into the list buffer.
+ * @param[out] id_list   Buffer for to the list of virtue ids.
+ *                       Can be NULL.
+ * @param[out] id_count  Number of virtue identifiers in the list
+ *                       before possible truncation due to the
+ *                       max_count. Can be NULL.
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_wol_virtue_list(async_sess_t *dev_sess, nic_wv_type_t type,
+    size_t max_count, nic_wv_id_t *id_list, size_t *id_count)
+{
+	if (id_list == NULL)
+		max_count = 0;
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	
+	sysarg_t count;
+	int rc = async_req_3_1(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_WOL_VIRTUE_LIST, (sysarg_t) type, max_count, &count);
+	
+	if (id_count)
+		*id_count = (size_t) count;
+	
+	if ((rc != EOK) || (!max_count)) {
+		async_exchange_end(exch);
+		return rc;
+	}
+	
+	rc = async_data_read_start(exch, id_list,
+	    max_count * sizeof(nic_wv_id_t));
+	
+	async_exchange_end(exch);
+	return rc;
+}
+
+/** Get number of virtues that can be enabled yet.
+ *
+ * Count: < 0 => Virtue of this type can be never used
+ *        = 0 => No more virtues can be enabled
+ *        > 0 => #count virtues can be enabled yet
+ *
+ * @param[in]  dev_sess
+ * @param[in]  type     Virtue type
+ * @param[out] count    Number of virtues
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_wol_virtue_get_caps(async_sess_t *dev_sess, nic_wv_type_t type,
+    int *count)
+{
+	assert(count);
+	
+	sysarg_t _count;
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_2_1(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_WOL_VIRTUE_GET_CAPS, (sysarg_t) type, &_count);
+	async_exchange_end(exch);
+	
+	*count = (int) _count;
+	return rc;
+}
+
+/** Load the frame that issued the wakeup.
+ *
+ * The NIC can support only matched_type,  only part of the frame
+ * can be available or not at all. Sometimes even the type can be
+ * uncertain -- in this case the matched_type contains NIC_WV_NONE.
+ *
+ * Frame_length can be greater than max_length, but at most max_length
+ * bytes will be copied into the frame buffer.
+ *
+ * Note: Only the type of the filter can be detected, not the concrete
+ * filter, because the driver is probably not running when the wakeup
+ * is issued.
+ *
+ * @param[in]  dev_sess
+ * @param[out] matched_type Type of the filter that issued wakeup.
+ * @param[in]  max_length   Size of the buffer
+ * @param[out] frame        Buffer for the frame. Can be NULL.
+ * @param[out] frame_length Length of the stored frame. Can be NULL.
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_wol_load_info(async_sess_t *dev_sess, nic_wv_type_t *matched_type,
+    size_t max_length, uint8_t *frame, size_t *frame_length)
+{
+	assert(matched_type);
+	
+	sysarg_t _matched_type;
+	sysarg_t _frame_length;
+	
+	if (frame == NULL)
+		max_length = 0;
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	
+	int rc = async_req_2_2(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_WOL_LOAD_INFO, max_length, &_matched_type, &_frame_length);
+	if (rc != EOK) {
+		async_exchange_end(exch);
+		return rc;
+	}
+	
+	*matched_type = (nic_wv_type_t) _matched_type;
+	if (frame_length)
+		*frame_length = (size_t) _frame_length;
+	
+	if ((max_length != 0) && (_frame_length != 0))
+		rc = async_data_read_start(exch, frame, max_length);
+	
+	async_exchange_end(exch);
+	return rc;
+}
+
+/** Probe supported options and current setting of offload computations
+ *
+ * @param[in]  dev_sess
+ * @param[out] supported Supported offload options
+ * @param[out] active    Currently active offload options
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_offload_probe(async_sess_t *dev_sess, uint32_t *supported,
+    uint32_t *active)
+{
+	assert(supported);
+	assert(active);
+	
+	sysarg_t _supported;
+	sysarg_t _active;
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_1_2(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_OFFLOAD_PROBE, &_supported, &_active);
+	async_exchange_end(exch);
+	
+	*supported = (uint32_t) _supported;
+	*active = (uint32_t) _active;
+	return rc;
+}
+
+/** Set which offload computations can be performed on the NIC.
+ *
+ * @param[in] dev_sess
+ * @param[in] mask     Mask for the options (only those set here will be set)
+ * @param[in] active   Which options should be enabled and which disabled
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_offload_set(async_sess_t *dev_sess, uint32_t mask, uint32_t active)
+{
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_3_0(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_AUTONEG_RESTART, (sysarg_t) mask, (sysarg_t) active);
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+/** Query the current interrupt/poll mode of the NIC
+ *
+ * @param[in]  dev_sess
+ * @param[out] mode     Current poll mode
+ * @param[out] period   Period used in periodic polling.
+ *                      Can be NULL.
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_poll_get_mode(async_sess_t *dev_sess, nic_poll_mode_t *mode,
+    struct timeval *period)
+{
+	assert(mode);
+	
+	sysarg_t _mode;
+	
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	
+	int rc = async_req_2_1(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_POLL_GET_MODE, period != NULL, &_mode);
+	if (rc != EOK) {
+		async_exchange_end(exch);
+		return rc;
+	}
+	
+	*mode = (nic_poll_mode_t) _mode;
+	
+	if (period != NULL)
+		rc = async_data_read_start(exch, period, sizeof(struct timeval));
+	
+	async_exchange_end(exch);
+	return rc;
+}
+
+/** Set the interrupt/poll mode of the NIC.
+ *
+ * @param[in] dev_sess
+ * @param[in] mode     New poll mode
+ * @param[in] period   Period used in periodic polling. Can be NULL.
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_poll_set_mode(async_sess_t *dev_sess, nic_poll_mode_t mode,
+    const struct timeval *period)
+{
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	
+	aid_t message_id = async_send_3(exch, DEV_IFACE_ID(NIC_DEV_IFACE),
+	    NIC_POLL_SET_MODE, (sysarg_t) mode, period != NULL, NULL);
+	
+	int rc;
+	if (period)
+		rc = async_data_write_start(exch, period, sizeof(struct timeval));
+	else
+		rc = EOK;
+	
+	async_exchange_end(exch);
+	
+	sysarg_t res;
+	async_wait_for(message_id, &res);
+	
+	if (rc != EOK)
+		return rc;
+	
+	return (int) res;
+}
+
+/** Request the driver to poll the NIC.
+ *
+ * @param[in] dev_sess
+ *
+ * @return EOK If the operation was successfully completed
+ *
+ */
+int nic_poll_now(async_sess_t *dev_sess)
+{
+	async_exch_t *exch = async_exchange_begin(dev_sess);
+	int rc = async_req_1_0(exch, DEV_IFACE_ID(NIC_DEV_IFACE), NIC_POLL_NOW);
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
+/** @}
+ */
Index: uspace/lib/c/generic/net/packet.c
===================================================================
--- uspace/lib/c/generic/net/packet.c	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ uspace/lib/c/generic/net/packet.c	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -36,4 +36,5 @@
  */
 
+#include <assert.h>
 #include <malloc.h>
 #include <mem.h>
@@ -44,29 +45,10 @@
 #include <sys/mman.h>
 
-#include <adt/generic_field.h>
+#include <adt/hash_table.h>
 #include <net/packet.h>
 #include <net/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];
-
-/** Packet map.
- * Maps packet identifiers to the packet references.
- * @see generic_field.h
- */
-GENERIC_FIELD_DECLARE(gpm, packet_map_t);
+/** Packet hash table size. */
+#define PACKET_HASH_TABLE_SIZE  128
 
 /** Packet map global data. */
@@ -75,8 +57,49 @@
 	fibril_rwlock_t lock;
 	/** Packet map. */
-	gpm_t packet_map;
+	hash_table_t packet_map;
+	/** Packet map operations */
+	hash_table_operations_t operations;
 } pm_globals;
 
-GENERIC_FIELD_IMPLEMENT(gpm, packet_map_t);
+typedef struct {
+	link_t link;
+	packet_t *packet;
+} pm_entry_t;
+
+/**
+ * Hash function for the packet mapping hash table
+ */
+static hash_index_t pm_hash(unsigned long key[])
+{
+	return (hash_index_t) key[0] % PACKET_HASH_TABLE_SIZE;
+}
+
+/**
+ * Key compare function for the packet mapping hash table
+ */
+static int pm_compare(unsigned long key[], hash_count_t keys, link_t *link)
+{
+	pm_entry_t *entry = list_get_instance(link, pm_entry_t, link);
+	return entry->packet->packet_id == key[0];
+}
+
+/**
+ * Remove callback for the packet mapping hash table
+ */
+static void pm_remove_callback(link_t *link)
+{
+	pm_entry_t *entry = list_get_instance(link, pm_entry_t, link);
+	free(entry);
+}
+
+/**
+ * Wrapper used when destroying the whole table
+ */
+static void pm_free_wrapper(link_t *link, void *ignored)
+{
+	pm_entry_t *entry = list_get_instance(link, pm_entry_t, link);
+	free(entry);
+}
+
 
 /** Initializes the packet map.
@@ -87,10 +110,18 @@
 int pm_init(void)
 {
-	int rc;
+	int rc = EOK;
 
 	fibril_rwlock_initialize(&pm_globals.lock);
 	
 	fibril_rwlock_write_lock(&pm_globals.lock);
-	rc = gpm_initialize(&pm_globals.packet_map);
+	
+	pm_globals.operations.hash = pm_hash;
+	pm_globals.operations.compare = pm_compare;
+	pm_globals.operations.remove_callback = pm_remove_callback;
+
+	if (!hash_table_create(&pm_globals.packet_map, PACKET_HASH_TABLE_SIZE, 1,
+	    &pm_globals.operations))
+		rc = ENOMEM;
+	
 	fibril_rwlock_write_unlock(&pm_globals.lock);
 	
@@ -100,27 +131,28 @@
 /** Finds the packet mapping.
  *
- * @param[in] packet_id	The packet identifier to be found.
- * @return		The found packet reference.
- * @return		NULL if the mapping does not exist.
+ * @param[in] packet_id Packet identifier to be found.
+ *
+ * @return The found packet reference.
+ * @return NULL if the mapping does not exist.
+ *
  */
 packet_t *pm_find(packet_id_t packet_id)
 {
-	packet_map_t *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)];
+	
+	unsigned long key = packet_id;
+	link_t *link = hash_table_find(&pm_globals.packet_map, &key);
+	
+	packet_t *packet;
+	if (link != NULL) {
+		pm_entry_t *entry =
+		    hash_table_get_instance(link, pm_entry_t, link);
+		packet = entry->packet;
+	} else
+		packet = NULL;
+	
 	fibril_rwlock_read_unlock(&pm_globals.lock);
 	return packet;
@@ -129,67 +161,58 @@
 /** Adds the packet mapping.
  *
- * @param[in] packet	The packet to be remembered.
- * @return		EOK on success.
- * @return		EINVAL if the packet is not valid.
- * @return		EINVAL if the packet map is not initialized.
- * @return		ENOMEM if there is not enough memory left.
+ * @param[in] packet Packet to be remembered.
+ *
+ * @return EOK on success.
+ * @return EINVAL if the packet is not valid.
+ * @return ENOMEM if there is not enough memory left.
+ *
  */
 int pm_add(packet_t *packet)
 {
-	packet_map_t *map;
-	int rc;
-
 	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_t *) malloc(sizeof(packet_map_t));
-			if (!map) {
-				fibril_rwlock_write_unlock(&pm_globals.lock);
-				return ENOMEM;
-			}
-			bzero(map, sizeof(packet_map_t));
-			rc = gpm_add(&pm_globals.packet_map, map);
-			if (rc < 0) {
-				fibril_rwlock_write_unlock(&pm_globals.lock);
-				free(map);
-				return rc;
-			}
-		} while (PACKET_MAP_PAGE(packet->packet_id) >=
-		    gpm_count(&pm_globals.packet_map));
+	
+	pm_entry_t *entry = malloc(sizeof(pm_entry_t));
+	if (entry == NULL) {
+		fibril_rwlock_write_unlock(&pm_globals.lock);
+		return ENOMEM;
 	}
-
-	(*map) [PACKET_MAP_INDEX(packet->packet_id)] = packet;
+	
+	entry->packet = packet;
+	
+	unsigned long key = packet->packet_id;
+	hash_table_insert(&pm_globals.packet_map, &key, &entry->link);
+	
 	fibril_rwlock_write_unlock(&pm_globals.lock);
+	
 	return EOK;
 }
 
-/** Releases the packet map. */
+/** Remove the packet mapping
+ *
+ * @param[in] packet The packet to be removed
+ *
+ */
+void pm_remove(packet_t *packet)
+{
+	assert(packet_is_valid(packet));
+	
+	fibril_rwlock_write_lock(&pm_globals.lock);
+	
+	unsigned long key = packet->packet_id;
+	hash_table_remove(&pm_globals.packet_map, &key, 1);
+	
+	fibril_rwlock_write_unlock(&pm_globals.lock);
+}
+
+/** Release the packet map. */
 void pm_destroy(void)
 {
-	int count;
-	int index;
-	packet_map_t *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, free);
-	/* leave locked */
+	hash_table_apply(&pm_globals.packet_map, pm_free_wrapper, NULL);
+	hash_table_destroy(&pm_globals.packet_map);
+	/* Leave locked */
 }
 
@@ -199,46 +222,52 @@
  * The packet is inserted right before the packets of the same order value.
  *
- * @param[in,out] first	The first packet of the queue. Sets the first packet of
- *			the queue. The original first packet may be shifted by
- *			the new packet.
- * @param[in] packet	The packet to be added.
- * @param[in] order	The packet order value.
- * @param[in] metric	The metric value of the packet.
- * @return		EOK on success.
- * @return		EINVAL if the first parameter is NULL.
- * @return		EINVAL if the packet is not valid.
+ * @param[in,out] first First packet of the queue. Sets the first
+ *                      packet of the queue. The original first packet
+ *                      may be shifted by the new packet.
+ * @param[in] packet    Packet to be added.
+ * @param[in] order     Packet order value.
+ * @param[in] metric    Metric value of the packet.
+ *
+ * @return EOK on success.
+ * @return EINVAL if the first parameter is NULL.
+ * @return EINVAL if the packet is not valid.
+ *
  */
 int pq_add(packet_t **first, packet_t *packet, size_t order, size_t metric)
 {
-	packet_t *item;
-
-	if (!first || !packet_is_valid(packet))
+	if ((!first) || (!packet_is_valid(packet)))
 		return EINVAL;
-
+	
 	pq_set_order(packet, order, metric);
 	if (packet_is_valid(*first)) {
-		item = * first;
+		packet_t *cur = *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;
+			if (cur->order < order) {
+				if (cur->next)
+					cur = pm_find(cur->next);
+				else {
+					cur->next = packet->packet_id;
+					packet->previous = cur->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;
+				packet->previous = cur->previous;
+				packet->next = cur->packet_id;
+				
+				cur->previous = packet->packet_id;
+				cur = pm_find(packet->previous);
+				
+				if (cur)
+					cur->next = packet->packet_id;
 				else
 					*first = packet;
+				
 				return EOK;
 			}
-		} while (packet_is_valid(item));
+		} while (packet_is_valid(cur));
 	}
+	
 	*first = packet;
 	return EOK;
@@ -312,10 +341,11 @@
 
 	next = pm_find(packet->next);
-	if (next) {
+	if (next)
 		next->previous = packet->previous;
-		previous = pm_find(next->previous);
-		if (previous)
-			previous->next = next->packet_id;
-	}
+	
+	previous = pm_find(packet->previous);
+	if (previous)
+		previous->next = packet->next ;
+	
 	packet->previous = 0;
 	packet->next = 0;
Index: uspace/lib/c/generic/ns.c
===================================================================
--- uspace/lib/c/generic/ns.c	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ uspace/lib/c/generic/ns.c	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -54,8 +54,9 @@
 	if (!exch)
 		return NULL;
+	
 	async_sess_t *sess =
 	    async_connect_me_to(mgmt, exch, service, arg2, arg3);
 	async_exchange_end(exch);
-
+	
 	if (!sess)
 		return NULL;
Index: uspace/lib/c/include/adt/hash_set.h
===================================================================
--- uspace/lib/c/include/adt/hash_set.h	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
+++ uspace/lib/c/include/adt/hash_set.h	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2006 Jakub Jermar
+ * Copyright (c) 2011 Radim Vansa
+ * 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 libc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_HASH_SET_H_
+#define LIBC_HASH_SET_H_
+
+#include <adt/list.h>
+#include <unistd.h>
+
+#define HASH_SET_MIN_SIZE  8
+
+typedef unsigned long (*hash_set_hash)(const link_t *);
+typedef int (*hash_set_equals)(const link_t *, const link_t *);
+
+/** Hash table structure. */
+typedef struct {
+	list_t *table;
+	
+	/** Current table size */
+	size_t size;
+	
+	/**
+	 * Current number of entries. If count > size,
+	 * the table is rehashed into table with double
+	 * size. If (4 * count < size) && (size > min_size),
+	 * the table is rehashed into table with half the size.
+	 */
+	size_t count;
+	
+	/** Hash function */
+	hash_set_hash hash;
+	
+	/** Hash table item equals function */
+	hash_set_equals equals;
+} hash_set_t;
+
+extern int hash_set_init(hash_set_t *, hash_set_hash, hash_set_equals, size_t);
+extern int hash_set_insert(hash_set_t *, link_t *);
+extern link_t *hash_set_find(hash_set_t *, const link_t *);
+extern int hash_set_contains(const hash_set_t *, const link_t *);
+extern size_t hash_set_count(const hash_set_t *);
+extern link_t *hash_set_remove(hash_set_t *, const link_t *);
+extern void hash_set_remove_selected(hash_set_t *,
+    int (*)(link_t *, void *), void *);
+extern void hash_set_destroy(hash_set_t *);
+extern void hash_set_apply(hash_set_t *, void (*)(link_t *, void *), void *);
+extern void hash_set_clear(hash_set_t *, void (*)(link_t *, void *), void *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/adt/hash_table.h
===================================================================
--- uspace/lib/c/include/adt/hash_table.h	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ uspace/lib/c/include/adt/hash_table.h	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -86,4 +86,5 @@
 extern bool hash_table_create(hash_table_t *, hash_count_t, hash_count_t,
     hash_table_operations_t *);
+extern void hash_table_clear(hash_table_t *);
 extern void hash_table_insert(hash_table_t *, unsigned long [], link_t *);
 extern link_t *hash_table_find(hash_table_t *, unsigned long []);
Index: uspace/lib/c/include/device/hw_res_parsed.h
===================================================================
--- uspace/lib/c/include/device/hw_res_parsed.h	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
+++ uspace/lib/c/include/device/hw_res_parsed.h	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2011 Jiri Michalec
+ * 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 libc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_DEVICE_HW_RES_PARSED_H_
+#define LIBC_DEVICE_HW_RES_PARSED_H_
+
+#include <device/hw_res.h>
+#include <str.h>
+
+/** Keep areas of the zero size in the list */
+#define HW_RES_KEEP_ZERO_AREA  0x1
+
+/** Keep duplicit entries */
+#define HW_RES_KEEP_DUPLICIT   0x2
+
+/** Address range structure */
+typedef struct addr_range {
+	/** Start address */
+	uint64_t address;
+	
+	/** Endianness */
+	endianness_t endianness;
+	
+	/** Area size */
+	size_t size;
+} addr_range_t;
+
+/** IO range type */
+typedef addr_range_t io_range_t;
+
+/** Memory range type */
+typedef addr_range_t mem_range_t;
+
+/** List of IRQs */
+typedef struct irq_list {
+	/** Irq count */
+	size_t count;
+	
+	/** Array of IRQs */
+	int *irqs;
+} irq_list_t;
+
+/** List of memory areas */
+typedef struct addr_range_list {
+	/** Areas count */
+	size_t count;
+	
+	/** Array of areas */
+	addr_range_t *ranges;
+} addr_range_list_t;
+
+/** List of IO mapped areas */
+typedef addr_range_list_t io_range_list_t;
+
+/** Memory range type */
+typedef addr_range_list_t mem_range_list_t;
+
+/** HW resources parsed according to resource type */
+typedef struct hw_resource_list_parsed {
+	/** List of IRQs */
+	irq_list_t irqs;
+	
+	/** List of memory areas */
+	mem_range_list_t mem_ranges;
+	
+	/** List of IO areas */
+	io_range_list_t io_ranges;
+} hw_res_list_parsed_t;
+
+/** Clean hw_resource_list_parsed_t structure
+ *
+ * All allocated memory will be released, data amd pointers set to 0.
+ *
+ * @param list The structure to clear
+ */
+static inline void hw_res_list_parsed_clean(hw_res_list_parsed_t *list)
+{
+	if (list == NULL)
+		return;
+	
+	free(list->irqs.irqs);
+	free(list->io_ranges.ranges);
+	free(list->mem_ranges.ranges);
+	
+	bzero(list, sizeof(hw_res_list_parsed_t));
+}
+
+/** Initialize the hw_resource_list_parsed_t structure
+ *
+ *  @param list The structure to initialize
+ */
+static inline void hw_res_list_parsed_init(hw_res_list_parsed_t *list)
+{
+	bzero(list, sizeof(hw_res_list_parsed_t));
+}
+
+extern int hw_res_list_parse(hw_resource_list_t *, hw_res_list_parsed_t *, int);
+extern int hw_res_get_list_parsed(async_sess_t *, hw_res_list_parsed_t *, int);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/device/nic.h
===================================================================
--- uspace/lib/c/include/device/nic.h	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
+++ uspace/lib/c/include/device/nic.h	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2010 Radim Vansa
+ * 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 libc
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBC_DEVICE_NIC_H_
+#define LIBC_DEVICE_NIC_H_
+
+#include <async.h>
+#include <net/device.h>
+#include <net/packet.h>
+#include <ipc/services.h>
+
+typedef enum {
+	NIC_SEND_MESSAGE = 0,
+	NIC_CONNECT_TO_NIL,
+	NIC_GET_STATE,
+	NIC_SET_STATE,
+	NIC_GET_ADDRESS,
+	NIC_SET_ADDRESS,
+	NIC_GET_STATS,
+	NIC_GET_DEVICE_INFO,
+	NIC_GET_CABLE_STATE,
+	NIC_GET_OPERATION_MODE,
+	NIC_SET_OPERATION_MODE,
+	NIC_AUTONEG_ENABLE,
+	NIC_AUTONEG_DISABLE,
+	NIC_AUTONEG_PROBE,
+	NIC_AUTONEG_RESTART,
+	NIC_GET_PAUSE,
+	NIC_SET_PAUSE,
+	NIC_UNICAST_GET_MODE,
+	NIC_UNICAST_SET_MODE,
+	NIC_MULTICAST_GET_MODE,
+	NIC_MULTICAST_SET_MODE,
+	NIC_BROADCAST_GET_MODE,
+	NIC_BROADCAST_SET_MODE,
+	NIC_DEFECTIVE_GET_MODE,
+	NIC_DEFECTIVE_SET_MODE,
+	NIC_BLOCKED_SOURCES_GET,
+	NIC_BLOCKED_SOURCES_SET,
+	NIC_VLAN_GET_MASK,
+	NIC_VLAN_SET_MASK,
+	NIC_VLAN_SET_TAG,
+	NIC_WOL_VIRTUE_ADD,
+	NIC_WOL_VIRTUE_REMOVE,
+	NIC_WOL_VIRTUE_PROBE,
+	NIC_WOL_VIRTUE_LIST,
+	NIC_WOL_VIRTUE_GET_CAPS,
+	NIC_WOL_LOAD_INFO,
+	NIC_OFFLOAD_PROBE,
+	NIC_OFFLOAD_SET,
+	NIC_POLL_GET_MODE,
+	NIC_POLL_SET_MODE,
+	NIC_POLL_NOW
+} nic_funcs_t;
+
+extern int nic_send_message(async_sess_t *, packet_id_t);
+extern int nic_connect_to_nil(async_sess_t *, services_t, nic_device_id_t);
+extern int nic_get_state(async_sess_t *, nic_device_state_t *);
+extern int nic_set_state(async_sess_t *, nic_device_state_t);
+extern int nic_get_address(async_sess_t *, nic_address_t *);
+extern int nic_set_address(async_sess_t *, const nic_address_t *);
+extern int nic_get_stats(async_sess_t *, nic_device_stats_t *);
+extern int nic_get_device_info(async_sess_t *, nic_device_info_t *);
+extern int nic_get_cable_state(async_sess_t *, nic_cable_state_t *);
+
+extern int nic_get_operation_mode(async_sess_t *, int *, nic_channel_mode_t *,
+    nic_role_t *);
+extern int nic_set_operation_mode(async_sess_t *, int, nic_channel_mode_t,
+    nic_role_t);
+extern int nic_autoneg_enable(async_sess_t *, uint32_t);
+extern int nic_autoneg_disable(async_sess_t *);
+extern int nic_autoneg_probe(async_sess_t *, uint32_t *, uint32_t *,
+    nic_result_t *, nic_result_t *);
+extern int nic_autoneg_restart(async_sess_t *);
+extern int nic_get_pause(async_sess_t *, nic_result_t *, nic_result_t *,
+    uint16_t *);
+extern int nic_set_pause(async_sess_t *, int, int, uint16_t);
+
+extern int nic_unicast_get_mode(async_sess_t *, nic_unicast_mode_t *, size_t,
+    nic_address_t *, size_t *);
+extern int nic_unicast_set_mode(async_sess_t *, nic_unicast_mode_t,
+    const nic_address_t *, size_t);
+extern int nic_multicast_get_mode(async_sess_t *, nic_multicast_mode_t *,
+    size_t, nic_address_t *, size_t *);
+extern int nic_multicast_set_mode(async_sess_t *, nic_multicast_mode_t,
+    const nic_address_t *, size_t);
+extern int nic_broadcast_get_mode(async_sess_t *, nic_broadcast_mode_t *);
+extern int nic_broadcast_set_mode(async_sess_t *, nic_broadcast_mode_t);
+extern int nic_defective_get_mode(async_sess_t *, uint32_t *);
+extern int nic_defective_set_mode(async_sess_t *, uint32_t);
+extern int nic_blocked_sources_get(async_sess_t *, size_t, nic_address_t *,
+    size_t *);
+extern int nic_blocked_sources_set(async_sess_t *, const nic_address_t *,
+    size_t);
+
+extern int nic_vlan_get_mask(async_sess_t *, nic_vlan_mask_t *);
+extern int nic_vlan_set_mask(async_sess_t *, const nic_vlan_mask_t *);
+extern int nic_vlan_set_tag(async_sess_t *, uint16_t, int, int);
+
+extern int nic_wol_virtue_add(async_sess_t *, nic_wv_type_t, const void *,
+    size_t, nic_wv_id_t *);
+extern int nic_wol_virtue_remove(async_sess_t *, nic_wv_id_t);
+extern int nic_wol_virtue_probe(async_sess_t *, nic_wv_id_t, nic_wv_type_t *,
+    size_t, void *, size_t *);
+extern int nic_wol_virtue_list(async_sess_t *, nic_wv_type_t, size_t,
+    nic_wv_id_t *, size_t *);
+extern int nic_wol_virtue_get_caps(async_sess_t *, nic_wv_type_t, int *);
+extern int nic_wol_load_info(async_sess_t *, nic_wv_type_t *, size_t, uint8_t *,
+    size_t *);
+
+extern int nic_offload_probe(async_sess_t *, uint32_t *, uint32_t *);
+extern int nic_offload_set(async_sess_t *, uint32_t, uint32_t);
+
+extern int nic_poll_get_mode(async_sess_t *, nic_poll_mode_t *,
+    struct timeval *);
+extern int nic_poll_set_mode(async_sess_t *, nic_poll_mode_t,
+    const struct timeval *);
+extern int nic_poll_now(async_sess_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/c/include/ipc/dev_iface.h
===================================================================
--- uspace/lib/c/include/ipc/dev_iface.h	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ uspace/lib/c/include/ipc/dev_iface.h	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -36,6 +36,10 @@
 typedef enum {
 	HW_RES_DEV_IFACE = 0,
+	/** Character device interface */
 	CHAR_DEV_IFACE,
-
+	
+	/** Network interface controller interface */
+	NIC_DEV_IFACE,
+	
 	/** Interface provided by any PCI device. */
 	PCI_DEV_IFACE,
Index: uspace/lib/c/include/ipc/devman.h
===================================================================
--- uspace/lib/c/include/ipc/devman.h	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ uspace/lib/c/include/ipc/devman.h	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -146,4 +146,5 @@
 typedef enum {
 	DRIVER_DEV_ADD = IPC_FIRST_USER_METHOD,
+	DRIVER_DEV_ADDED,
 	DRIVER_DEV_REMOVE,
 	DRIVER_DEV_GONE,
Index: uspace/lib/c/include/ipc/il.h
===================================================================
--- uspace/lib/c/include/ipc/il.h	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ uspace/lib/c/include/ipc/il.h	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -54,4 +54,10 @@
 	NET_IL_MTU_CHANGED,
 	
+	/**
+	 * Device address changed message
+	 * @see il_addr_changed_msg()
+	 */
+	NET_IL_ADDR_CHANGED,
+
 	/** Packet received message.
 	 * @see il_received_msg()
Index: uspace/lib/c/include/ipc/net.h
===================================================================
--- uspace/lib/c/include/ipc/net.h	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ uspace/lib/c/include/ipc/net.h	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -277,5 +277,5 @@
  *
  */
-#define IPC_GET_DEVICE(call)  ((device_id_t) IPC_GET_ARG1(call))
+#define IPC_GET_DEVICE(call)  ((nic_device_id_t) IPC_GET_ARG1(call))
 
 /** Return the packet identifier message argument.
@@ -298,5 +298,33 @@
  *
  */
-#define IPC_GET_STATE(call)  ((device_state_t) IPC_GET_ARG2(call))
+#define IPC_GET_STATE(call)  ((nic_device_state_t) IPC_GET_ARG2(call))
+
+/** Return the device handle argument
+ *
+ * @param[in] call Message call structure
+ *
+ */
+#define IPC_GET_DEVICE_HANDLE(call) ((devman_handle_t) IPC_GET_ARG2(call))
+
+/** Return the device driver service message argument.
+ *
+ * @param[in] call Message call structure.
+ *
+ */
+#define IPC_GET_SERVICE(call)  ((services_t) IPC_GET_ARG3(call))
+
+/** Return the target service message argument.
+ *
+ * @param[in] call Message call structure.
+ *
+ */
+#define IPC_GET_TARGET(call)  ((services_t) IPC_GET_ARG3(call))
+
+/** Return the sender service message argument.
+ *
+ * @param[in] call Message call structure.
+ *
+ */
+#define IPC_GET_SENDER(call)  ((services_t) IPC_GET_ARG3(call))
 
 /** Return the maximum transmission unit message argument.
@@ -305,26 +333,5 @@
  *
  */
-#define IPC_GET_MTU(call)  ((size_t) IPC_GET_ARG2(call))
-
-/** Return the device driver service message argument.
- *
- * @param[in] call Message call structure.
- *
- */
-#define IPC_GET_SERVICE(call)  ((services_t) IPC_GET_ARG3(call))
-
-/** Return the target service message argument.
- *
- * @param[in] call Message call structure.
- *
- */
-#define IPC_GET_TARGET(call)  ((services_t) IPC_GET_ARG3(call))
-
-/** Return the sender service message argument.
- *
- * @param[in] call Message call structure.
- *
- */
-#define IPC_GET_SENDER(call)  ((services_t) IPC_GET_ARG3(call))
+#define IPC_GET_MTU(call)  ((size_t) IPC_GET_ARG3(call))
 
 /** Return the error service message argument.
Index: uspace/lib/c/include/ipc/net_net.h
===================================================================
--- uspace/lib/c/include/ipc/net_net.h	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ uspace/lib/c/include/ipc/net_net.h	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -43,14 +43,18 @@
 /** Networking subsystem central module messages. */
 typedef enum {
-	/** Returns the general configuration
+	/** Return general configuration
 	 * @see net_get_conf_req()
 	 */
 	NET_NET_GET_CONF = NET_FIRST,
-	/** Returns the device specific configuration
+	/** Return device specific configuration
 	 * @see net_get_device_conf_req()
 	 */
 	NET_NET_GET_DEVICE_CONF,
-	/** Starts the networking stack. */
-	NET_NET_STARTUP,
+	/** Return number of mastered devices */
+	NET_NET_GET_DEVICES_COUNT,
+	/** Return names and device IDs of all devices */
+	NET_NET_GET_DEVICES,
+	/** Notify the networking service about a ready device */
+	NET_NET_DRIVER_READY
 } net_messages;
 
Index: uspace/lib/c/include/ipc/nil.h
===================================================================
--- uspace/lib/c/include/ipc/nil.h	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ uspace/lib/c/include/ipc/nil.h	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -70,4 +70,8 @@
 	 */
 	NET_NIL_BROADCAST_ADDR,
+	/** Device has changed address
+	 * @see nil_addr_changed_msg()
+	 */
+	NET_NIL_ADDR_CHANGED
 } nil_messages;
 
Index: uspace/lib/c/include/ipc/services.h
===================================================================
--- uspace/lib/c/include/ipc/services.h	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ uspace/lib/c/include/ipc/services.h	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -49,6 +49,4 @@
 	SERVICE_CLIPBOARD  = FOURCC('c', 'l', 'i', 'p'),
 	SERVICE_NETWORKING = FOURCC('n', 'e', 't', ' '),
-	SERVICE_LO         = FOURCC('l', 'o', ' ', ' '),
-	SERVICE_NE2000     = FOURCC('n', 'e', '2', 'k'),
 	SERVICE_ETHERNET   = FOURCC('e', 't', 'h', ' '),
 	SERVICE_NILDUMMY   = FOURCC('n', 'i', 'l', 'd'),
Index: uspace/lib/c/include/net/device.h
===================================================================
--- uspace/lib/c/include/net/device.h	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ uspace/lib/c/include/net/device.h	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2009 Lukas Mejdrech
+ * Copyright (c) 2011 Radim Vansa
  * All rights reserved.
  *
@@ -39,44 +40,134 @@
 
 #include <adt/int_map.h>
+#include <net/eth_phys.h>
+#include <bool.h>
+
+/** Ethernet address length. */
+#define ETH_ADDR  6
+
+/** MAC printing format */
+#define PRIMAC  "%02x:%02x:%02x:%02x:%02x:%02x"
+
+/** MAC arguments */
+#define ARGSMAC(__a) \
+	(__a)[0], (__a)[1], (__a)[2], (__a)[3], (__a)[4], (__a)[5]
+
+/* Compare MAC address with specific value */
+#define MAC_EQUALS_VALUE(__a, __a0, __a1, __a2, __a3, __a4, __a5) \
+	((__a)[0] == (__a0) && (__a)[1] == (__a1) && (__a)[2] == (__a2) \
+	&& (__a)[3] == (__a3) && (__a)[4] == (__a4) && (__a)[5] == (__a5))
+
+#define MAC_IS_ZERO(__x) \
+	MAC_EQUALS_VALUE(__x, 0, 0, 0, 0, 0, 0)
 
 /** Device identifier to generic type map declaration. */
-#define DEVICE_MAP_DECLARE	INT_MAP_DECLARE
+#define DEVICE_MAP_DECLARE  INT_MAP_DECLARE
 
 /** Device identifier to generic type map implementation. */
-#define DEVICE_MAP_IMPLEMENT	INT_MAP_IMPLEMENT
+#define DEVICE_MAP_IMPLEMENT  INT_MAP_IMPLEMENT
+
+/** Max length of any hw nic address (currently only eth) */
+#define NIC_MAX_ADDRESS_LENGTH  16
 
 /** Invalid device identifier. */
-#define DEVICE_INVALID_ID	(-1)
+#define NIC_DEVICE_INVALID_ID  (-1)
+
+#define NIC_VENDOR_MAX_LENGTH         64
+#define NIC_MODEL_MAX_LENGTH          64
+#define NIC_PART_NUMBER_MAX_LENGTH    64
+#define NIC_SERIAL_NUMBER_MAX_LENGTH  64
+
+/**
+ * The bitmap uses single bit for each of the 2^12 = 4096 possible VLAN tags.
+ * This means its size is 4096/8 = 512 bytes.
+ */
+#define NIC_VLAN_BITMAP_SIZE  512
+
+#define NIC_DEVICE_PRINT_FMT  "%x"
 
 /** Device identifier type. */
-typedef int device_id_t;
-
-/** Device state type. */
-typedef enum device_state device_state_t;
-
-/** Type definition of the device usage statistics.
- * @see device_stats
- */
-typedef struct device_stats device_stats_t;
+typedef int nic_device_id_t;
+
+/**
+ * Structure covering the MAC address.
+ */
+typedef struct nic_address {
+	uint8_t address[ETH_ADDR];
+} nic_address_t;
 
 /** Device state. */
-enum device_state {
-	/** Device not present or not initialized. */
-	NETIF_NULL = 0,
-	/** Device present and stopped. */
-	NETIF_STOPPED,
-	/** Device present and active. */
-	NETIF_ACTIVE,
-	/** Device present but unable to transmit. */
-	NETIF_CARRIER_LOST
-};
+typedef enum nic_device_state {
+	/**
+	 * Device present and stopped. Moving device to this state means to discard
+	 * all settings and WOL virtues, rebooting the NIC to state as if the
+	 * computer just booted (or the NIC was just inserted in case of removable
+	 * NIC).
+	 */
+	NIC_STATE_STOPPED,
+	/**
+	 * If the NIC is in this state no packets (frames) are transmitted nor
+	 * received. However, the settings are not restarted. You can use this state
+	 * to temporarily disable transmition/reception or atomically (with respect
+	 * to incoming/outcoming packets) change frames acceptance etc.
+	 */
+	NIC_STATE_DOWN,
+	/** Device is normally operating. */
+	NIC_STATE_ACTIVE,
+	/** Just a constant to limit the state numbers */
+	NIC_STATE_MAX,
+} nic_device_state_t;
+
+/**
+ * Channel operating mode used on the medium.
+ */
+typedef enum {
+	NIC_CM_UNKNOWN,
+	NIC_CM_FULL_DUPLEX,
+	NIC_CM_HALF_DUPLEX,
+	NIC_CM_SIMPLEX
+} nic_channel_mode_t;
+
+/**
+ * Role for the device (used e.g. for 1000Gb ethernet)
+ */
+typedef enum {
+	NIC_ROLE_UNKNOWN,
+	NIC_ROLE_AUTO,
+	NIC_ROLE_MASTER,
+	NIC_ROLE_SLAVE
+} nic_role_t;
+
+/**
+ * Current state of the cable in the device
+ */
+typedef enum {
+	NIC_CS_UNKNOWN,
+	NIC_CS_PLUGGED,
+	NIC_CS_UNPLUGGED
+} nic_cable_state_t;
+
+/**
+ * Result of the requested operation
+ */
+typedef enum {
+	/** Successfully disabled */
+	NIC_RESULT_DISABLED,
+	/** Successfully enabled */
+	NIC_RESULT_ENABLED,
+	/** Not supported at all */
+	NIC_RESULT_NOT_SUPPORTED,
+	/** Temporarily not available */
+	NIC_RESULT_NOT_AVAILABLE,
+	/** Result extensions */
+	NIC_RESULT_FIRST_EXTENSION
+} nic_result_t;
 
 /** Device usage statistics. */
-struct device_stats {
-	/** Total packets received. */
+typedef struct nic_device_stats {
+	/** Total packets received (accepted). */
 	unsigned long receive_packets;
 	/** Total packets transmitted. */
 	unsigned long send_packets;
-	/** Total bytes received. */
+	/** Total bytes received (accepted). */
 	unsigned long receive_bytes;
 	/** Total bytes transmitted. */
@@ -86,12 +177,20 @@
 	/** Packet transmition problems counter. */
 	unsigned long send_errors;
-	/** No space in buffers counter. */
+	/** Number of frames dropped due to insufficient space in RX buffers */
 	unsigned long receive_dropped;
-	/** No space available counter. */
+	/** Number of frames dropped due to insufficient space in TX buffers */
 	unsigned long send_dropped;
-	/** Total multicast packets received. */
-	unsigned long multicast;
+	/** Total multicast packets received (accepted). */
+	unsigned long receive_multicast;
+	/** Total broadcast packets received (accepted). */
+	unsigned long receive_broadcast;
 	/** The number of collisions due to congestion on the medium. */
 	unsigned long collisions;
+	/** Unicast packets received but not accepted (filtered) */
+	unsigned long receive_filtered_unicast;
+	/** Multicast packets received but not accepted (filtered) */
+	unsigned long receive_filtered_multicast;
+	/** Broadcast packets received but not accepted (filtered) */
+	unsigned long receive_filtered_broadcast;
 
 	/* detailed receive_errors */
@@ -129,5 +228,250 @@
 	/** Total compressed packet transmitted. */
 	unsigned long send_compressed;
-};
+} nic_device_stats_t;
+
+/** Errors corresponding to those in the nic_device_stats_t */
+typedef enum {
+	NIC_SEC_BUFFER_FULL,
+	NIC_SEC_ABORTED,
+	NIC_SEC_CARRIER_LOST,
+	NIC_SEC_FIFO_OVERRUN,
+	NIC_SEC_HEARTBEAT,
+	NIC_SEC_WINDOW_ERROR,
+	/* Error encountered during TX but with other type of error */
+	NIC_SEC_OTHER
+} nic_send_error_cause_t;
+
+/** Errors corresponding to those in the nic_device_stats_t */
+typedef enum {
+	NIC_REC_BUFFER_FULL,
+	NIC_REC_LENGTH,
+	NIC_REC_BUFFER_OVERFLOW,
+	NIC_REC_CRC,
+	NIC_REC_FRAME_ALIGNMENT,
+	NIC_REC_FIFO_OVERRUN,
+	NIC_REC_MISSED,
+	/* Error encountered during RX but with other type of error */
+	NIC_REC_OTHER
+} nic_receive_error_cause_t;
+
+/**
+ * Information about the NIC that never changes - name, vendor, model,
+ * capabilites and so on.
+ */
+typedef struct nic_device_info {
+	/* Device identification */
+	char vendor_name[NIC_VENDOR_MAX_LENGTH];
+	char model_name[NIC_MODEL_MAX_LENGTH];
+	char part_number[NIC_PART_NUMBER_MAX_LENGTH];
+	char serial_number[NIC_SERIAL_NUMBER_MAX_LENGTH];
+	uint16_t vendor_id;
+	uint16_t device_id;
+	uint16_t subsystem_vendor_id;
+	uint16_t subsystem_id;
+	/* Device capabilities */
+	uint16_t ethernet_support[ETH_PHYS_LAYERS];
+
+	/** The mask of all modes which the device can advertise
+	 *
+	 *  see ETH_AUTONEG_ macros in net/eth_phys.h of libc
+	 */
+	uint32_t autoneg_support;
+} nic_device_info_t;
+
+/**
+ * Type of the ethernet frame
+ */
+typedef enum nic_frame_type {
+	NIC_FRAME_UNICAST,
+	NIC_FRAME_MULTICAST,
+	NIC_FRAME_BROADCAST
+} nic_frame_type_t;
+
+/**
+ * Specifies which unicast frames is the NIC receiving.
+ */
+typedef enum nic_unicast_mode {
+	NIC_UNICAST_UNKNOWN,
+	/** No unicast frames are received */
+	NIC_UNICAST_BLOCKED,
+	/** Only the frames with this NIC's MAC as destination are received */
+	NIC_UNICAST_DEFAULT,
+	/**
+	 * Both frames with this NIC's MAC and those specified in the list are
+	 * received
+	 */
+	NIC_UNICAST_LIST,
+	/** All unicast frames are received */
+	NIC_UNICAST_PROMISC
+} nic_unicast_mode_t;
+
+typedef enum nic_multicast_mode {
+	NIC_MULTICAST_UNKNOWN,
+	/** No multicast frames are received */
+	NIC_MULTICAST_BLOCKED,
+	/** Frames with multicast addresses specified in this list are received */
+	NIC_MULTICAST_LIST,
+	/** All multicast frames are received */
+	NIC_MULTICAST_PROMISC
+} nic_multicast_mode_t;
+
+typedef enum nic_broadcast_mode {
+	NIC_BROADCAST_UNKNOWN,
+	/** Broadcast frames are dropped */
+	NIC_BROADCAST_BLOCKED,
+	/** Broadcast frames are received */
+	NIC_BROADCAST_ACCEPTED
+} nic_broadcast_mode_t;
+
+/**
+ * Structure covering the bitmap with VLAN tags.
+ */
+typedef struct nic_vlan_mask {
+	uint8_t bitmap[NIC_VLAN_BITMAP_SIZE];
+} nic_vlan_mask_t;
+
+/* WOL virtue identifier */
+typedef unsigned int nic_wv_id_t;
+
+/**
+ * Structure passed as argument for virtue NIC_WV_MAGIC_PACKET.
+ */
+typedef struct nic_wv_magic_packet_data {
+	uint8_t password[6];
+} nic_wv_magic_packet_data_t;
+
+/**
+ * Structure passed as argument for virtue NIC_WV_DIRECTED_IPV4
+ */
+typedef struct nic_wv_ipv4_data {
+	uint8_t address[4];
+} nic_wv_ipv4_data_t;
+
+/**
+ * Structure passed as argument for virtue NIC_WV_DIRECTED_IPV6
+ */
+typedef struct nic_wv_ipv6_data {
+	uint8_t address[16];
+} nic_wv_ipv6_data_t;
+
+/**
+ * WOL virtue types defining the interpretation of data passed to the virtue.
+ * Those tagged with S can have only single virtue active at one moment, those
+ * tagged with M can have multiple ones.
+ */
+typedef enum nic_wv_type {
+	/**
+	 * Used for deletion of the virtue - in this case the mask, data and length
+	 * arguments are ignored.
+	 */
+	NIC_WV_NONE,
+	/** S
+	 * Enabled <=> wakeup upon link change
+	 */
+	NIC_WV_LINK_CHANGE,
+	/** S
+	 * If this virtue is set up, wakeup can be issued by a magic packet frame.
+	 * If the data argument is not NULL, it must contain
+	 * nic_wv_magic_packet_data structure with the SecureOn password.
+	 */
+	NIC_WV_MAGIC_PACKET,
+	/** M
+	 * If the virtue is set up, wakeup can be issued by a frame targeted to
+	 * device with MAC address specified in data. The data must contain
+	 * nic_address_t structure.
+	 */
+	NIC_WV_DESTINATION,
+	/** S
+	 * Enabled <=> wakeup upon receiving broadcast frame
+	 */
+	NIC_WV_BROADCAST,
+	/** S
+	 * Enabled <=> wakeup upon receiving ARP Request
+	 */
+	NIC_WV_ARP_REQUEST,
+	/** M
+	 * If enabled, the wakeup is issued upon receiving frame with an IPv4 packet
+	 * with IPv4 address specified in data. The data must contain
+	 * nic_wv_ipv4_data structure.
+	 */
+	NIC_WV_DIRECTED_IPV4,
+	/** M
+	 * If enabled, the wakeup is issued upon receiving frame with an IPv4 packet
+	 * with IPv6 address specified in data. The data must contain
+	 * nic_wv_ipv6_data structure.
+	 */
+	NIC_WV_DIRECTED_IPV6,
+	/** M
+	 * First length/2 bytes in the argument are interpreted as mask, second
+	 * length/2 bytes are interpreted as content.
+	 * If enabled, the wakeup is issued upon receiving frame where the bytes
+	 * with non-zero value in the mask equal to those in the content.
+	 */
+	NIC_WV_FULL_MATCH,
+	/**
+	 * Dummy value, do not use.
+	 */
+	NIC_WV_MAX
+} nic_wv_type_t;
+
+/**
+ * Specifies the interrupt/polling mode used by the driver and NIC
+ */
+typedef enum nic_poll_mode {
+	/**
+	 * NIC issues interrupts upon events.
+	 */
+	NIC_POLL_IMMEDIATE,
+	/**
+	 * Some uspace app calls nic_poll_now(...) in order to check the NIC state
+	 * - no interrupts are received from the NIC.
+	 */
+	NIC_POLL_ON_DEMAND,
+	/**
+	 * The driver itself issues a poll request in a periodic manner. It is
+	 * allowed to use hardware timer if the NIC supports it.
+	 */
+	NIC_POLL_PERIODIC,
+	/**
+	 * The driver itself issued a poll request in a periodic manner. The driver
+	 * must create software timer, internal hardware timer of NIC must not be
+	 * used even if the NIC supports it.
+	 */
+	NIC_POLL_SOFTWARE_PERIODIC
+} nic_poll_mode_t;
+
+/**
+ * Says if this virtue type is a multi-virtue (there can be multiple virtues of
+ * this type at once).
+ *
+ * @param type
+ *
+ * @return true or false
+ */
+static inline int nic_wv_is_multi(nic_wv_type_t type) {
+	switch (type) {
+	case NIC_WV_FULL_MATCH:
+	case NIC_WV_DESTINATION:
+	case NIC_WV_DIRECTED_IPV4:
+	case NIC_WV_DIRECTED_IPV6:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static inline const char *nic_device_state_to_string(nic_device_state_t state)
+{
+	switch (state) {
+	case NIC_STATE_STOPPED:
+		return "stopped";
+	case NIC_STATE_DOWN:
+		return "down";
+	case NIC_STATE_ACTIVE:
+		return "active";
+	default:
+		return "undefined";
+	}
+}
 
 #endif
Index: uspace/lib/c/include/net/eth_phys.h
===================================================================
--- uspace/lib/c/include/net/eth_phys.h	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
+++ uspace/lib/c/include/net/eth_phys.h	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2011 Radim Vansa
+ * Copyright (c) 2011 Jiri Michalec
+ * 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.
+ */
+
+#ifndef LIBC_NET_ETH_PHYS_H_
+#define LIBC_NET_ETH_PHYS_H_
+
+#include <sys/types.h>
+
+/*****************************************************/
+/* Definitions of possible supported physical layers */
+/*****************************************************/
+
+/* Ethernet physical layers */
+#define ETH_OLD          0
+#define ETH_10M          1
+#define ETH_100M         2
+#define ETH_1000M        3
+#define ETH_10G          4
+#define ETH_40G_100G     5
+/* 6, 7 reserved for future use */
+#define ETH_PHYS_LAYERS  8
+
+/* < 10Mbs ethernets */
+#define ETH_EXPERIMENTAL     0x0001
+#define ETH_1BASE5           0x0002
+/* 10Mbs ethernets */
+#define ETH_10BASE5          0x0001
+#define ETH_10BASE2          0x0002
+#define ETH_10BROAD36        0x0004
+#define ETH_STARLAN_10       0x0008
+#define ETH_LATTISNET        0x0010
+#define ETH_10BASE_T         0x0020
+#define ETH_FOIRL            0x0040
+#define ETH_10BASE_FL        0x0080
+#define ETH_10BASE_FB        0x0100
+#define ETH_10BASE_FP        0x0200
+/* 100Mbs (fast) ethernets */
+#define ETH_100BASE_TX       0x0001
+#define ETH_100BASE_T4       0x0002
+#define ETH_100BASE_T2       0x0004
+#define ETH_100BASE_FX       0x0008
+#define ETH_100BASE_SX       0x0010
+#define ETH_100BASE_BX10     0x0020
+#define ETH_100BASE_LX10     0x0040
+#define ETH_100BASE_VG       0x0080
+/* 1000Mbs (gigabit) ethernets */
+#define ETH_1000BASE_T       0x0001
+#define ETH_1000BASE_TX      0x0002
+#define ETH_1000BASE_SX      0x0004
+#define ETH_1000BASE_LX      0x0008
+#define ETH_1000BASE_LH      0x0010
+#define ETH_1000BASE_CX      0x0020
+#define ETH_1000BASE_BX10    0x0040
+#define ETH_1000BASE_LX10    0x0080
+#define ETH_1000BASE_PX10_D  0x0100
+#define ETH_1000BASE_PX10_U  0x0200
+#define ETH_1000BASE_PX20_D  0x0400
+#define ETH_1000BASE_PX20_U  0x0800
+#define ETH_1000BASE_ZX      0x1000
+#define ETH_1000BASE_KX      0x2000
+/* 10Gbs ethernets */
+#define ETH_10GBASE_SR       0x0001
+#define ETH_10GBASE_LX4      0x0002
+#define ETH_10GBASE_LR       0x0004
+#define ETH_10GBASE_ER       0x0008
+#define ETH_10GBASE_SW       0x0010
+#define ETH_10GBASE_LW       0x0020
+#define ETH_10GBASE_EW       0x0040
+#define ETH_10GBASE_CX4      0x0080
+#define ETH_10GBASE_T        0x0100
+#define ETH_10GBASE_LRM      0x0200
+#define ETH_10GBASE_KX4      0x0400
+#define ETH_10GBASE_KR       0x0800
+/* 40Gbs and 100Gbs ethernets */
+#define ETH_40GBASE_SR4      0x0001
+#define ETH_40GBASE_LR4      0x0002
+#define ETH_40GBASE_CR4      0x0004
+#define ETH_40GBASE_KR4      0x0008
+#define ETH_100GBASE_SR10    0x0010
+#define ETH_100GBASE_LR4     0x0020
+#define ETH_100GBASE_ER4     0x0040
+#define ETH_100GBASE_CR10    0x0080
+
+/******************************************/
+/* Auto-negotiation advertisement options */
+/******************************************/
+
+#define ETH_AUTONEG_10BASE_T_HALF    UINT32_C(0x00000001)
+#define ETH_AUTONEG_10BASE_T_FULL    UINT32_C(0x00000002)
+#define ETH_AUTONEG_100BASE_TX_HALF  UINT32_C(0x00000004)
+#define ETH_AUTONEG_100BASE_T4_HALF  UINT32_C(0x00000008)
+#define ETH_AUTONEG_100BASE_T2_HALF  UINT32_C(0x00000010)
+#define ETH_AUTONEG_100BASE_TX_FULL  UINT32_C(0x00000020)
+#define ETH_AUTONEG_100BASE_T2_FULL  UINT32_C(0x00000040)
+#define ETH_AUTONEG_1000BASE_T_HALF  UINT32_C(0x00000080)
+#define ETH_AUTONEG_1000BASE_T_FULL  UINT32_C(0x00000100)
+
+/** Symetric pause packet (802.3x standard) */
+#define ETH_AUTONEG_PAUSE_SYMETRIC   UINT32_C(0x10000000)
+/** Asymetric pause packet (802.3z standard, gigabit ethernet) */
+#define ETH_AUTONEG_PAUSE_ASYMETRIC  UINT32_C(0x20000000)
+
+#define ETH_AUTONEG_MODE_MASK      UINT32_C(0x0FFFFFFF)
+#define ETH_AUTONEG_FEATURES_MASK  UINT32_C(~(ETH_AUTONEG_MODE_MASK))
+
+#define ETH_AUTONEG_MODES  9
+
+struct eth_autoneg_map {
+	uint32_t value;
+	const char *name;
+};
+
+extern const char *ethernet_names[8][17];
+extern const struct eth_autoneg_map ethernet_autoneg_mapping[ETH_AUTONEG_MODES];
+
+#endif
Index: uspace/lib/c/include/net/packet.h
===================================================================
--- uspace/lib/c/include/net/packet.h	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ uspace/lib/c/include/net/packet.h	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -38,8 +38,10 @@
 #define LIBC_PACKET_H_
 
+#include <sys/types.h>
+
 /** Packet identifier type.
  * Value zero is used as an invalid identifier.
  */
-typedef int packet_id_t;
+typedef sysarg_t packet_id_t;
 
 /** Type definition of the packet.
@@ -51,5 +53,5 @@
  * @see packet_dimension
  */
-typedef struct packet_dimension	packet_dimension_t;
+typedef struct packet_dimension packet_dimension_t;
 
 /** Packet dimension. */
@@ -71,4 +73,5 @@
 extern packet_t *pm_find(packet_id_t);
 extern int pm_add(packet_t *);
+extern void pm_remove(packet_t *);
 extern int pm_init(void);
 extern void pm_destroy(void);
Index: uspace/lib/c/include/net/packet_header.h
===================================================================
--- uspace/lib/c/include/net/packet_header.h	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ uspace/lib/c/include/net/packet_header.h	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -61,4 +61,7 @@
 #define PACKET_MAGIC_VALUE	0x11227788
 
+/** Maximum total length of the packet */
+#define PACKET_MAX_LENGTH  65536
+
 /** Packet header. */
 struct packet {
@@ -85,4 +88,10 @@
 	 */
 	size_t length;
+
+	/** Offload info provided by the NIC */
+	uint32_t offload_info;
+
+	/** Mask which bits in offload info are valid */
+	uint32_t offload_mask;
 
 	/** Stored source and destination addresses length. */
Index: uspace/lib/drv/Makefile
===================================================================
--- uspace/lib/drv/Makefile	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ uspace/lib/drv/Makefile	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -39,4 +39,5 @@
 	generic/remote_hw_res.c \
 	generic/remote_char_dev.c \
+	generic/remote_nic.c \
 	generic/remote_usb.c \
 	generic/remote_pci.c \
Index: uspace/lib/drv/generic/dev_iface.c
===================================================================
--- uspace/lib/drv/generic/dev_iface.c	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ uspace/lib/drv/generic/dev_iface.c	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -41,4 +41,5 @@
 #include "remote_hw_res.h"
 #include "remote_char_dev.h"
+#include "remote_nic.h"
 #include "remote_usb.h"
 #include "remote_usbhc.h"
@@ -50,4 +51,5 @@
 		&remote_hw_res_iface,
 		&remote_char_dev_iface,
+		&remote_nic_iface,
 		&remote_pci_iface,
 		&remote_usb_iface,
Index: uspace/lib/drv/generic/driver.c
===================================================================
--- uspace/lib/drv/generic/driver.c	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ uspace/lib/drv/generic/driver.c	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -303,4 +303,14 @@
 }
 
+static void driver_dev_added(ipc_callid_t iid, ipc_call_t *icall)
+{
+	fibril_mutex_lock(&devices_mutex);
+	ddf_dev_t *dev = driver_get_device(IPC_GET_ARG1(*icall));
+	fibril_mutex_unlock(&devices_mutex);
+	
+	if (dev != NULL && driver->driver_ops->device_added != NULL)
+		driver->driver_ops->device_added(dev);
+}
+
 static void driver_dev_remove(ipc_callid_t iid, ipc_call_t *icall)
 {
@@ -450,4 +460,8 @@
 		case DRIVER_DEV_ADD:
 			driver_dev_add(callid, &call);
+			break;
+		case DRIVER_DEV_ADDED:
+			async_answer_0(callid, EOK);
+			driver_dev_added(callid, &call);
 			break;
 		case DRIVER_DEV_REMOVE:
Index: uspace/lib/drv/generic/remote_nic.c
===================================================================
--- uspace/lib/drv/generic/remote_nic.c	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
+++ uspace/lib/drv/generic/remote_nic.c	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -0,0 +1,1253 @@
+/*
+ * Copyright (c) 2011 Radim Vansa
+ * 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 libdrv
+ * @{
+ */
+/**
+ * @file
+ * @brief Driver-side RPC skeletons for DDF NIC interface
+ */
+
+#include <assert.h>
+#include <async.h>
+#include <errno.h>
+#include <ipc/services.h>
+#include <adt/measured_strings.h>
+#include <sys/time.h>
+#include "ops/nic.h"
+
+static void remote_nic_send_message(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	assert(nic_iface->send_message);
+	
+	packet_id_t packet_id = (packet_id_t) IPC_GET_ARG2(*call);
+	
+	int rc = nic_iface->send_message(dev, packet_id);
+	async_answer_0(callid, rc);
+}
+
+static void remote_nic_connect_to_nil(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	assert(nic_iface->connect_to_nil);
+	
+	services_t nil_service = (services_t) IPC_GET_ARG2(*call);
+	nic_device_id_t device_id = (nic_device_id_t) IPC_GET_ARG3(*call);
+	
+	int rc = nic_iface->connect_to_nil(dev, nil_service, device_id);
+	async_answer_0(callid, rc);
+}
+
+static void remote_nic_get_state(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	assert(nic_iface->get_state);
+	
+	nic_device_state_t state = NIC_STATE_MAX;
+	
+	int rc = nic_iface->get_state(dev, &state);
+	async_answer_1(callid, rc, state);
+}
+
+static void remote_nic_set_state(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	assert(nic_iface->set_state);
+	
+	nic_device_state_t state = (nic_device_state_t) IPC_GET_ARG2(*call);
+	
+	int rc = nic_iface->set_state(dev, state);
+	async_answer_0(callid, rc);
+}
+
+static void remote_nic_get_address(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	assert(nic_iface->get_address);
+	
+	nic_address_t address;
+	bzero(&address, sizeof(nic_address_t));
+	
+	int rc = nic_iface->get_address(dev, &address);
+	if (rc == EOK) {
+		size_t max_len;
+		ipc_callid_t data_callid;
+		
+		/* All errors will be translated into EPARTY anyway */
+		if (!async_data_read_receive(&data_callid, &max_len)) {
+			async_answer_0(data_callid, EINVAL);
+			async_answer_0(callid, EINVAL);
+			return;
+		}
+		
+		if (max_len != sizeof(nic_address_t)) {
+			async_answer_0(data_callid, ELIMIT);
+			async_answer_0(callid, ELIMIT);
+			return;
+		}
+		
+		async_data_read_finalize(data_callid, &address,
+		    sizeof(nic_address_t));
+	}
+	
+	async_answer_0(callid, rc);
+}
+
+static void remote_nic_set_address(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	
+	size_t length;
+	ipc_callid_t data_callid;
+	if (!async_data_write_receive(&data_callid, &length)) {
+		async_answer_0(data_callid, EINVAL);
+		async_answer_0(callid, EINVAL);
+		return;
+	}
+	
+	if (length > sizeof(nic_address_t)) {
+		async_answer_0(data_callid, ELIMIT);
+		async_answer_0(callid, ELIMIT);
+		return;
+	}
+	
+	nic_address_t address;
+	if (async_data_write_finalize(data_callid, &address, length) != EOK) {
+		async_answer_0(callid, EINVAL);
+		return;
+	}
+	
+	if (nic_iface->set_address != NULL) {
+		int rc = nic_iface->set_address(dev, &address);
+		async_answer_0(callid, rc);
+	} else
+		async_answer_0(callid, ENOTSUP);
+}
+
+static void remote_nic_get_stats(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->get_stats == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	nic_device_stats_t stats;
+	bzero(&stats, sizeof(nic_device_stats_t));
+	
+	int rc = nic_iface->get_stats(dev, &stats);
+	if (rc == EOK) {
+		ipc_callid_t data_callid;
+		size_t max_len;
+		if (!async_data_read_receive(&data_callid, &max_len)) {
+			async_answer_0(data_callid, EINVAL);
+			async_answer_0(callid, EINVAL);
+			return;
+		}
+		
+		if (max_len < sizeof(nic_device_stats_t)) {
+			async_answer_0(data_callid, ELIMIT);
+			async_answer_0(callid, ELIMIT);
+			return;
+		}
+		
+		async_data_read_finalize(data_callid, &stats,
+		    sizeof(nic_device_stats_t));
+	}
+	
+	async_answer_0(callid, rc);
+}
+
+static void remote_nic_get_device_info(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->get_device_info == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	nic_device_info_t info;
+	bzero(&info, sizeof(nic_device_info_t));
+	
+	int rc = nic_iface->get_device_info(dev, &info);
+	if (rc == EOK) {
+		ipc_callid_t data_callid;
+		size_t max_len;
+		if (!async_data_read_receive(&data_callid, &max_len)) {
+			async_answer_0(data_callid, EINVAL);
+			async_answer_0(callid, EINVAL);
+			return;
+		}
+		
+		if (max_len < sizeof (nic_device_info_t)) {
+			async_answer_0(data_callid, ELIMIT);
+			async_answer_0(callid, ELIMIT);
+			return;
+		}
+		
+		async_data_read_finalize(data_callid, &info,
+		    sizeof(nic_device_info_t));
+	}
+	
+	async_answer_0(callid, rc);
+}
+
+static void remote_nic_get_cable_state(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->get_cable_state == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	nic_cable_state_t cs = NIC_CS_UNKNOWN;
+	
+	int rc = nic_iface->get_cable_state(dev, &cs);
+	async_answer_1(callid, rc, (sysarg_t) cs);
+}
+
+static void remote_nic_get_operation_mode(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->get_operation_mode == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	int speed = 0;
+	nic_channel_mode_t duplex = NIC_CM_UNKNOWN;
+	nic_role_t role = NIC_ROLE_UNKNOWN;
+	
+	int rc = nic_iface->get_operation_mode(dev, &speed, &duplex, &role);
+	async_answer_3(callid, rc, (sysarg_t) speed, (sysarg_t) duplex,
+	    (sysarg_t) role);
+}
+
+static void remote_nic_set_operation_mode(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->set_operation_mode == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	int speed = (int) IPC_GET_ARG2(*call);
+	nic_channel_mode_t duplex = (nic_channel_mode_t) IPC_GET_ARG3(*call);
+	nic_role_t role = (nic_role_t) IPC_GET_ARG4(*call);
+	
+	int rc = nic_iface->set_operation_mode(dev, speed, duplex, role);
+	async_answer_0(callid, rc);
+}
+
+static void remote_nic_autoneg_enable(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->autoneg_enable == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	uint32_t advertisement = (uint32_t) IPC_GET_ARG2(*call);
+	
+	int rc = nic_iface->autoneg_enable(dev, advertisement);
+	async_answer_0(callid, rc);
+}
+
+static void remote_nic_autoneg_disable(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->autoneg_disable == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	int rc = nic_iface->autoneg_disable(dev);
+	async_answer_0(callid, rc);
+}
+
+static void remote_nic_autoneg_probe(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->autoneg_probe == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	uint32_t our_adv = 0;
+	uint32_t their_adv = 0;
+	nic_result_t result = NIC_RESULT_NOT_AVAILABLE;
+	nic_result_t their_result = NIC_RESULT_NOT_AVAILABLE;
+	
+	int rc = nic_iface->autoneg_probe(dev, &our_adv, &their_adv, &result,
+	    &their_result);
+	async_answer_4(callid, rc, our_adv, their_adv, (sysarg_t) result,
+	    (sysarg_t) their_result);
+}
+
+static void remote_nic_autoneg_restart(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->autoneg_restart == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	int rc = nic_iface->autoneg_restart(dev);
+	async_answer_0(callid, rc);
+}
+
+static void remote_nic_get_pause(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->get_pause == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	nic_result_t we_send;
+	nic_result_t we_receive;
+	uint16_t pause;
+	
+	int rc = nic_iface->get_pause(dev, &we_send, &we_receive, &pause);
+	async_answer_3(callid, rc, we_send, we_receive, pause);
+}
+
+static void remote_nic_set_pause(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->set_pause == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	int allow_send = (int) IPC_GET_ARG2(*call);
+	int allow_receive = (int) IPC_GET_ARG3(*call);
+	uint16_t pause = (uint16_t) IPC_GET_ARG4(*call);
+	
+	int rc = nic_iface->set_pause(dev, allow_send, allow_receive,
+	    pause);
+	async_answer_0(callid, rc);
+}
+
+static void remote_nic_unicast_get_mode(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->unicast_get_mode == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	size_t max_count = IPC_GET_ARG2(*call);
+	nic_address_t *address_list = NULL;
+	
+	if (max_count != 0) {
+		address_list = malloc(max_count * sizeof (nic_address_t));
+		if (!address_list) {
+			async_answer_0(callid, ENOMEM);
+			return;
+		}
+	}
+	
+	bzero(address_list, max_count * sizeof(nic_address_t));
+	nic_unicast_mode_t mode = NIC_UNICAST_DEFAULT;
+	size_t address_count = 0;
+	
+	int rc = nic_iface->unicast_get_mode(dev, &mode, max_count, address_list,
+	    &address_count);
+	
+	if ((rc != EOK) || (max_count == 0) || (address_count == 0)) {
+		free(address_list);
+		async_answer_2(callid, rc, mode, address_count);
+		return;
+	}
+	
+	ipc_callid_t data_callid;
+	size_t max_len;
+	if (!async_data_read_receive(&data_callid, &max_len)) {
+		async_answer_0(data_callid, EINVAL);
+		async_answer_2(callid, rc, mode, address_count);
+		free(address_list);
+		return;
+	}
+	
+	if (max_len > address_count * sizeof(nic_address_t))
+		max_len = address_count * sizeof(nic_address_t);
+	
+	if (max_len > max_count * sizeof(nic_address_t))
+		max_len = max_count * sizeof(nic_address_t);
+	
+	async_data_read_finalize(data_callid, address_list, max_len);
+	async_answer_0(data_callid, EINVAL);
+	
+	free(address_list);
+	async_answer_2(callid, rc, mode, address_count);
+}
+
+static void remote_nic_unicast_set_mode(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	
+	size_t length;
+	nic_unicast_mode_t mode = IPC_GET_ARG2(*call);
+	size_t address_count = IPC_GET_ARG3(*call);
+	nic_address_t *address_list = NULL;
+	
+	if (address_count) {
+		ipc_callid_t data_callid;
+		if (!async_data_write_receive(&data_callid, &length)) {
+			async_answer_0(data_callid, EINVAL);
+			async_answer_0(callid, EINVAL);
+			return;
+		}
+		
+		if (length != address_count * sizeof(nic_address_t)) {
+			async_answer_0(data_callid, ELIMIT);
+			async_answer_0(callid, ELIMIT);
+			return;
+		}
+		
+		address_list = malloc(length);
+		if (address_list == NULL) {
+			async_answer_0(data_callid, ENOMEM);
+			async_answer_0(callid, ENOMEM);
+			return;
+		}
+		
+		if (async_data_write_finalize(data_callid, address_list,
+		    length) != EOK) {
+			async_answer_0(callid, EINVAL);
+			free(address_list);
+			return;
+		}
+	}
+	
+	if (nic_iface->unicast_set_mode != NULL) {
+		int rc = nic_iface->unicast_set_mode(dev, mode, address_list,
+		    address_count);
+		async_answer_0(callid, rc);
+	} else
+		async_answer_0(callid, ENOTSUP);
+	
+	free(address_list);
+}
+
+static void remote_nic_multicast_get_mode(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->multicast_get_mode == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	size_t max_count = IPC_GET_ARG2(*call);
+	nic_address_t *address_list = NULL;
+	
+	if (max_count != 0) {
+		address_list = malloc(max_count * sizeof(nic_address_t));
+		if (!address_list) {
+			async_answer_0(callid, ENOMEM);
+			return;
+		}
+	}
+	
+	bzero(address_list, max_count * sizeof(nic_address_t));
+	nic_multicast_mode_t mode = NIC_MULTICAST_BLOCKED;
+	size_t address_count = 0;
+	
+	int rc = nic_iface->multicast_get_mode(dev, &mode, max_count, address_list,
+	    &address_count);
+	
+	
+	if ((rc != EOK) || (max_count == 0) || (address_count == 0)) {
+		free(address_list);
+		async_answer_2(callid, rc, mode, address_count);
+		return;
+	}
+	
+	ipc_callid_t data_callid;
+	size_t max_len;
+	if (!async_data_read_receive(&data_callid, &max_len)) {
+		async_answer_0(data_callid, EINVAL);
+		async_answer_2(callid, rc, mode, address_count);
+		free(address_list);
+		return;
+	}
+	
+	if (max_len > address_count * sizeof(nic_address_t))
+		max_len = address_count * sizeof(nic_address_t);
+	
+	if (max_len > max_count * sizeof(nic_address_t))
+		max_len = max_count * sizeof(nic_address_t);
+	
+	async_data_read_finalize(data_callid, address_list, max_len);
+	
+	free(address_list);
+	async_answer_2(callid, rc, mode, address_count);
+}
+
+static void remote_nic_multicast_set_mode(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	
+	nic_multicast_mode_t mode = IPC_GET_ARG2(*call);
+	size_t address_count = IPC_GET_ARG3(*call);
+	nic_address_t *address_list = NULL;
+	
+	if (address_count) {
+		ipc_callid_t data_callid;
+		size_t length;
+		if (!async_data_write_receive(&data_callid, &length)) {
+			async_answer_0(data_callid, EINVAL);
+			async_answer_0(callid, EINVAL);
+			return;
+		}
+		
+		if (length != address_count * sizeof (nic_address_t)) {
+			async_answer_0(data_callid, ELIMIT);
+			async_answer_0(callid, ELIMIT);
+			return;
+		}
+		
+		address_list = malloc(length);
+		if (address_list == NULL) {
+			async_answer_0(data_callid, ENOMEM);
+			async_answer_0(callid, ENOMEM);
+			return;
+		}
+		
+		if (async_data_write_finalize(data_callid, address_list,
+		    length) != EOK) {
+			async_answer_0(callid, EINVAL);
+			free(address_list);
+			return;
+		}
+	}
+	
+	if (nic_iface->multicast_set_mode != NULL) {
+		int rc = nic_iface->multicast_set_mode(dev, mode, address_list,
+		    address_count);
+		async_answer_0(callid, rc);
+	} else
+		async_answer_0(callid, ENOTSUP);
+	
+	free(address_list);
+}
+
+static void remote_nic_broadcast_get_mode(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->broadcast_get_mode == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	nic_broadcast_mode_t mode = NIC_BROADCAST_ACCEPTED;
+	
+	int rc = nic_iface->broadcast_get_mode(dev, &mode);
+	async_answer_1(callid, rc, mode);
+}
+
+static void remote_nic_broadcast_set_mode(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->broadcast_set_mode == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	nic_broadcast_mode_t mode = IPC_GET_ARG2(*call);
+	
+	int rc = nic_iface->broadcast_set_mode(dev, mode);
+	async_answer_0(callid, rc);
+}
+
+static void remote_nic_defective_get_mode(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->defective_get_mode == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	uint32_t mode = 0;
+	
+	int rc = nic_iface->defective_get_mode(dev, &mode);
+	async_answer_1(callid, rc, mode);
+}
+
+static void remote_nic_defective_set_mode(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->defective_set_mode == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	uint32_t mode = IPC_GET_ARG2(*call);
+	
+	int rc = nic_iface->defective_set_mode(dev, mode);
+	async_answer_0(callid, rc);
+}
+
+static void remote_nic_blocked_sources_get(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->blocked_sources_get == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	size_t max_count = IPC_GET_ARG2(*call);
+	nic_address_t *address_list = NULL;
+	
+	if (max_count != 0) {
+		address_list = malloc(max_count * sizeof(nic_address_t));
+		if (!address_list) {
+			async_answer_0(callid, ENOMEM);
+			return;
+		}
+	}
+	
+	bzero(address_list, max_count * sizeof(nic_address_t));
+	size_t address_count = 0;
+	
+	int rc = nic_iface->blocked_sources_get(dev, max_count, address_list,
+	    &address_count);
+	
+	if ((rc != EOK) || (max_count == 0) || (address_count == 0)) {
+		async_answer_1(callid, rc, address_count);
+		free(address_list);
+		return;
+	}
+	
+	ipc_callid_t data_callid;
+	size_t max_len;
+	if (!async_data_read_receive(&data_callid, &max_len)) {
+		async_answer_0(data_callid, EINVAL);
+		async_answer_1(callid, rc, address_count);
+		free(address_list);
+		return;
+	}
+	
+	if (max_len > address_count * sizeof(nic_address_t))
+		max_len = address_count * sizeof(nic_address_t);
+	
+	if (max_len > max_count * sizeof(nic_address_t))
+		max_len = max_count * sizeof(nic_address_t);
+	
+	async_data_read_finalize(data_callid, address_list, max_len);
+	async_answer_0(data_callid, EINVAL);
+	
+	free(address_list);
+	async_answer_1(callid, rc, address_count);
+}
+
+static void remote_nic_blocked_sources_set(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	
+	size_t length;
+	size_t address_count = IPC_GET_ARG2(*call);
+	nic_address_t *address_list = NULL;
+	
+	if (address_count) {
+		ipc_callid_t data_callid;
+		if (!async_data_write_receive(&data_callid, &length)) {
+			async_answer_0(data_callid, EINVAL);
+			async_answer_0(callid, EINVAL);
+			return;
+		}
+		
+		if (length != address_count * sizeof(nic_address_t)) {
+			async_answer_0(data_callid, ELIMIT);
+			async_answer_0(callid, ELIMIT);
+			return;
+		}
+		
+		address_list = malloc(length);
+		if (address_list == NULL) {
+			async_answer_0(data_callid, ENOMEM);
+			async_answer_0(callid, ENOMEM);
+			return;
+		}
+		
+		if (async_data_write_finalize(data_callid, address_list,
+		    length) != EOK) {
+			async_answer_0(callid, EINVAL);
+			free(address_list);
+			return;
+		}
+	}
+	
+	if (nic_iface->blocked_sources_set != NULL) {
+		int rc = nic_iface->blocked_sources_set(dev, address_list,
+		    address_count);
+		async_answer_0(callid, rc);
+	} else
+		async_answer_0(callid, ENOTSUP);
+	
+	free(address_list);
+}
+
+static void remote_nic_vlan_get_mask(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->vlan_get_mask == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	nic_vlan_mask_t vlan_mask;
+	bzero(&vlan_mask, sizeof(nic_vlan_mask_t));
+	
+	int rc = nic_iface->vlan_get_mask(dev, &vlan_mask);
+	if (rc == EOK) {
+		ipc_callid_t data_callid;
+		size_t max_len;
+		if (!async_data_read_receive(&data_callid, &max_len)) {
+			async_answer_0(data_callid, EINVAL);
+			async_answer_0(callid, EINVAL);
+			return;
+		}
+		
+		if (max_len != sizeof(nic_vlan_mask_t)) {
+			async_answer_0(data_callid, EINVAL);
+			async_answer_0(callid, EINVAL);
+			return;
+		}
+		
+		async_data_read_finalize(data_callid, &vlan_mask, max_len);
+	}
+	
+	async_answer_0(callid, rc);
+}
+
+static void remote_nic_vlan_set_mask(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	
+	nic_vlan_mask_t vlan_mask;
+	nic_vlan_mask_t *vlan_mask_pointer = NULL;
+	bool vlan_mask_set = (bool) IPC_GET_ARG2(*call);
+	
+	if (vlan_mask_set) {
+		ipc_callid_t data_callid;
+		size_t length;
+		if (!async_data_write_receive(&data_callid, &length)) {
+			async_answer_0(data_callid, EINVAL);
+			async_answer_0(callid, EINVAL);
+			return;
+		}
+		
+		if (length != sizeof(nic_vlan_mask_t)) {
+			async_answer_0(data_callid, ELIMIT);
+			async_answer_0(callid, ELIMIT);
+			return;
+		}
+		
+		if (async_data_write_finalize(data_callid, &vlan_mask,
+		    length) != EOK) {
+			async_answer_0(callid, EINVAL);
+			return;
+		}
+		
+		vlan_mask_pointer = &vlan_mask;
+	}
+	
+	if (nic_iface->vlan_set_mask != NULL) {
+		int rc = nic_iface->vlan_set_mask(dev, vlan_mask_pointer);
+		async_answer_0(callid, rc);
+	} else
+		async_answer_0(callid, ENOTSUP);
+}
+
+static void remote_nic_vlan_set_tag(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	
+	if (nic_iface->vlan_set_tag == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	uint16_t tag = (uint16_t) IPC_GET_ARG2(*call);
+	int add = (int) IPC_GET_ARG3(*call);
+	int strip = (int) IPC_GET_ARG4(*call);
+	
+	int rc = nic_iface->vlan_set_tag(dev, tag, add, strip);
+	async_answer_0(callid, rc);
+}
+
+static void remote_nic_wol_virtue_add(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	
+	int send_data = (int) IPC_GET_ARG3(*call);
+	ipc_callid_t data_callid;
+	
+	if (nic_iface->wol_virtue_add == NULL) {
+		if (send_data) {
+			async_data_write_receive(&data_callid, NULL);
+			async_answer_0(data_callid, ENOTSUP);
+		}
+		
+		async_answer_0(callid, ENOTSUP);
+	}
+	
+	size_t length = 0;
+	void *data = NULL;
+	
+	if (send_data) {
+		if (!async_data_write_receive(&data_callid, &length)) {
+			async_answer_0(data_callid, EINVAL);
+			async_answer_0(callid, EINVAL);
+			return;
+		}
+		
+		data = malloc(length);
+		if (data == NULL) {
+			async_answer_0(data_callid, ENOMEM);
+			async_answer_0(callid, ENOMEM);
+			return;
+		}
+		
+		if (async_data_write_finalize(data_callid, data,
+		    length) != EOK) {
+			async_answer_0(callid, EINVAL);
+			free(data);
+			return;
+		}
+	}
+	
+	nic_wv_id_t id = 0;
+	nic_wv_type_t type = (nic_wv_type_t) IPC_GET_ARG2(*call);
+	
+	int rc = nic_iface->wol_virtue_add(dev, type, data, length, &id);
+	async_answer_1(callid, rc, (sysarg_t) id);
+	free(data);
+}
+
+static void remote_nic_wol_virtue_remove(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	
+	if (nic_iface->wol_virtue_remove == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	nic_wv_id_t id = (nic_wv_id_t) IPC_GET_ARG2(*call);
+	
+	int rc = nic_iface->wol_virtue_remove(dev, id);
+	async_answer_0(callid, rc);
+}
+
+static void remote_nic_wol_virtue_probe(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	
+	if (nic_iface->wol_virtue_probe == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	nic_wv_id_t id = (nic_wv_id_t) IPC_GET_ARG2(*call);
+	size_t max_length = IPC_GET_ARG3(*call);
+	nic_wv_type_t type = NIC_WV_NONE;
+	size_t length = 0;
+	ipc_callid_t data_callid;
+	void *data = NULL;
+	
+	if (max_length != 0) {
+		data = malloc(max_length);
+		if (data == NULL) {
+			async_answer_0(callid, ENOMEM);
+			return;
+		}
+	}
+	
+	bzero(data, max_length);
+	
+	int rc = nic_iface->wol_virtue_probe(dev, id, &type, max_length,
+	    data, &length);
+	
+	if ((max_length != 0) && (length != 0)) {
+		size_t req_length;
+		if (!async_data_read_receive(&data_callid, &req_length)) {
+			async_answer_0(data_callid, EINVAL);
+			async_answer_0(callid, EINVAL);
+			free(data);
+			return;
+		}
+		
+		if (req_length > length)
+			req_length = length;
+		
+		if (req_length > max_length)
+			req_length = max_length;
+		
+		async_data_read_finalize(data_callid, data, req_length);
+	}
+	
+	async_answer_2(callid, rc, (sysarg_t) type, (sysarg_t) length);
+	free(data);
+}
+
+static void remote_nic_wol_virtue_list(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->wol_virtue_list == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	nic_wv_type_t type = (nic_wv_type_t) IPC_GET_ARG2(*call);
+	size_t max_count = IPC_GET_ARG3(*call);
+	size_t count = 0;
+	nic_wv_id_t *id_list = NULL;
+	ipc_callid_t data_callid;
+	
+	if (max_count != 0) {
+		id_list = malloc(max_count * sizeof(nic_wv_id_t));
+		if (id_list == NULL) {
+			async_answer_0(callid, ENOMEM);
+			return;
+		}
+	}
+	
+	bzero(id_list, max_count * sizeof (nic_wv_id_t));
+	
+	int rc = nic_iface->wol_virtue_list(dev, type, max_count, id_list,
+	    &count);
+	
+	if ((max_count != 0) && (count != 0)) {
+		size_t req_length;
+		if (!async_data_read_receive(&data_callid, &req_length)) {
+			async_answer_0(data_callid, EINVAL);
+			async_answer_0(callid, EINVAL);
+			free(id_list);
+			return;
+		}
+		
+		if (req_length > count * sizeof(nic_wv_id_t))
+			req_length = count * sizeof(nic_wv_id_t);
+		
+		if (req_length > max_count * sizeof(nic_wv_id_t))
+			req_length = max_count * sizeof(nic_wv_id_t);
+		
+		rc = async_data_read_finalize(data_callid, id_list, req_length);
+	}
+	
+	async_answer_1(callid, rc, (sysarg_t) count);
+	free(id_list);
+}
+
+static void remote_nic_wol_virtue_get_caps(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->wol_virtue_get_caps == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	int count = -1;
+	nic_wv_type_t type = (nic_wv_type_t) IPC_GET_ARG2(*call);
+	
+	int rc = nic_iface->wol_virtue_get_caps(dev, type, &count);
+	async_answer_1(callid, rc, (sysarg_t) count);
+}
+
+static void remote_nic_wol_load_info(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->wol_load_info == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	size_t max_length = (size_t) IPC_GET_ARG2(*call);
+	size_t frame_length = 0;
+	nic_wv_type_t type = NIC_WV_NONE;
+	uint8_t *data = NULL;
+	
+	if (max_length != 0) {
+		data = malloc(max_length);
+		if (data == NULL) {
+			async_answer_0(callid, ENOMEM);
+			return;
+		}
+	}
+	
+	bzero(data, max_length);
+	
+	int rc = nic_iface->wol_load_info(dev, &type, max_length, data,
+	    &frame_length);
+	if (rc == EOK) {
+		ipc_callid_t data_callid;
+		size_t req_length;
+		if (!async_data_read_receive(&data_callid, &req_length)) {
+			async_answer_0(data_callid, EINVAL);
+			async_answer_0(callid, EINVAL);
+			free(data);
+			return;
+		}
+		
+		req_length = req_length > max_length ? max_length : req_length;
+		req_length = req_length > frame_length ? frame_length : req_length;
+		async_data_read_finalize(data_callid, data, req_length);
+	}
+	
+	async_answer_2(callid, rc, (sysarg_t) type, (sysarg_t) frame_length);
+	free(data);
+}
+
+static void remote_nic_offload_probe(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->offload_probe == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	uint32_t supported = 0;
+	uint32_t active = 0;
+	
+	int rc = nic_iface->offload_probe(dev, &supported, &active);
+	async_answer_2(callid, rc, supported, active);
+}
+
+static void remote_nic_offload_set(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->offload_set == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	uint32_t mask = (uint32_t) IPC_GET_ARG2(*call);
+	uint32_t active = (uint32_t) IPC_GET_ARG3(*call);
+	
+	int rc = nic_iface->offload_set(dev, mask, active);
+	async_answer_0(callid, rc);
+}
+
+static void remote_nic_poll_get_mode(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->poll_get_mode == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	nic_poll_mode_t mode = NIC_POLL_IMMEDIATE;
+	int request_data = IPC_GET_ARG2(*call);
+	struct timeval period = {
+		.tv_sec = 0,
+		.tv_usec = 0
+	};
+	
+	int rc = nic_iface->poll_get_mode(dev, &mode, &period);
+	if ((rc == EOK) && (request_data)) {
+		size_t max_len;
+		ipc_callid_t data_callid;
+		
+		if (!async_data_read_receive(&data_callid, &max_len)) {
+			async_answer_0(data_callid, EINVAL);
+			async_answer_0(callid, EINVAL);
+			return;
+		}
+		
+		if (max_len != sizeof(struct timeval)) {
+			async_answer_0(data_callid, ELIMIT);
+			async_answer_0(callid, ELIMIT);
+			return;
+		}
+		
+		async_data_read_finalize(data_callid, &period,
+		    sizeof(struct timeval));
+	}
+	
+	async_answer_1(callid, rc, (sysarg_t) mode);
+}
+
+static void remote_nic_poll_set_mode(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	
+	nic_poll_mode_t mode = IPC_GET_ARG2(*call);
+	int has_period = IPC_GET_ARG3(*call);
+	struct timeval period_buf;
+	struct timeval *period = NULL;
+	size_t length;
+	
+	if (has_period) {
+		ipc_callid_t data_callid;
+		if (!async_data_write_receive(&data_callid, &length)) {
+			async_answer_0(data_callid, EINVAL);
+			async_answer_0(callid, EINVAL);
+			return;
+		}
+		
+		if (length != sizeof(struct timeval)) {
+			async_answer_0(data_callid, ELIMIT);
+			async_answer_0(callid, ELIMIT);
+			return;
+		}
+		
+		period = &period_buf;
+		if (async_data_write_finalize(data_callid, period,
+		    length) != EOK) {
+			async_answer_0(callid, EINVAL);
+			return;
+		}
+	}
+	
+	if (nic_iface->poll_set_mode != NULL) {
+		int rc = nic_iface->poll_set_mode(dev, mode, period);
+		async_answer_0(callid, rc);
+	} else
+		async_answer_0(callid, ENOTSUP);
+}
+
+static void remote_nic_poll_now(ddf_fun_t *dev, void *iface,
+    ipc_callid_t callid, ipc_call_t *call)
+{
+	nic_iface_t *nic_iface = (nic_iface_t *) iface;
+	if (nic_iface->poll_now == NULL) {
+		async_answer_0(callid, ENOTSUP);
+		return;
+	}
+	
+	int rc = nic_iface->poll_now(dev);
+	async_answer_0(callid, rc);
+}
+
+/** Remote NIC interface operations.
+ *
+ */
+static remote_iface_func_ptr_t remote_nic_iface_ops[] = {
+	&remote_nic_send_message,
+	&remote_nic_connect_to_nil,
+	&remote_nic_get_state,
+	&remote_nic_set_state,
+	&remote_nic_get_address,
+	&remote_nic_set_address,
+	&remote_nic_get_stats,
+	&remote_nic_get_device_info,
+	&remote_nic_get_cable_state,
+	&remote_nic_get_operation_mode,
+	&remote_nic_set_operation_mode,
+	&remote_nic_autoneg_enable,
+	&remote_nic_autoneg_disable,
+	&remote_nic_autoneg_probe,
+	&remote_nic_autoneg_restart,
+	&remote_nic_get_pause,
+	&remote_nic_set_pause,
+	&remote_nic_unicast_get_mode,
+	&remote_nic_unicast_set_mode,
+	&remote_nic_multicast_get_mode,
+	&remote_nic_multicast_set_mode,
+	&remote_nic_broadcast_get_mode,
+	&remote_nic_broadcast_set_mode,
+	&remote_nic_defective_get_mode,
+	&remote_nic_defective_set_mode,
+	&remote_nic_blocked_sources_get,
+	&remote_nic_blocked_sources_set,
+	&remote_nic_vlan_get_mask,
+	&remote_nic_vlan_set_mask,
+	&remote_nic_vlan_set_tag,
+	&remote_nic_wol_virtue_add,
+	&remote_nic_wol_virtue_remove,
+	&remote_nic_wol_virtue_probe,
+	&remote_nic_wol_virtue_list,
+	&remote_nic_wol_virtue_get_caps,
+	&remote_nic_wol_load_info,
+	&remote_nic_offload_probe,
+	&remote_nic_offload_set,
+	&remote_nic_poll_get_mode,
+	&remote_nic_poll_set_mode,
+	&remote_nic_poll_now
+};
+
+/** Remote NIC interface structure.
+ *
+ * Interface for processing request from remote
+ * clients addressed to the NIC interface.
+ *
+ */
+remote_iface_t remote_nic_iface = {
+	.method_count = sizeof(remote_nic_iface_ops) /
+	    sizeof(remote_iface_func_ptr_t),
+	.methods = remote_nic_iface_ops
+};
+
+/**
+ * @}
+ */
Index: uspace/lib/drv/include/ddf/driver.h
===================================================================
--- uspace/lib/drv/include/ddf/driver.h	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ uspace/lib/drv/include/ddf/driver.h	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -137,4 +137,10 @@
 	/** Callback method for passing a new device to the device driver */
 	int (*add_device)(ddf_dev_t *);
+	/**
+	 * Notification that the device was succesfully added.
+	 * The driver can do any blocking operation without
+	 * blocking the device manager.
+	 */
+	void (*device_added)(ddf_dev_t *dev);
 	/** Ask driver to remove a device */
 	int (*dev_remove)(ddf_dev_t *);
Index: uspace/lib/drv/include/ops/nic.h
===================================================================
--- uspace/lib/drv/include/ops/nic.h	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
+++ uspace/lib/drv/include/ops/nic.h	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2011 Radim Vansa
+ * 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 libdrv
+ * @{
+ */
+/** @file
+ * @brief DDF NIC interface definition
+ */
+
+#ifndef LIBDRV_OPS_NIC_H_
+#define LIBDRV_OPS_NIC_H_
+
+#include <net/packet.h>
+#include <ipc/services.h>
+#include <net/device.h>
+#include <sys/time.h>
+
+#include "../ddf/driver.h"
+
+typedef struct nic_iface {
+	/** Mandatory methods */
+	int (*send_message)(ddf_fun_t *, packet_id_t);
+	int (*connect_to_nil)(ddf_fun_t *, services_t, nic_device_id_t);
+	int (*get_state)(ddf_fun_t *, nic_device_state_t *);
+	int (*set_state)(ddf_fun_t *, nic_device_state_t);
+	int (*get_address)(ddf_fun_t *, nic_address_t *);
+	
+	/** Optional methods */
+	int (*set_address)(ddf_fun_t *, const nic_address_t *);
+	int (*get_stats)(ddf_fun_t *, nic_device_stats_t *);
+	int (*get_device_info)(ddf_fun_t *, nic_device_info_t *);
+	int (*get_cable_state)(ddf_fun_t *, nic_cable_state_t *);
+	
+	int (*get_operation_mode)(ddf_fun_t *, int *, nic_channel_mode_t *,
+	    nic_role_t *);
+	int (*set_operation_mode)(ddf_fun_t *, int, nic_channel_mode_t,
+	    nic_role_t);
+	int (*autoneg_enable)(ddf_fun_t *, uint32_t);
+	int (*autoneg_disable)(ddf_fun_t *);
+	int (*autoneg_probe)(ddf_fun_t *, uint32_t *, uint32_t *,
+	    nic_result_t *, nic_result_t *);
+	int (*autoneg_restart)(ddf_fun_t *);
+	int (*get_pause)(ddf_fun_t *, nic_result_t *, nic_result_t *,
+		uint16_t *);
+	int (*set_pause)(ddf_fun_t *, int, int, uint16_t);
+	
+	int (*unicast_get_mode)(ddf_fun_t *, nic_unicast_mode_t *, size_t,
+	    nic_address_t *, size_t *);
+	int (*unicast_set_mode)(ddf_fun_t *, nic_unicast_mode_t,
+	    const nic_address_t *, size_t);
+	int (*multicast_get_mode)(ddf_fun_t *, nic_multicast_mode_t *, size_t,
+	    nic_address_t *, size_t *);
+	int (*multicast_set_mode)(ddf_fun_t *, nic_multicast_mode_t,
+	    const nic_address_t *, size_t);
+	int (*broadcast_get_mode)(ddf_fun_t *, nic_broadcast_mode_t *);
+	int (*broadcast_set_mode)(ddf_fun_t *, nic_broadcast_mode_t);
+	int (*defective_get_mode)(ddf_fun_t *, uint32_t *);
+	int (*defective_set_mode)(ddf_fun_t *, uint32_t);
+	int (*blocked_sources_get)(ddf_fun_t *, size_t, nic_address_t *,
+	    size_t *);
+	int (*blocked_sources_set)(ddf_fun_t *, const nic_address_t *, size_t);
+	
+	int (*vlan_get_mask)(ddf_fun_t *, nic_vlan_mask_t *);
+	int (*vlan_set_mask)(ddf_fun_t *, const nic_vlan_mask_t *);
+	int (*vlan_set_tag)(ddf_fun_t *, uint16_t, int, int);
+	
+	int (*wol_virtue_add)(ddf_fun_t *, nic_wv_type_t, const void *,
+	    size_t, nic_wv_id_t *);
+	int (*wol_virtue_remove)(ddf_fun_t *, nic_wv_id_t);
+	int (*wol_virtue_probe)(ddf_fun_t *, nic_wv_id_t, nic_wv_type_t *,
+	    size_t, void *, size_t *);
+	int (*wol_virtue_list)(ddf_fun_t *, nic_wv_type_t, size_t,
+	    nic_wv_id_t *, size_t *);
+	int (*wol_virtue_get_caps)(ddf_fun_t *, nic_wv_type_t, int *);
+	int (*wol_load_info)(ddf_fun_t *, nic_wv_type_t *, size_t,
+	    uint8_t *, size_t *);
+	
+	int (*offload_probe)(ddf_fun_t *, uint32_t *, uint32_t *);
+	int (*offload_set)(ddf_fun_t *, uint32_t, uint32_t);
+	
+	int (*poll_get_mode)(ddf_fun_t *, nic_poll_mode_t *,
+	    struct timeval *);
+	int (*poll_set_mode)(ddf_fun_t *, nic_poll_mode_t,
+	    const struct timeval *);
+	int (*poll_now)(ddf_fun_t *);
+} nic_iface_t;
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/lib/drv/include/remote_nic.h
===================================================================
--- uspace/lib/drv/include/remote_nic.h	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
+++ uspace/lib/drv/include/remote_nic.h	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2011 Radim Vansa
+ * 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 libdrv
+ * @{
+ */
+/** @file
+ */
+
+#ifndef LIBDRV_REMOTE_NIC_H_
+#define LIBDRV_REMOTE_NIC_H_
+
+extern remote_iface_t remote_nic_iface;
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/lib/net/Makefile
===================================================================
--- uspace/lib/net/Makefile	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ uspace/lib/net/Makefile	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -40,6 +40,4 @@
 	generic/protocol_map.c \
 	adt/module_map.c \
-	netif/netif_remote.c \
-	netif/netif_skel.c \
 	nil/nil_remote.c \
 	nil/nil_skel.c \
Index: uspace/lib/net/generic/generic.c
===================================================================
--- uspace/lib/net/generic/generic.c	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ uspace/lib/net/generic/generic.c	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -54,5 +54,5 @@
  */
 int generic_device_state_msg_remote(async_sess_t *sess, sysarg_t message,
-    device_id_t device_id, sysarg_t state, services_t target)
+    nic_device_id_t device_id, sysarg_t state, services_t target)
 {
 	async_exch_t *exch = async_exchange_begin(sess);
@@ -68,5 +68,4 @@
  * @param[in] message   Service specific message.
  * @param[in] device_id Device identifier.
- * @param[in] arg2      Second argument of the message.
  * @param[in] service   Device module service.
  *
@@ -77,9 +76,9 @@
  */
 int generic_device_req_remote(async_sess_t *sess, sysarg_t message,
-    device_id_t device_id, sysarg_t arg2, services_t service)
-{
-	async_exch_t *exch = async_exchange_begin(sess);
-	int rc = async_req_3_0(exch, message, (sysarg_t) device_id,
-	    arg2, (sysarg_t) service);
+    nic_device_id_t device_id, services_t service)
+{
+	async_exch_t *exch = async_exchange_begin(sess);
+	int rc = async_req_3_0(exch, message, (sysarg_t) device_id, 0,
+	    (sysarg_t) service);
 	async_exchange_end(exch);
 	
@@ -103,25 +102,21 @@
  */
 int generic_get_addr_req(async_sess_t *sess, sysarg_t message,
-    device_id_t device_id, measured_string_t **address, uint8_t **data)
-{
-	if ((!address) || (!data))
+    nic_device_id_t device_id, uint8_t *address, size_t max_len)
+{
+	if (!address)
 		return EBADMEM;
 	
 	/* Request the address */
 	async_exch_t *exch = async_exchange_begin(sess);
-	aid_t message_id = async_send_1(exch, message, (sysarg_t) device_id,
+	aid_t aid = async_send_1(exch, message, (sysarg_t) device_id,
 	    NULL);
-	int rc = measured_strings_return(exch, address, data, 1);
+	int rc = async_data_read_start(exch, address, max_len);
 	async_exchange_end(exch);
 	
 	sysarg_t result;
-	async_wait_for(message_id, &result);
-	
-	/* If not successful */
-	if ((rc == EOK) && (result != EOK)) {
-		/* Clear the data */
-		free(*address);
-		free(*data);
-	}
+	async_wait_for(aid, &result);
+	
+	if (rc != EOK)
+		return rc;
 	
 	return (int) result;
@@ -142,5 +137,5 @@
  */
 int generic_packet_size_req_remote(async_sess_t *sess, sysarg_t message,
-    device_id_t device_id, packet_dimension_t *packet_dimension)
+    nic_device_id_t device_id, packet_dimension_t *packet_dimension)
 {
 	if (!packet_dimension)
@@ -179,5 +174,5 @@
  */
 int generic_received_msg_remote(async_sess_t *sess, sysarg_t message,
-    device_id_t device_id, packet_id_t packet_id, services_t target,
+    nic_device_id_t device_id, packet_id_t packet_id, services_t target,
     services_t error)
 {
@@ -210,5 +205,5 @@
  */
 int generic_send_msg_remote(async_sess_t *sess, sysarg_t message,
-    device_id_t device_id, packet_id_t packet_id, services_t sender,
+    nic_device_id_t device_id, packet_id_t packet_id, services_t sender,
     services_t error)
 {
@@ -251,5 +246,5 @@
  */
 int generic_translate_req(async_sess_t *sess, sysarg_t message,
-    device_id_t device_id, services_t service,
+    nic_device_id_t device_id, services_t service,
     measured_string_t *configuration, size_t count,
     measured_string_t **translation, uint8_t **data)
Index: uspace/lib/net/generic/net_checksum.c
===================================================================
--- uspace/lib/net/generic/net_checksum.c	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ uspace/lib/net/generic/net_checksum.c	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -40,8 +40,11 @@
 
 /** Big-endian encoding CRC divider. */
-#define CRC_DIVIDER_BE	0x04c11db7
+#define CRC_DIVIDER_BE  0x04c11db7
 
 /** Little-endian encoding CRC divider. */
-#define CRC_DIVIDER_LE	0xedb88320
+#define CRC_DIVIDER_LE  0xedb88320
+
+/** Polynomial used in multicast address hashing */
+#define CRC_MCAST_POLYNOMIAL  0x04c11db6
 
 /** Compacts the computed checksum to the 16 bit number adding the carries.
@@ -203,5 +206,5 @@
 }
 
-/** Computes the ip header checksum.
+/** Compute the IP header checksum.
  *
  * To compute the checksum of a new packet, the checksum header field must be
@@ -221,4 +224,39 @@
 }
 
+/** Compute the standard hash from MAC
+ *
+ * Hashing MAC into 64 possible values and using the value as index to
+ * 64bit number.
+ *
+ * The code is copied from qemu-0.13's implementation of ne2000 and rt8139
+ * drivers, but according to documentation there it originates in FreeBSD.
+ *
+ * @param[in] addr The 6-byte MAC address to be hashed
+ *
+ * @return 64-bit number with only single bit set to 1
+ *
+ */
+uint64_t multicast_hash(const uint8_t addr[6])
+{
+	uint32_t crc;
+    int carry, i, j;
+    uint8_t b;
+
+    crc = 0xffffffff;
+    for (i = 0; i < 6; i++) {
+        b = addr[i];
+        for (j = 0; j < 8; j++) {
+            carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01);
+            crc <<= 1;
+            b >>= 1;
+            if (carry)
+                crc = ((crc ^ CRC_MCAST_POLYNOMIAL) | carry);
+        }
+    }
+	
+    uint64_t one64 = 1;
+    return one64 << (crc >> 26);
+}
+
 /** @}
  */
Index: uspace/lib/net/generic/net_remote.c
===================================================================
--- uspace/lib/net/generic/net_remote.c	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ uspace/lib/net/generic/net_remote.c	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -38,7 +38,7 @@
 #include <ipc/services.h>
 #include <ipc/net_net.h>
-
 #include <malloc.h>
-
+#include <async.h>
+#include <devman.h>
 #include <generic.h>
 #include <net/modules.h>
@@ -98,5 +98,5 @@
     size_t count, uint8_t **data)
 {
-	return generic_translate_req(sess, NET_NET_GET_DEVICE_CONF, 0, 0,
+	return generic_translate_req(sess, NET_NET_GET_CONF, 0, 0,
 	    *configuration, count, configuration, data);
 }
@@ -124,5 +124,5 @@
  *
  */
-int net_get_device_conf_req(async_sess_t *sess, device_id_t device_id,
+int net_get_device_conf_req(async_sess_t *sess, nic_device_id_t device_id,
     measured_string_t **configuration, size_t count, uint8_t **data)
 {
@@ -131,4 +131,49 @@
 }
 
+int net_get_devices_req(async_sess_t *sess, measured_string_t **devices,
+    size_t *count, uint8_t **data)
+{
+	if ((!devices) || (!count))
+		return EBADMEM;
+	
+	async_exch_t *exch = async_exchange_begin(sess);
+	
+	int rc = async_req_0_1(exch, NET_NET_GET_DEVICES_COUNT, count);
+	if (rc != EOK) {
+		async_exchange_end(exch);
+		return rc;
+	}
+	
+	if (*count == 0) {
+		async_exchange_end(exch);
+		*data = NULL;
+		return EOK;
+	}
+	
+	aid_t message_id = async_send_0(exch, NET_NET_GET_DEVICES, NULL);
+	rc = measured_strings_return(exch, devices, data, *count);
+	
+	async_exchange_end(exch);
+	
+	sysarg_t result;
+	async_wait_for(message_id, &result);
+	
+	if ((rc == EOK) && (result != EOK)) {
+		free(*devices);
+		free(*data);
+	}
+	
+	return (int) result;
+}
+
+int net_driver_ready(async_sess_t *sess, devman_handle_t handle)
+{
+	async_exch_t *exch = async_exchange_begin(sess);
+	int rc = async_req_1_0(exch, NET_NET_DRIVER_READY, handle);
+	async_exchange_end(exch);
+	
+	return rc;
+}
+
 /** @}
  */
Index: uspace/lib/net/generic/packet_remote.c
===================================================================
--- uspace/lib/net/generic/packet_remote.c	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ uspace/lib/net/generic/packet_remote.c	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -115,5 +115,5 @@
 	
 	*packet = pm_find(packet_id);
-	if (!*packet) {
+	if (*packet == NULL) {
 		async_exch_t *exch = async_exchange_begin(sess);
 		sysarg_t size;
@@ -130,5 +130,5 @@
 	}
 	
-	if ((*packet)->next) {
+	if ((*packet != NULL) && ((*packet)->next)) {
 		packet_t *next;
 		return packet_translate_remote(sess, &next, (*packet)->next);
Index: uspace/lib/net/generic/protocol_map.c
===================================================================
--- uspace/lib/net/generic/protocol_map.c	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ uspace/lib/net/generic/protocol_map.c	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -50,5 +50,5 @@
 	switch (nil) {
 	case SERVICE_ETHERNET:
-	case SERVICE_NE2000:
+	case SERVICE_NILDUMMY:
 		switch (il) {
 		case SERVICE_IP:
@@ -76,5 +76,5 @@
 	switch (nil) {
 	case SERVICE_ETHERNET:
-	case SERVICE_NE2000:
+	case SERVICE_NILDUMMY:
 		switch (protocol) {
 		case ETH_P_IP:
@@ -139,5 +139,4 @@
 	switch (nil) {
 	case SERVICE_ETHERNET:
-	case SERVICE_NE2000:
 		return HW_ETHER;
 	default:
Index: uspace/lib/net/il/arp_remote.c
===================================================================
--- uspace/lib/net/il/arp_remote.c	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ uspace/lib/net/il/arp_remote.c	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -84,5 +84,5 @@
  *
  */
-int arp_clear_address_req(async_sess_t *sess, device_id_t device_id,
+int arp_clear_address_req(async_sess_t *sess, nic_device_id_t device_id,
     services_t protocol, measured_string_t *address)
 {
@@ -108,5 +108,5 @@
  *
  */
-int arp_clear_device_req(async_sess_t *sess, device_id_t device_id)
+int arp_clear_device_req(async_sess_t *sess, nic_device_id_t device_id)
 {
 	async_exch_t *exch = async_exchange_begin(sess);
@@ -143,5 +143,5 @@
  *
  */
-int arp_device_req(async_sess_t *sess, device_id_t device_id,
+int arp_device_req(async_sess_t *sess, nic_device_id_t device_id,
     services_t protocol, services_t netif, measured_string_t *address)
 {
@@ -177,5 +177,5 @@
  *
  */
-int arp_translate_req(async_sess_t *sess, device_id_t device_id,
+int arp_translate_req(async_sess_t *sess, nic_device_id_t device_id,
     services_t protocol, measured_string_t *address,
     measured_string_t **translation, uint8_t **data)
Index: uspace/lib/net/il/il_remote.c
===================================================================
--- uspace/lib/net/il/il_remote.c	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ uspace/lib/net/il/il_remote.c	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -55,6 +55,6 @@
  *
  */
-int il_device_state_msg(async_sess_t *sess, device_id_t device_id,
-    device_state_t state, services_t target)
+int il_device_state_msg(async_sess_t *sess, nic_device_id_t device_id,
+    nic_device_state_t state, services_t target)
 {
 	return generic_device_state_msg_remote(sess, NET_IL_DEVICE_STATE,
@@ -73,6 +73,6 @@
  *
  */
-int il_received_msg(async_sess_t *sess, device_id_t device_id, packet_t *packet,
-    services_t target)
+int il_received_msg(async_sess_t *sess, nic_device_id_t device_id,
+    packet_t *packet, services_t target)
 {
 	return generic_received_msg_remote(sess, NET_IL_RECEIVED, device_id,
@@ -91,5 +91,5 @@
  *
  */
-int il_mtu_changed_msg(async_sess_t *sess, device_id_t device_id, size_t mtu,
+int il_mtu_changed_msg(async_sess_t *sess, nic_device_id_t device_id, size_t mtu,
     services_t target)
 {
@@ -98,4 +98,26 @@
 }
 
+/** Notify IL layer modules about address change (implemented by ARP)
+ *
+ */
+int il_addr_changed_msg(async_sess_t *sess, nic_device_id_t device_id,
+    size_t addr_len, const uint8_t *address)
+{
+	async_exch_t *exch = async_exchange_begin(sess);
+	
+	aid_t message_id = async_send_1(exch, NET_IL_ADDR_CHANGED,
+			(sysarg_t) device_id, NULL);
+	int rc = async_data_write_start(exch, address, addr_len);
+	
+	async_exchange_end(exch);
+	
+	sysarg_t res;
+    async_wait_for(message_id, &res);
+    if (rc != EOK)
+		return rc;
+	
+    return (int) res;
+}
+
 /** @}
  */
Index: uspace/lib/net/il/ip_remote.c
===================================================================
--- uspace/lib/net/il/ip_remote.c	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ uspace/lib/net/il/ip_remote.c	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -62,5 +62,5 @@
  *
  */
-int ip_add_route_req_remote(async_sess_t *sess, device_id_t device_id,
+int ip_add_route_req_remote(async_sess_t *sess, nic_device_id_t device_id,
     in_addr_t address, in_addr_t netmask, in_addr_t gateway)
 {
@@ -123,8 +123,8 @@
  *
  */
-int ip_device_req_remote(async_sess_t *sess, device_id_t device_id,
+int ip_device_req(async_sess_t *sess, nic_device_id_t device_id,
     services_t service)
 {
-	return generic_device_req_remote(sess, NET_IP_DEVICE, device_id, 0,
+	return generic_device_req_remote(sess, NET_IP_DEVICE, device_id,
 	    service);
 }
@@ -144,5 +144,5 @@
 int ip_get_route_req_remote(async_sess_t *sess, ip_protocol_t protocol,
     const struct sockaddr *destination, socklen_t addrlen,
-    device_id_t *device_id, void **header, size_t *headerlen)
+    nic_device_id_t *device_id, void **header, size_t *headerlen)
 {
 	if ((!destination) || (addrlen == 0))
@@ -196,5 +196,5 @@
  *
  */
-int ip_packet_size_req_remote(async_sess_t *sess, device_id_t device_id,
+int ip_packet_size_req_remote(async_sess_t *sess, nic_device_id_t device_id,
     packet_dimension_t *packet_dimension)
 {
@@ -216,5 +216,5 @@
  *
  */
-int ip_received_error_msg_remote(async_sess_t *sess, device_id_t device_id,
+int ip_received_error_msg_remote(async_sess_t *sess, nic_device_id_t device_id,
     packet_t *packet, services_t target, services_t error)
 {
@@ -240,5 +240,5 @@
  *
  */
-int ip_send_msg_remote(async_sess_t *sess, device_id_t device_id,
+int ip_send_msg_remote(async_sess_t *sess, nic_device_id_t device_id,
     packet_t *packet, services_t sender, services_t error)
 {
@@ -256,5 +256,5 @@
  *
  */
-int ip_set_gateway_req_remote(async_sess_t *sess, device_id_t device_id,
+int ip_set_gateway_req_remote(async_sess_t *sess, nic_device_id_t device_id,
     in_addr_t gateway)
 {
Index: uspace/lib/net/include/arp_interface.h
===================================================================
--- uspace/lib/net/include/arp_interface.h	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ uspace/lib/net/include/arp_interface.h	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -46,10 +46,10 @@
 /*@{*/
 
-extern int arp_device_req(async_sess_t *, device_id_t, services_t, services_t,
+extern int arp_device_req(async_sess_t *, nic_device_id_t, services_t, services_t,
     measured_string_t *);
-extern int arp_translate_req(async_sess_t *, device_id_t, services_t,
+extern int arp_translate_req(async_sess_t *, nic_device_id_t, services_t,
     measured_string_t *, measured_string_t **, uint8_t **);
-extern int arp_clear_device_req(async_sess_t *, device_id_t);
-extern int arp_clear_address_req(async_sess_t *, device_id_t, services_t,
+extern int arp_clear_device_req(async_sess_t *, nic_device_id_t);
+extern int arp_clear_address_req(async_sess_t *, nic_device_id_t, services_t,
     measured_string_t *);
 extern int arp_clean_cache_req(async_sess_t *);
Index: uspace/lib/net/include/generic.h
===================================================================
--- uspace/lib/net/include/generic.h	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ uspace/lib/net/include/generic.h	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -45,16 +45,16 @@
 
 extern int generic_device_state_msg_remote(async_sess_t *, sysarg_t,
-    device_id_t, sysarg_t, services_t);
-extern int generic_device_req_remote(async_sess_t *, sysarg_t, device_id_t,
-    sysarg_t, services_t);
-extern int generic_get_addr_req(async_sess_t *, sysarg_t, device_id_t,
-    measured_string_t **, uint8_t **);
-extern int generic_packet_size_req_remote(async_sess_t *, sysarg_t, device_id_t,
-    packet_dimension_t *);
-extern int generic_received_msg_remote(async_sess_t *, sysarg_t, device_id_t,
+    nic_device_id_t, sysarg_t, services_t);
+extern int generic_device_req_remote(async_sess_t *, sysarg_t, nic_device_id_t,
+    services_t);
+extern int generic_get_addr_req(async_sess_t *, sysarg_t, nic_device_id_t,
+    uint8_t *address, size_t max_length);
+extern int generic_packet_size_req_remote(async_sess_t *, sysarg_t,
+    nic_device_id_t, packet_dimension_t *);
+extern int generic_received_msg_remote(async_sess_t *, sysarg_t,
+    nic_device_id_t, packet_id_t, services_t, services_t);
+extern int generic_send_msg_remote(async_sess_t *, sysarg_t, nic_device_id_t,
     packet_id_t, services_t, services_t);
-extern int generic_send_msg_remote(async_sess_t *, sysarg_t, device_id_t,
-    packet_id_t, services_t, services_t);
-extern int generic_translate_req(async_sess_t *, sysarg_t, device_id_t,
+extern int generic_translate_req(async_sess_t *, sysarg_t, nic_device_id_t,
     services_t, measured_string_t *, size_t, measured_string_t **, uint8_t **);
 
Index: uspace/lib/net/include/il_remote.h
===================================================================
--- uspace/lib/net/include/il_remote.h	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ uspace/lib/net/include/il_remote.h	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -50,8 +50,12 @@
 /*@{*/
 
-extern int il_device_state_msg(async_sess_t *, device_id_t, device_state_t,
+extern int il_device_state_msg(async_sess_t *, nic_device_id_t,
+    nic_device_state_t, services_t);
+extern int il_received_msg(async_sess_t *, nic_device_id_t, packet_t *,
     services_t);
-extern int il_received_msg(async_sess_t *, device_id_t, packet_t *, services_t);
-extern int il_mtu_changed_msg(async_sess_t *, device_id_t, size_t, services_t);
+extern int il_mtu_changed_msg(async_sess_t *, nic_device_id_t, size_t,
+    services_t);
+extern int il_addr_changed_msg(async_sess_t *, nic_device_id_t, size_t,
+    const uint8_t *);
 
 /*@}*/
Index: uspace/lib/net/include/ip_interface.h
===================================================================
--- uspace/lib/net/include/ip_interface.h	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ uspace/lib/net/include/ip_interface.h	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -46,5 +46,4 @@
 #define ip_set_gateway_req     ip_set_gateway_req_remote
 #define ip_packet_size_req     ip_packet_size_req_remote
-#define ip_device_req          ip_device_req_remote
 #define ip_add_route_req       ip_add_route_req_remote
 #define ip_send_msg            ip_send_msg_remote
@@ -69,5 +68,5 @@
  *
  */
-typedef int (*tl_received_msg_t)(device_id_t device_id, packet_t *packet,
+typedef int (*tl_received_msg_t)(nic_device_id_t device_id, packet_t *packet,
     services_t receiver, services_t error);
 
Index: uspace/lib/net/include/ip_remote.h
===================================================================
--- uspace/lib/net/include/ip_remote.h	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ uspace/lib/net/include/ip_remote.h	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -43,16 +43,16 @@
 #include <async.h>
 
-extern int ip_set_gateway_req_remote(async_sess_t *, device_id_t, in_addr_t);
-extern int ip_packet_size_req_remote(async_sess_t *, device_id_t,
+extern int ip_set_gateway_req_remote(async_sess_t *, nic_device_id_t, in_addr_t);
+extern int ip_packet_size_req_remote(async_sess_t *, nic_device_id_t,
     packet_dimension_t *);
-extern int ip_received_error_msg_remote(async_sess_t *, device_id_t, packet_t *,
+extern int ip_received_error_msg_remote(async_sess_t *, nic_device_id_t, packet_t *,
     services_t, services_t);
-extern int ip_device_req_remote(async_sess_t *, device_id_t, services_t);
-extern int ip_add_route_req_remote(async_sess_t *, device_id_t, in_addr_t,
+extern int ip_device_req(async_sess_t *, nic_device_id_t, services_t);
+extern int ip_add_route_req_remote(async_sess_t *, nic_device_id_t, in_addr_t,
     in_addr_t, in_addr_t);
-extern int ip_send_msg_remote(async_sess_t *, device_id_t, packet_t *,
+extern int ip_send_msg_remote(async_sess_t *, nic_device_id_t, packet_t *,
     services_t, services_t);
 extern int ip_get_route_req_remote(async_sess_t *, ip_protocol_t,
-    const struct sockaddr *, socklen_t, device_id_t *, void **, size_t *);
+    const struct sockaddr *, socklen_t, nic_device_id_t *, void **, size_t *);
 
 #endif
Index: uspace/lib/net/include/net_checksum.h
===================================================================
--- uspace/lib/net/include/net_checksum.h	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ uspace/lib/net/include/net_checksum.h	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -30,5 +30,4 @@
  * @{
  */
-
 /** @file
  * General CRC and checksum computation.
@@ -42,14 +41,22 @@
 
 /** IP checksum value for computed zero checksum.
+ *
  * Zero is returned as 0xFFFF (not flipped)
+ *
  */
-#define IP_CHECKSUM_ZERO	0xffffU
+#define IP_CHECKSUM_ZERO  0xffffU
 
-#ifdef ARCH_IS_BIG_ENDIAN
+#ifdef __BE__
+
 #define compute_crc32(seed, data, length) \
 	compute_crc32_be(seed, (uint8_t *) data, length)
-#else
+
+#endif
+
+#ifdef __LE__
+
 #define compute_crc32(seed, data, length) \
 	compute_crc32_le(seed, (uint8_t *) data, length)
+
 #endif
 
@@ -60,4 +67,5 @@
 extern uint16_t flip_checksum(uint16_t);
 extern uint16_t ip_checksum(uint8_t *, size_t);
+extern uint64_t multicast_hash(const uint8_t addr[6]);
 
 #endif
Index: uspace/lib/net/include/net_interface.h
===================================================================
--- uspace/lib/net/include/net_interface.h	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ uspace/lib/net/include/net_interface.h	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -35,8 +35,8 @@
 
 #include <ipc/services.h>
-
 #include <net/device.h>
 #include <adt/measured_strings.h>
 #include <async.h>
+#include <devman.h>
 
 /** @name Networking module interface
@@ -45,9 +45,12 @@
 /*@{*/
 
-extern int net_get_device_conf_req(async_sess_t *, device_id_t,
+extern int net_get_device_conf_req(async_sess_t *, nic_device_id_t,
     measured_string_t **, size_t, uint8_t **);
 extern int net_get_conf_req(async_sess_t *, measured_string_t **, size_t,
     uint8_t **);
 extern void net_free_settings(measured_string_t *, uint8_t *);
+extern int net_get_devices_req(async_sess_t *, measured_string_t **, size_t *,
+    uint8_t **);
+extern int net_driver_ready(async_sess_t *, devman_handle_t);
 extern async_sess_t *net_connect_module(void);
 
Index: uspace/lib/net/include/netif_remote.h
===================================================================
--- uspace/lib/net/include/netif_remote.h	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ 	(revision )
@@ -1,55 +1,0 @@
-/*
- * 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 libnet
- * @{
- */
-
-#ifndef LIBNET_NETIF_REMOTE_H_
-#define LIBNET_NETIF_REMOTE_H_
-
-#include <ipc/services.h>
-#include <adt/measured_strings.h>
-#include <net/device.h>
-#include <net/packet.h>
-#include <async.h>
-
-extern int netif_get_addr_req(async_sess_t *, device_id_t, measured_string_t **,
-    uint8_t **);
-extern int netif_probe_req(async_sess_t *, device_id_t, int, void *);
-extern int netif_send_msg(async_sess_t *, device_id_t, packet_t *, services_t);
-extern int netif_start_req(async_sess_t *, device_id_t);
-extern int netif_stop_req(async_sess_t *, device_id_t);
-extern int netif_stats_req(async_sess_t *, device_id_t, device_stats_t *);
-extern async_sess_t *netif_bind_service(services_t, device_id_t, services_t,
-    async_client_conn_t);
-
-#endif
-
-/** @}
- */
Index: uspace/lib/net/include/netif_skel.h
===================================================================
--- uspace/lib/net/include/netif_skel.h	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ 	(revision )
@@ -1,212 +1,0 @@
-/*
- * 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 libnet
- * @{
- */
-
-/** @file
- * Network interface module skeleton.
- * The skeleton has to be part of each network interface module.
- */
-
-#ifndef NET_NETIF_SKEL_H_
-#define NET_NETIF_SKEL_H_
-
-#include <fibril_synch.h>
-#include <ipc/services.h>
-#include <adt/measured_strings.h>
-#include <net/device.h>
-#include <net/packet.h>
-#include <async.h>
-
-/** Network interface device specific data. */
-typedef struct {
-	device_id_t device_id;   /**< Device identifier. */
-	device_state_t state;    /**< Actual device state. */
-	void *specific;          /**< Driver specific data. */
-} netif_device_t;
-
-/** Device map.
- *
- * Maps device identifiers to the network interface device specific data.
- * @see device.h
- *
- */
-DEVICE_MAP_DECLARE(netif_device_map, netif_device_t);
-
-/** Network interface module skeleton global data. */
-typedef struct {
-	async_sess_t *sess;             /**< Networking module session. */
-	async_sess_t *nil_sess;         /**< Network interface layer session. */
-	netif_device_map_t device_map;  /**< Device map. */
-	fibril_rwlock_t lock;           /**< Safety lock. */
-} netif_globals_t;
-
-extern netif_globals_t netif_globals;
-
-/** Initialize the specific module.
- *
- * This function has to be implemented in user code.
- *
- */
-extern int netif_initialize(void);
-
-/** Probe the existence of the device.
- *
- * This has to be implemented in user code.
- *
- * @param[in] device_id Device identifier.
- * @param[in] irq       Device interrupt number.
- * @param[in] io        Device input/output address.
- *
- * @return EOK on success.
- * @return Other error codes as defined for the find_device()
- *         function.
- * @return Other error codes as defined for the specific module
- *         message implementation.
- *
- */
-extern int netif_probe_message(device_id_t device_id, int irq, void *io);
-
-/** Send the packet queue.
- *
- * This has to be implemented in user code.
- *
- * @param[in] device_id Device identifier.
- * @param[in] packet    Packet queue.
- * @param[in] sender    Sending module service.
- *
- * @return EOK on success.
- * @return EFORWARD if the device is not active (in the
- *         NETIF_ACTIVE state).
- * @return Other error codes as defined for the find_device()
- *         function.
- * @return Other error codes as defined for the specific module
- *         message implementation.
- *
- */
-extern int netif_send_message(device_id_t device_id, packet_t *packet,
-    services_t sender);
-
-/** Start the device.
- *
- * This has to be implemented in user code.
- *
- * @param[in] device Device structure.
- *
- * @return New network interface state (non-negative values).
- * @return Other error codes as defined for the find_device()
- *         function.
- * @return Other error codes as defined for the specific module
- *         message implementation.
- *
- */
-extern int netif_start_message(netif_device_t *device);
-
-/** Stop the device.
- *
- * This has to be implemented in user code.
- *
- * @param[in] device Device structure.
- *
- * @return EOK on success.
- * @return Other error codes as defined for the find_device()
- *         function.
- * @return Other error codes as defined for the specific module
- *         message implementation.
- *
- */
-extern int netif_stop_message(netif_device_t *device);
-
-/** Return the device local hardware address.
- *
- * This has to be implemented in user code.
- *
- * @param[in] device_id Device identifier.
- * @param[out] address  Device local hardware address.
- *
- * @return EOK on success.
- * @return EBADMEM if the address parameter is NULL.
- * @return ENOENT if there no such device.
- * @return Other error codes as defined for the find_device()
- *         function.
- * @return Other error codes as defined for the specific module
- *         message implementation.
- *
- */
-extern int netif_get_addr_message(device_id_t device_id,
-    measured_string_t *address);
-
-/** Process the netif driver specific message.
- *
- * This function is called for uncommon messages received by the netif
- * skeleton. This has to be implemented in user code.
- *
- * @param[in]  callid Message identifier.
- * @param[in]  call   Message.
- * @param[out] answer Answer.
- * @param[out] count  Number of answer arguments.
- *
- * @return EOK on success.
- * @return ENOTSUP if the message is not known.
- * @return Other error codes as defined for the specific module
- *         message implementation.
- *
- */
-extern int netif_specific_message(ipc_callid_t callid, ipc_call_t *call,
-    ipc_call_t *answer, size_t *count);
-
-/** Return the device usage statistics.
- *
- * This has to be implemented in user code.
- *
- * @param[in]  device_id Device identifier.
- * @param[out] stats     Device usage statistics.
- *
- * @return EOK on success.
- * @return Other error codes as defined for the find_device()
- *         function.
- * @return Other error codes as defined for the specific module
- *         message implementation.
- *
- */
-extern int netif_get_device_stats(device_id_t device_id,
-    device_stats_t *stats);
-
-extern int find_device(device_id_t, netif_device_t **);
-extern void null_device_stats(device_stats_t *);
-extern void netif_pq_release(packet_id_t);
-extern packet_t *netif_packet_get_1(size_t);
-
-extern int netif_module_start(void);
-
-#endif
-
-/** @}
- */
Index: uspace/lib/net/include/nil_remote.h
===================================================================
--- uspace/lib/net/include/nil_remote.h	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ uspace/lib/net/include/nil_remote.h	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -34,7 +34,7 @@
 #define __NET_NIL_REMOTE_H__
 
-#include <ipc/services.h>
 #include <net/device.h>
 #include <net/packet.h>
+#include <devman.h>
 #include <generic.h>
 #include <async.h>
@@ -58,11 +58,10 @@
 	    packet_get_id(packet), sender, 0)
 
-#define nil_device_req(sess, device_id, mtu, netif_service) \
-	generic_device_req_remote(sess, NET_NIL_DEVICE, device_id, mtu, \
-	    netif_service)
-
-extern int nil_device_state_msg(async_sess_t *, device_id_t, sysarg_t);
-extern int nil_received_msg(async_sess_t *, device_id_t, packet_t *,
-    services_t);
+extern int nil_device_req(async_sess_t *, nic_device_id_t, devman_handle_t,
+    size_t);
+extern int nil_device_state_msg(async_sess_t *, nic_device_id_t, sysarg_t);
+extern int nil_received_msg(async_sess_t *, nic_device_id_t, packet_id_t);
+extern int nil_addr_changed_msg(async_sess_t *, nic_device_id_t,
+    const nic_address_t *);
 
 #endif
Index: uspace/lib/net/include/nil_skel.h
===================================================================
--- uspace/lib/net/include/nil_skel.h	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ uspace/lib/net/include/nil_skel.h	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -70,5 +70,5 @@
  *
  */
-extern int nil_device_state_msg_local(device_id_t device_id, sysarg_t state);
+extern int nil_device_state_msg_local(nic_device_id_t device_id, sysarg_t state);
 
 /** Pass the packet queue to the network interface layer.
@@ -81,5 +81,4 @@
  * @param[in] device_id Source device identifier.
  * @param[in] packet    Received packet or the received packet queue.
- * @param[in] target    Target service. Ignored parameter.
  *
  * @return EOK on success.
@@ -88,6 +87,5 @@
  *
  */
-extern int nil_received_msg_local(device_id_t device_id, packet_t *packet,
-    services_t target);
+extern int nil_received_msg_local(nic_device_id_t device_id, packet_t *packet);
 
 /** Message processing function.
Index: uspace/lib/net/include/tl_common.h
===================================================================
--- uspace/lib/net/include/tl_common.h	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ uspace/lib/net/include/tl_common.h	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -52,7 +52,7 @@
 
 extern int tl_get_ip_packet_dimension(async_sess_t *, packet_dimensions_t *,
-    device_id_t, packet_dimension_t **);
+    nic_device_id_t, packet_dimension_t **);
 extern int tl_get_address_port(const struct sockaddr *, int, uint16_t *);
-extern int tl_update_ip_packet_dimension(packet_dimensions_t *, device_id_t,
+extern int tl_update_ip_packet_dimension(packet_dimensions_t *, nic_device_id_t,
     size_t);
 extern int tl_set_address_port(struct sockaddr *, int, uint16_t);
Index: uspace/lib/net/include/tl_remote.h
===================================================================
--- uspace/lib/net/include/tl_remote.h	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ uspace/lib/net/include/tl_remote.h	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -51,6 +51,6 @@
 /*@{*/
 
-extern int tl_received_msg(async_sess_t *, device_id_t, packet_t *, services_t,
-    services_t);
+extern int tl_received_msg(async_sess_t *, nic_device_id_t, packet_t *,
+    services_t, services_t);
 
 /*@}*/
Index: uspace/lib/net/netif/netif_remote.c
===================================================================
--- uspace/lib/net/netif/netif_remote.c	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ 	(revision )
@@ -1,199 +1,0 @@
-/*
- * 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 libnet
- * @{
- */
-
-/** @file
- * Network interface module interface implementation for remote modules.
- */
-
-#include <netif_remote.h>
-#include <packet_client.h>
-#include <generic.h>
-#include <ipc/services.h>
-#include <ipc/netif.h>
-#include <net/modules.h>
-#include <adt/measured_strings.h>
-#include <net/packet.h>
-#include <net/device.h>
-
-/** Return the device local hardware address.
- *
- * @param[in]  sess      Network interface session.
- * @param[in]  device_id Device identifier.
- * @param[out] address   Device local hardware address.
- * @param[out] data      Address data.
- *
- * @return EOK on success.
- * @return EBADMEM if the address parameter is NULL.
- * @return ENOENT if there no such device.
- * @return Other error codes as defined for the
- *         netif_get_addr_message() function.
- *
- */
-int netif_get_addr_req(async_sess_t *sess, device_id_t device_id,
-    measured_string_t **address, uint8_t **data)
-{
-	return generic_get_addr_req(sess, NET_NETIF_GET_ADDR, device_id,
-	    address, data);
-}
-
-/** Probe the existence of the device.
- *
- * @param[in] sess      Network interface session.
- * @param[in] device_id Device identifier.
- * @param[in] irq       Device interrupt number.
- * @param[in] io        Device input/output address.
- *
- * @return EOK on success.
- * @return Other error codes as defined for the
- *         netif_probe_message().
- *
- */
-int netif_probe_req(async_sess_t *sess, device_id_t device_id, int irq, void *io)
-{
-	async_exch_t *exch = async_exchange_begin(sess);
-	int rc = async_req_3_0(exch, NET_NETIF_PROBE, device_id, (sysarg_t) irq,
-	    (sysarg_t) io);
-	async_exchange_end(exch);
-	
-	return rc;
-}
-
-/** Send the packet queue.
- *
- * @param[in] sess      Network interface session.
- * @param[in] device_id Device identifier.
- * @param[in] packet    Packet queue.
- * @param[in] sender    Sending module service.
- *
- * @return EOK on success.
- * @return Other error codes as defined for the generic_send_msg()
- *         function.
- *
- */
-int netif_send_msg(async_sess_t *sess, device_id_t device_id, packet_t *packet,
-    services_t sender)
-{
-	return generic_send_msg_remote(sess, NET_NETIF_SEND, device_id,
-	    packet_get_id(packet), sender, 0);
-}
-
-/** Start the device.
- *
- * @param[in] sess      Network interface session.
- * @param[in] device_id Device identifier.
- *
- * @return EOK on success.
- * @return Other error codes as defined for the find_device()
- *         function.
- * @return Other error codes as defined for the
- *         netif_start_message() function.
- *
- */
-int netif_start_req(async_sess_t *sess, device_id_t device_id)
-{
-	async_exch_t *exch = async_exchange_begin(sess);
-	int rc = async_req_1_0(exch, NET_NETIF_START, device_id);
-	async_exchange_end(exch);
-	
-	return rc;
-}
-
-/** Stop the device.
- *
- * @param[in] sess      Network interface session.
- * @param[in] device_id Device identifier.
- *
- * @return EOK on success.
- * @return Other error codes as defined for the find_device()
- *         function.
- * @return Other error codes as defined for the
- *         netif_stop_message() function.
- *
- */
-int netif_stop_req(async_sess_t *sess, device_id_t device_id)
-{
-	async_exch_t *exch = async_exchange_begin(sess);
-	int rc = async_req_1_0(exch, NET_NETIF_STOP, device_id);
-	async_exchange_end(exch);
-	
-	return rc;
-}
-
-/** Return the device usage statistics.
- *
- * @param[in]  sess      Network interface session.
- * @param[in]  device_id Device identifier.
- * @param[out] stats     Device usage statistics.
- *
- * @return EOK on success.
- *
- */
-int netif_stats_req(async_sess_t *sess, device_id_t device_id,
-    device_stats_t *stats)
-{
-	if (!stats)
-		return EBADMEM;
-	
-	async_exch_t *exch = async_exchange_begin(sess);
-	aid_t message_id = async_send_1(exch, NET_NETIF_STATS,
-	    (sysarg_t) device_id, NULL);
-	async_data_read_start(exch, stats, sizeof(*stats));
-	async_exchange_end(exch);
-	
-	sysarg_t result;
-	async_wait_for(message_id, &result);
-	
-	return (int) result;
-}
-
-/** Create bidirectional connection with the network interface module
- *
- * Create bidirectional connection with the network interface module and
- * register the message receiver.
- *
- * @param[in] service   Network interface module service.
- * @param[in] device_id Device identifier.
- * @param[in] me        Requesting module service.
- * @param[in] receiver  Message receiver.
- *
- * @return Session to the needed service.
- * @return NULL on failure.
- *
- */
-async_sess_t *netif_bind_service(services_t service, device_id_t device_id,
-    services_t me, async_client_conn_t receiver)
-{
-	return bind_service(service, device_id, me, 0, receiver);
-}
-
-/** @}
- */
Index: uspace/lib/net/netif/netif_skel.c
===================================================================
--- uspace/lib/net/netif/netif_skel.c	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ 	(revision )
@@ -1,422 +1,0 @@
-/*
- * 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 libnet
- * @{
- */
-
-/** @file
- * Network interface module skeleton implementation.
- * @see netif_skel.h
- */
-
-#include <async.h>
-#include <mem.h>
-#include <fibril_synch.h>
-#include <stdio.h>
-#include <ipc/services.h>
-#include <ipc/netif.h>
-#include <errno.h>
-
-#include <generic.h>
-#include <net/modules.h>
-#include <net/packet.h>
-#include <packet_client.h>
-#include <packet_remote.h>
-#include <adt/measured_strings.h>
-#include <net/device.h>
-#include <netif_skel.h>
-#include <nil_remote.h>
-
-DEVICE_MAP_IMPLEMENT(netif_device_map, netif_device_t);
-
-/** Network interface global data. */
-netif_globals_t netif_globals;
-
-/** Probe the existence of the device.
- *
- * @param[in] device_id   Device identifier.
- * @param[in] irq         Device interrupt number.
- * @param[in] io          Device input/output address.
- *
- * @return EOK on success.
- * @return Other error codes as defined for the
- *         netif_probe_message().
- *
- */
-static int netif_probe_req_local(device_id_t device_id, int irq, void *io)
-{
-	fibril_rwlock_write_lock(&netif_globals.lock);
-	int result = netif_probe_message(device_id, irq, io);
-	fibril_rwlock_write_unlock(&netif_globals.lock);
-	
-	return result;
-}
-
-/** Send the packet queue.
- *
- * @param[in] device_id   Device identifier.
- * @param[in] packet      Packet queue.
- * @param[in] sender      Sending module service.
- *
- * @return EOK on success.
- * @return Other error codes as defined for the generic_send_msg()
- *         function.
- *
- */
-static int netif_send_msg_local(device_id_t device_id, packet_t *packet,
-    services_t sender)
-{
-	fibril_rwlock_write_lock(&netif_globals.lock);
-	int result = netif_send_message(device_id, packet, sender);
-	fibril_rwlock_write_unlock(&netif_globals.lock);
-	
-	return result;
-}
-
-/** Start the device.
- *
- * @param[in] device_id   Device identifier.
- *
- * @return EOK on success.
- * @return Other error codes as defined for the find_device()
- *         function.
- * @return Other error codes as defined for the
- *         netif_start_message() function.
- *
- */
-static int netif_start_req_local(device_id_t device_id)
-{
-	fibril_rwlock_write_lock(&netif_globals.lock);
-	
-	netif_device_t *device;
-	int rc = find_device(device_id, &device);
-	if (rc != EOK) {
-		fibril_rwlock_write_unlock(&netif_globals.lock);
-		return rc;
-	}
-	
-	int result = netif_start_message(device);
-	if (result > NETIF_NULL) {
-		nil_device_state_msg(netif_globals.nil_sess, device_id, result);
-		fibril_rwlock_write_unlock(&netif_globals.lock);
-		return EOK;
-	}
-	
-	fibril_rwlock_write_unlock(&netif_globals.lock);
-	
-	return result;
-}
-
-/** Stop the device.
- *
- * @param[in] device_id   Device identifier.
- *
- * @return EOK on success.
- * @return Other error codes as defined for the find_device()
- *         function.
- * @return Other error codes as defined for the
- *         netif_stop_message() function.
- *
- */
-static int netif_stop_req_local(device_id_t device_id)
-{
-	fibril_rwlock_write_lock(&netif_globals.lock);
-	
-	netif_device_t *device;
-	int rc = find_device(device_id, &device);
-	if (rc != EOK) {
-		fibril_rwlock_write_unlock(&netif_globals.lock);
-		return rc;
-	}
-	
-	int result = netif_stop_message(device);
-	if (result > NETIF_NULL) {
-		nil_device_state_msg(netif_globals.nil_sess, device_id, result);
-		fibril_rwlock_write_unlock(&netif_globals.lock);
-		return EOK;
-	}
-	
-	fibril_rwlock_write_unlock(&netif_globals.lock);
-	
-	return result;
-}
-
-/** Find the device specific data.
- *
- * @param[in]  device_id Device identifier.
- * @param[out] device    Device specific data.
- *
- * @return EOK on success.
- * @return ENOENT if device is not found.
- * @return EPERM if the device is not initialized.
- *
- */
-int find_device(device_id_t device_id, netif_device_t **device)
-{
-	if (!device)
-		return EBADMEM;
-	
-	*device = netif_device_map_find(&netif_globals.device_map, device_id);
-	if (*device == NULL)
-		return ENOENT;
-	
-	if ((*device)->state == NETIF_NULL)
-		return EPERM;
-	
-	return EOK;
-}
-
-/** Clear the usage statistics.
- *
- * @param[in] stats The usage statistics.
- *
- */
-void null_device_stats(device_stats_t *stats)
-{
-	bzero(stats, sizeof(device_stats_t));
-}
-
-/** Release the given packet.
- *
- * Prepared for future optimization.
- *
- * @param[in] packet_id The packet identifier.
- *
- */
-void netif_pq_release(packet_id_t packet_id)
-{
-	pq_release_remote(netif_globals.sess, packet_id);
-}
-
-/** Allocate new packet to handle the given content size.
- *
- * @param[in] content Minimum content size.
- *
- * @return The allocated packet.
- * @return NULL on error.
- *
- */
-packet_t *netif_packet_get_1(size_t content)
-{
-	return packet_get_1_remote(netif_globals.sess, content);
-}
-
-/** Register the device notification receiver,
- *
- * Register a network interface layer module as the device
- * notification receiver.
- *
- * @param[in] sess      Session to the network interface layer module.
- *
- * @return EOK on success.
- * @return ELIMIT if there is another module registered.
- *
- */
-static int register_message(async_sess_t *sess)
-{
-	fibril_rwlock_write_lock(&netif_globals.lock);
-	if (netif_globals.nil_sess != NULL) {
-		fibril_rwlock_write_unlock(&netif_globals.lock);
-		return ELIMIT;
-	}
-	
-	netif_globals.nil_sess = sess;
-	
-	fibril_rwlock_write_unlock(&netif_globals.lock);
-	return EOK;
-}
-
-/** Process the netif module messages.
- *
- * @param[in]  callid Mmessage identifier.
- * @param[in]  call   Message.
- * @param[out] answer Answer.
- * @param[out] count  Number of arguments of the answer.
- *
- * @return EOK on success.
- * @return ENOTSUP if the message is unknown.
- * @return Other error codes as defined for each specific module
- *         message function.
- *
- * @see IS_NET_NETIF_MESSAGE()
- *
- */
-static int netif_module_message(ipc_callid_t callid, ipc_call_t *call,
-    ipc_call_t *answer, size_t *count)
-{
-	size_t length;
-	device_stats_t stats;
-	packet_t *packet;
-	measured_string_t address;
-	int rc;
-	
-	*count = 0;
-	
-	if (!IPC_GET_IMETHOD(*call))
-		return EOK;
-	
-	async_sess_t *callback =
-	    async_callback_receive_start(EXCHANGE_SERIALIZE, call);
-	if (callback)
-		return register_message(callback);
-	
-	switch (IPC_GET_IMETHOD(*call)) {
-	case NET_NETIF_PROBE:
-		return netif_probe_req_local(IPC_GET_DEVICE(*call),
-		    NETIF_GET_IRQ(*call), NETIF_GET_IO(*call));
-	
-	case NET_NETIF_SEND:
-		rc = packet_translate_remote(netif_globals.sess, &packet,
-		    IPC_GET_PACKET(*call));
-		if (rc != EOK)
-			return rc;
-		
-		return netif_send_msg_local(IPC_GET_DEVICE(*call), packet,
-		    IPC_GET_SENDER(*call));
-	
-	case NET_NETIF_START:
-		return netif_start_req_local(IPC_GET_DEVICE(*call));
-	
-	case NET_NETIF_STATS:
-		fibril_rwlock_read_lock(&netif_globals.lock);
-		
-		rc = async_data_read_receive(&callid, &length);
-		if (rc != EOK) {
-			fibril_rwlock_read_unlock(&netif_globals.lock);
-			return rc;
-		}
-		
-		if (length < sizeof(device_stats_t)) {
-			fibril_rwlock_read_unlock(&netif_globals.lock);
-			return EOVERFLOW;
-		}
-		
-		rc = netif_get_device_stats(IPC_GET_DEVICE(*call), &stats);
-		if (rc == EOK) {
-			rc = async_data_read_finalize(callid, &stats,
-			    sizeof(device_stats_t));
-		}
-		
-		fibril_rwlock_read_unlock(&netif_globals.lock);
-		return rc;
-	
-	case NET_NETIF_STOP:
-		return netif_stop_req_local(IPC_GET_DEVICE(*call));
-	
-	case NET_NETIF_GET_ADDR:
-		fibril_rwlock_read_lock(&netif_globals.lock);
-		
-		rc = netif_get_addr_message(IPC_GET_DEVICE(*call), &address);
-		if (rc == EOK)
-			rc = measured_strings_reply(&address, 1);
-		
-		fibril_rwlock_read_unlock(&netif_globals.lock);
-		return rc;
-	}
-	
-	return netif_specific_message(callid, call, answer, count);
-}
-
-/** Default fibril for new module connections.
- *
- * @param[in] iid   Initial message identifier.
- * @param[in] icall Initial message call structure.
- *
- */
-static void netif_client_connection(ipc_callid_t iid, ipc_call_t *icall,
-    void *arg)
-{
-	/*
-	 * Accept the connection by answering
-	 * the initial IPC_M_CONNECT_ME_TO call.
-	 */
-	async_answer_0(iid, EOK);
-	
-	while (true) {
-		ipc_call_t answer;
-		size_t count;
-		
-		/* Clear the answer structure */
-		refresh_answer(&answer, &count);
-		
-		/* Fetch the next message */
-		ipc_call_t call;
-		ipc_callid_t callid = async_get_call(&call);
-		
-		/* Process the message */
-		int res = netif_module_message(callid, &call, &answer, &count);
-		
-		/* End if said to either by the message or the processing result */
-		if ((!IPC_GET_IMETHOD(call)) || (res == EHANGUP))
-			return;
-		
-		/* Answer the message */
-		answer_call(callid, res, &answer, count);
-	}
-}
-
-/** Start the network interface module.
- *
- * Initialize the client connection serving function, initialize the module,
- * registers the module service and start the async manager, processing IPC
- * messages in an infinite loop.
- *
- * @return EOK on success.
- * @return Other error codes as defined for each specific module
- *         message function.
- *
- */
-int netif_module_start(void)
-{
-	async_set_client_connection(netif_client_connection);
-	
-	netif_globals.sess = connect_to_service(SERVICE_NETWORKING);
-	netif_globals.nil_sess = NULL;
-	netif_device_map_initialize(&netif_globals.device_map);
-	
-	int rc = pm_init();
-	if (rc != EOK)
-		return rc;
-	
-	fibril_rwlock_initialize(&netif_globals.lock);
-	
-	rc = netif_initialize();
-	if (rc != EOK) {
-		pm_destroy();
-		return rc;
-	}
-	
-	async_manager();
-	
-	pm_destroy();
-	return EOK;
-}
-
-/** @}
- */
Index: uspace/lib/net/nil/nil_remote.c
===================================================================
--- uspace/lib/net/nil/nil_remote.c	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ uspace/lib/net/nil/nil_remote.c	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -54,5 +54,5 @@
  *
  */
-int nil_device_state_msg(async_sess_t *sess, device_id_t device_id,
+int nil_device_state_msg(async_sess_t *sess, nic_device_id_t device_id,
     sysarg_t state)
 {
@@ -76,9 +76,44 @@
  *
  */
-int nil_received_msg(async_sess_t *sess, device_id_t device_id,
-    packet_t *packet, services_t target)
+int nil_received_msg(async_sess_t *sess, nic_device_id_t device_id,
+    packet_id_t packet_id)
 {
 	return generic_received_msg_remote(sess, NET_NIL_RECEIVED,
-	    device_id, packet_get_id(packet), target, 0);
+	    device_id, packet_id, 0, 0);
+}
+
+/** Notify upper layers that device address has changed
+ *
+ */
+int nil_addr_changed_msg(async_sess_t *sess, nic_device_id_t device_id,
+    const nic_address_t *address)
+{
+	assert(sess);
+	
+	async_exch_t *exch = async_exchange_begin(sess);
+	
+	aid_t message_id = async_send_1(exch, NET_NIL_ADDR_CHANGED,
+	    (sysarg_t) device_id, NULL);
+	int rc = async_data_write_start(exch, address, sizeof (nic_address_t));
+	
+	async_exchange_end(exch);
+	
+	sysarg_t res;
+    async_wait_for(message_id, &res);
+	
+    if (rc != EOK)
+		return rc;
+	
+    return (int) res;
+}
+
+int nil_device_req(async_sess_t *sess, nic_device_id_t device_id,
+    devman_handle_t handle, size_t mtu)
+{
+	async_exch_t *exch = async_exchange_begin(sess);
+	int rc = async_req_3_0(exch, NET_NIL_DEVICE, (sysarg_t) device_id,
+	    (sysarg_t) handle, (sysarg_t) mtu);
+	async_exchange_end(exch);
+	return rc;
 }
 
Index: uspace/lib/net/tl/icmp_client.c
===================================================================
--- uspace/lib/net/tl/icmp_client.c	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ uspace/lib/net/tl/icmp_client.c	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -39,12 +39,6 @@
 #include <icmp_header.h>
 #include <packet_client.h>
-
-#ifdef CONFIG_DEBUG
-#include <stdio.h>
-#endif
-
 #include <errno.h>
 #include <sys/types.h>
-
 #include <net/icmp_codes.h>
 #include <net/packet.h>
@@ -60,6 +54,5 @@
  * @return		Zero if the packet contains no data.
  */
-int
-icmp_client_process_packet(packet_t *packet, icmp_type_t *type,
+int icmp_client_process_packet(packet_t *packet, icmp_type_t *type,
     icmp_code_t *code, icmp_param_t *pointer, icmp_param_t *mtu)
 {
@@ -81,9 +74,4 @@
 		*mtu = header->un.frag.mtu;
 
-	/* Remove debug dump */
-#ifdef CONFIG_DEBUG
-	printf("ICMP error %d (%d) in packet %d\n", header->type, header->code,
-	    packet_get_id(packet));
-#endif
 	return sizeof(icmp_header_t);
 }
Index: uspace/lib/net/tl/tl_common.c
===================================================================
--- uspace/lib/net/tl/tl_common.c	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ uspace/lib/net/tl/tl_common.c	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -119,5 +119,5 @@
  */
 int tl_get_ip_packet_dimension(async_sess_t *sess,
-    packet_dimensions_t *packet_dimensions, device_id_t device_id,
+    packet_dimensions_t *packet_dimensions, nic_device_id_t device_id,
     packet_dimension_t **packet_dimension)
 {
@@ -160,5 +160,5 @@
 int
 tl_update_ip_packet_dimension(packet_dimensions_t *packet_dimensions,
-    device_id_t device_id, size_t content)
+    nic_device_id_t device_id, size_t content)
 {
 	packet_dimension_t *packet_dimension;
@@ -170,7 +170,7 @@
 	packet_dimension->content = content;
 
-	if (device_id != DEVICE_INVALID_ID) {
+	if (device_id != NIC_DEVICE_INVALID_ID) {
 		packet_dimension = packet_dimensions_find(packet_dimensions,
-		    DEVICE_INVALID_ID);
+		    NIC_DEVICE_INVALID_ID);
 
 		if (packet_dimension) {
@@ -179,5 +179,5 @@
 			else
 				packet_dimensions_exclude(packet_dimensions,
-				    DEVICE_INVALID_ID, free);
+				    NIC_DEVICE_INVALID_ID, free);
 		}
 	}
Index: uspace/lib/net/tl/tl_remote.c
===================================================================
--- uspace/lib/net/tl/tl_remote.c	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ uspace/lib/net/tl/tl_remote.c	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -56,5 +56,5 @@
  *
  */
-int tl_received_msg(async_sess_t *sess, device_id_t device_id, packet_t *packet,
+int tl_received_msg(async_sess_t *sess, nic_device_id_t device_id, packet_t *packet,
     services_t target, services_t error)
 {
Index: uspace/lib/net/tl/tl_skel.c
===================================================================
--- uspace/lib/net/tl/tl_skel.c	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ uspace/lib/net/tl/tl_skel.c	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -123,4 +123,5 @@
 		goto out;
 	
+	task_retval(0);
 	async_manager();
 	
Index: uspace/lib/nic/Makefile
===================================================================
--- uspace/lib/nic/Makefile	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
+++ uspace/lib/nic/Makefile	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -0,0 +1,41 @@
+#
+# Copyright (c) 2011 Radim Vansa
+# 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.
+#
+
+USPACE_PREFIX = ../..
+LIBRARY = libnic
+LIBS = $(LIBDRV_PREFIX)/libdrv.a $(LIBNET_PREFIX)/libnet.a
+EXTRA_CFLAGS += -DLIBNIC_INTERNAL -Iinclude -I$(LIBDRV_PREFIX)/include -I$(LIBNET_PREFIX)/include
+
+SOURCES = \
+	src/nic_driver.c \
+	src/nic_addr_db.c \
+	src/nic_rx_control.c \
+	src/nic_wol_virtues.c \
+	src/nic_impl.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/lib/nic/include/nic.h
===================================================================
--- uspace/lib/nic/include/nic.h	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
+++ uspace/lib/nic/include/nic.h	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 2011 Radim Vansa
+ * 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 libnic
+ * @{
+ */
+/**
+ * @file
+ * @brief Public header exposing NICF to drivers
+ */
+
+#ifndef __NIC_H__
+#define __NIC_H__
+
+#include <adt/list.h>
+#include <ddf/driver.h>
+#include <device/hw_res_parsed.h>
+#include <net/packet.h>
+#include <ops/nic.h>
+
+struct nic;
+typedef struct nic nic_t;
+
+/**
+ * Single WOL virtue descriptor.
+ */
+typedef struct nic_wol_virtue {
+	link_t item;
+	nic_wv_id_t id;
+	nic_wv_type_t type;
+	const void *data;
+	size_t length;
+	struct nic_wol_virtue *next;
+} nic_wol_virtue_t;
+
+/**
+ * Simple structure for sending the allocated frames (packets) in a list.
+ */
+typedef struct {
+	link_t link;
+	packet_t *packet;
+} nic_frame_t;
+
+typedef list_t nic_frame_list_t;
+
+/**
+ * Handler for writing packet data to the NIC device.
+ * The function is responsible for releasing the packet.
+ * It does not return anything, if some error is detected the function just
+ * silently fails (logging on debug level is suggested).
+ *
+ * @param nic_data
+ * @param packet	Pointer to the packet to be sent
+ */
+typedef void (*write_packet_handler)(nic_t *, packet_t *);
+/**
+ * The handler for transitions between driver states.
+ * If the handler returns negative error code, the transition between
+ * states is canceled (the state is not changed).
+ *
+ * @param nic_data	NICF main structure
+ *
+ * @return EOK	If everything is all right.
+ * @return negative error code on error.
+ */
+typedef int (*state_change_handler)(nic_t *);
+/**
+ * Handler for unicast filtering mode change.
+ *
+ * @param nic_data		NICF main structure
+ * @param new_mode		The mode that should be set up
+ * @param address_list	Addresses as argument to the mode
+ * @param address_count	Number of addresses in the list
+ *
+ * @return EOK		If the mode is set up
+ * @return ENOTSUP	If this mode is not supported
+ */
+typedef int (*unicast_mode_change_handler)(nic_t *,
+	nic_unicast_mode_t, const nic_address_t *, size_t);
+/**
+ * Handler for multicast filtering mode change.
+ *
+ * @param nic_data		NICF main structure
+ * @param new_mode		The mode that should be set up
+ * @param address_list	Addresses as argument to the mode
+ * @param address_count	Number of addresses in the list
+ *
+ * @return EOK		If the mode is set up
+ * @return ENOTSUP	If this mode is not supported
+ */
+typedef int (*multicast_mode_change_handler)(nic_t *,
+	nic_multicast_mode_t, const nic_address_t *, size_t);
+/**
+ * Handler for broadcast filtering mode change.
+ *
+ * @param nic_data	NICF main structure
+ * @param new_mode	The mode that should be set up
+ *
+ * @return EOK		If the mode is set up
+ * @return ENOTSUP	If this mode is not supported
+ */
+typedef int (*broadcast_mode_change_handler)(nic_t *, nic_broadcast_mode_t);
+/**
+ * Handler for blocked sources list change.
+ *
+ * @param nic_data		NICF main structure
+ * @param address_list	Addresses as argument to the mode
+ * @param address_count	Number of addresses in the list
+ */
+typedef void (*blocked_sources_change_handler)(nic_t *,
+	const nic_address_t *, size_t);
+/**
+ * Handler for VLAN filtering mask change.
+ * @param nic_data		NICF main structure
+ * @param vlan_mask		The new mask | NULL for disabling vlan filter
+ */
+typedef void (*vlan_mask_change_handler)(nic_t *, const nic_vlan_mask_t *);
+/**
+ * Handler called when a WOL virtue is added.
+ * If the maximum of accepted WOL virtues changes due to adding this virtue
+ * you should update the vector wol_virtues.caps_max.
+ * The driver is allowed to store pointer to the virtue data until
+ * on_wol_virtue_remove on these data is called (although probably this is
+ * not a good practice).
+ *
+ * @param nic_data	NICF main structure
+ * @param virtue	Structure with virtue description
+ *
+ * @return EOK		If the filter can be used. Software emulation of the
+ * 					filter is activated unless the emulate is set to 0.
+ * @return ENOTSUP	If this filter cannot work on this NIC (e.g. the NIC
+ * 					cannot run in promiscuous node or the limit of WOL
+ * 					packets' specifications was reached).
+ * @return ELIMIT	If this filter must implemented in HW but currently the
+ * 					limit of these HW filters was reached.
+ */
+typedef int (*wol_virtue_add_handler)(nic_t *, const nic_wol_virtue_t *);
+/**
+ * Handler called when a WOL virtue is removed.
+ * If the maximum of accepted WOL virtues changes due to removing this
+ * virtue you should update the vector wol_virtues.caps_max.
+ *
+ * @param nic_data	NICF main structure
+ * @param virtue		Structure with virtue description
+ */
+typedef void (*wol_virtue_remove_handler)(nic_t *, const nic_wol_virtue_t *);
+/**
+ * Handler for poll mode change.
+ *
+ * @param nic_data	NICF main structure
+ * @param mode		Mode to be set up
+ * @param period	New period of polling (with NIC_POLL_PERIODIC)
+ *
+ * @return EOK		If the mode was fully setup
+ * @return ENOTSUP	If NICF should do the periodic polling
+ * @return EINVAL	If this mode cannot be set up under no circumstances
+ */
+typedef int (*poll_mode_change_handler)(nic_t *,
+	nic_poll_mode_t, const struct timeval *);
+/**
+ * Event handler called when the NIC should poll its buffers for a new frame
+ * (in NIC_POLL_PERIODIC or NIC_POLL_ON_DEMAND) modes.
+ *
+ * @param nic_data	NICF main structure
+ */
+typedef void (*poll_request_handler)(nic_t *);
+
+/* nic_t allocation and deallocation */
+extern nic_t *nic_create_and_bind(ddf_dev_t *);
+extern void nic_unbind_and_destroy(ddf_dev_t *);
+
+/* Functions called in the main function */
+extern int nic_driver_init(const char *);
+extern void nic_driver_implement(driver_ops_t *, ddf_dev_ops_t *,
+	nic_iface_t *);
+
+/* Functions called in add_device */
+extern int nic_connect_to_services(nic_t *);
+extern int nic_register_as_ddf_fun(nic_t *, ddf_dev_ops_t *);
+extern int nic_get_resources(nic_t *, hw_res_list_parsed_t *);
+extern void nic_set_specific(nic_t *, void *);
+extern void nic_set_write_packet_handler(nic_t *, write_packet_handler);
+extern void nic_set_state_change_handlers(nic_t *,
+	state_change_handler, state_change_handler, state_change_handler);
+extern void nic_set_filtering_change_handlers(nic_t *,
+	unicast_mode_change_handler, multicast_mode_change_handler,
+	broadcast_mode_change_handler, blocked_sources_change_handler,
+	vlan_mask_change_handler);
+extern void nic_set_wol_virtue_change_handlers(nic_t *,
+	wol_virtue_add_handler, wol_virtue_remove_handler);
+extern void nic_set_poll_handlers(nic_t *,
+	poll_mode_change_handler, poll_request_handler);
+
+/* Functions called in device_added */
+extern int nic_ready(nic_t *);
+
+/* General driver functions */
+extern ddf_dev_t *nic_get_ddf_dev(nic_t *);
+extern ddf_fun_t *nic_get_ddf_fun(nic_t *);
+extern nic_t *nic_get_from_ddf_dev(ddf_dev_t *);
+extern nic_t *nic_get_from_ddf_fun(ddf_fun_t *);
+extern void *nic_get_specific(nic_t *);
+extern nic_device_state_t nic_query_state(nic_t *);
+extern void nic_set_tx_busy(nic_t *, int);
+extern int nic_report_address(nic_t *, const nic_address_t *);
+extern int nic_report_poll_mode(nic_t *, nic_poll_mode_t, struct timeval *);
+extern void nic_query_address(nic_t *, nic_address_t *);
+extern void nic_received_packet(nic_t *, packet_t *);
+extern void nic_received_noneth_packet(nic_t *, packet_t *);
+extern void nic_received_frame(nic_t *, nic_frame_t *);
+extern void nic_received_frame_list(nic_t *, nic_frame_list_t *);
+extern void nic_disable_interrupt(nic_t *, int);
+extern void nic_enable_interrupt(nic_t *, int);
+extern nic_poll_mode_t nic_query_poll_mode(nic_t *, struct timeval *);
+
+/* Statistics updates */
+extern void nic_report_send_ok(nic_t *, size_t, size_t);
+extern void nic_report_send_error(nic_t *, nic_send_error_cause_t, unsigned);
+extern void nic_report_receive_error(nic_t *, nic_receive_error_cause_t,
+    unsigned);
+extern void nic_report_collisions(nic_t *, unsigned);
+
+/* Packet / frame / frame list allocation and deallocation */
+extern packet_t *nic_alloc_packet(nic_t *, size_t);
+extern void nic_release_packet(nic_t *, packet_t *);
+extern nic_frame_t *nic_alloc_frame(nic_t *, size_t);
+extern nic_frame_list_t *nic_alloc_frame_list(void);
+extern void nic_frame_list_append(nic_frame_list_t *, nic_frame_t *);
+extern void nic_release_frame(nic_t *, nic_frame_t *);
+
+/* RXC query and report functions */
+extern void nic_report_hw_filtering(nic_t *, int, int, int);
+extern void nic_query_unicast(const nic_t *,
+	nic_unicast_mode_t *, size_t, nic_address_t *, size_t *);
+extern void nic_query_multicast(const nic_t *,
+	nic_multicast_mode_t *, size_t, nic_address_t *, size_t *);
+extern void nic_query_broadcast(const nic_t *, nic_broadcast_mode_t *);
+extern void nic_query_blocked_sources(const nic_t *,
+	size_t, nic_address_t *, size_t *);
+extern int nic_query_vlan_mask(const nic_t *, nic_vlan_mask_t *);
+extern int nic_query_wol_max_caps(const nic_t *, nic_wv_type_t);
+extern void nic_set_wol_max_caps(nic_t *, nic_wv_type_t, int);
+extern uint64_t nic_mcast_hash(const nic_address_t *, size_t);
+extern uint64_t nic_query_mcast_hash(nic_t *);
+
+/* Software period functions */
+extern void nic_sw_period_start(nic_t *);
+extern void nic_sw_period_stop(nic_t *);
+
+/* Packet DMA lock */
+extern void * nic_dma_lock_packet(packet_t * packet);
+extern void nic_dma_unlock_packet(packet_t * packet);
+
+#endif // __NIC_H__
+
+/** @}
+ */
Index: uspace/lib/nic/include/nic_addr_db.h
===================================================================
--- uspace/lib/nic/include/nic_addr_db.h	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
+++ uspace/lib/nic/include/nic_addr_db.h	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2011 Radim Vansa
+ * 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 libnic
+ * @{
+ */
+/**
+ * @file
+ * @brief Generic hash-set based database of addresses
+ */
+
+#ifndef __NIC_ADDR_DB_H__
+#define __NIC_ADDR_DB_H__
+
+#ifndef LIBNIC_INTERNAL
+#error "This is internal libnic header, please don't include it"
+#endif
+
+#include <adt/hash_set.h>
+
+/**
+ * Initial size of DB's hash set
+ */
+#define NIC_ADDR_DB_INIT_SIZE 	8
+/**
+ * Maximal length of addresses in the DB (in bytes).
+ */
+#define NIC_ADDR_MAX_LENGTH		16
+
+/**
+ * Fibril-safe database of addresses implemented using hash set.
+ */
+typedef struct nic_addr_db {
+	hash_set_t set;
+	size_t addr_len;
+} nic_addr_db_t;
+
+/**
+ * Helper structure for keeping the address in the hash set.
+ */
+typedef struct nic_addr_entry {
+	link_t item;
+	size_t addr_len;
+	uint8_t addr[NIC_ADDR_MAX_LENGTH];
+} nic_addr_entry_t;
+
+extern int nic_addr_db_init(nic_addr_db_t *db, size_t addr_len);
+extern void nic_addr_db_clear(nic_addr_db_t *db);
+extern void nic_addr_db_destroy(nic_addr_db_t *db);
+extern size_t nic_addr_db_count(const nic_addr_db_t *db);
+extern int nic_addr_db_insert(nic_addr_db_t *db, const uint8_t *addr);
+extern int nic_addr_db_remove(nic_addr_db_t *db, const uint8_t *addr);
+extern void nic_addr_db_remove_selected(nic_addr_db_t *db,
+	int (*func)(const uint8_t *, void *), void *arg);
+extern int nic_addr_db_contains(const nic_addr_db_t *db, const uint8_t *addr);
+extern void nic_addr_db_foreach(const nic_addr_db_t *db,
+	void (*func)(const uint8_t *, void *), void *arg);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/nic/include/nic_driver.h
===================================================================
--- uspace/lib/nic/include/nic_driver.h	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
+++ uspace/lib/nic/include/nic_driver.h	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2011 Radim Vansa
+ * 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 libnic
+ * @{
+ */
+/**
+ * @file
+ * @brief Internal NICF structures
+ */
+
+#ifndef __NIC_DRIVER_H__
+#define __NIC_DRIVER_H__
+
+#ifndef LIBNIC_INTERNAL
+#error "This is internal libnic's header, please do not include it"
+#endif
+
+#include <fibril_synch.h>
+#include <net/device.h>
+#include <async.h>
+
+#include "nic.h"
+#include "nic_rx_control.h"
+#include "nic_wol_virtues.h"
+
+#define DEVICE_CATEGORY_NIC "nic"
+
+struct sw_poll_info {
+	fid_t fibril;
+	volatile int run;
+	volatile int running;
+};
+
+struct nic {
+	/**
+	 * Device from device manager's point of view.
+	 * The value must be set within the add_device handler
+	 * (in nic_create_and_bind) and must not be changed.
+	 */
+	ddf_dev_t *dev;
+	/**
+	 * Device's NIC function.
+	 * The value must be set within the add_device handler
+	 * (in nic_driver_register_as_ddf_function) and must not be changed.
+	 */
+	ddf_fun_t *fun;
+	/** Identifier for higher network stack layers */
+	nic_device_id_t device_id;
+	/** Current state of the device */
+	nic_device_state_t state;
+	/** Transmiter is busy - messages are dropped */
+	int tx_busy;
+	/** Device's MAC address */
+	nic_address_t mac;
+	/** Device's default MAC address (assigned the first time, used in STOP) */
+	nic_address_t default_mac;
+	/** Session to SERVICE_NETWORKING */
+	async_sess_t *net_session;
+	/** Session to SERVICE_ETHERNET or SERVICE_NILDUMMY */
+	async_sess_t *nil_session;
+	/** Phone to APIC or i8259 */
+	async_sess_t *irc_session;
+	/** Current polling mode of the NIC */
+	nic_poll_mode_t poll_mode;
+	/** Polling period (applicable when poll_mode == NIC_POLL_PERIODIC) */
+	struct timeval poll_period;
+	/** Current polling mode of the NIC */
+	nic_poll_mode_t default_poll_mode;
+	/** Polling period (applicable when default_poll_mode == NIC_POLL_PERIODIC) */
+	struct timeval default_poll_period;
+	/** Software period fibrill information */
+	struct sw_poll_info sw_poll_info;
+	/**
+	 * Lock on everything but statistics, rx control and wol virtues. This lock
+	 * cannot be used if filters_lock or stats_lock is already held - you must
+	 * acquire main_lock first (otherwise deadlock could happen).
+	 */
+	fibril_rwlock_t main_lock;
+	/** Device statistics */
+	nic_device_stats_t stats;
+	/**
+	 * Lock for statistics. You must not hold any other lock from nic_t except
+	 * the main_lock at the same moment. If both this lock and main_lock should
+	 * be locked, the main_lock must be locked as the first.
+	 */
+	fibril_rwlock_t stats_lock;
+	/** Receive control configuration */
+	nic_rxc_t rx_control;
+	/**
+	 * Lock for receive control. You must not hold any other lock from nic_t
+	 * except the main_lock at the same moment. If both this lock and main_lock
+	 * should be locked, the main_lock must be locked as the first.
+	 */
+	fibril_rwlock_t rxc_lock;
+	/** WOL virtues configuration */
+	nic_wol_virtues_t wol_virtues;
+	/**
+	 * Lock for WOL virtues. You must not hold any other lock from nic_t
+	 * except the main_lock at the same moment. If both this lock and main_lock
+	 * should be locked, the main_lock must be locked as the first.
+	 */
+	fibril_rwlock_t wv_lock;
+	/**
+	 * Function really sending the data. This MUST be filled in if the 
+	 * nic_send_message_impl function is used for sending messages (filled 
+	 * as send_message member of the nic_iface_t structure).
+	 * Called with the main_lock locked for reading.
+	 */
+	write_packet_handler write_packet;
+	/**
+	 * Event handler called when device goes to the ACTIVE state.
+	 * The implementation is optional.
+	 * Called with the main_lock locked for writing.
+	 */
+	state_change_handler on_activating;
+	/**
+	 * Event handler called when device goes to the DOWN state.
+	 * The implementation is optional.
+	 * Called with the main_lock locked for writing.
+	 */
+	state_change_handler on_going_down;
+	/**
+	 * Event handler called when device goes to the STOPPED state.
+	 * The implementation is optional.
+	 * Called with the main_lock locked for writing.
+	 */
+	state_change_handler on_stopping;
+	/**
+	 * Event handler called when the unicast receive mode is changed.
+	 * The implementation is optional. Called with rxc_lock locked for writing.
+	 */
+	unicast_mode_change_handler on_unicast_mode_change;
+	/**
+	 * Event handler called when the multicast receive mode is changed.
+	 * The implementation is optional. Called with rxc_lock locked for writing.
+	 */
+	multicast_mode_change_handler on_multicast_mode_change;
+	/**
+	 * Event handler called when the broadcast receive mode is changed.
+	 * The implementation is optional. Called with rxc_lock locked for writing.
+	 */
+	broadcast_mode_change_handler on_broadcast_mode_change;
+	/**
+	 * Event handler called when the blocked sources set is changed.
+	 * The implementation is optional. Called with rxc_lock locked for writing.
+	 */
+	blocked_sources_change_handler on_blocked_sources_change;
+	/**
+	 * Event handler called when the VLAN mask is changed.
+	 * The implementation is optional. Called with rxc_lock locked for writing.
+	 */
+	vlan_mask_change_handler on_vlan_mask_change;
+	/**
+	 * Event handler called when a new WOL virtue is added.
+	 * The implementation is optional.
+	 * Called with filters_lock locked for writing.
+	 */
+	wol_virtue_add_handler on_wol_virtue_add;
+	/**
+	 * Event handler called when a WOL virtue is removed.
+	 * The implementation is optional.
+	 * Called with filters_lock locked for writing.
+	 */
+	wol_virtue_remove_handler on_wol_virtue_remove;
+	/**
+	 * Event handler called when the polling mode is changed.
+	 * The implementation is optional.
+	 * Called with main_lock locked for writing.
+	 */
+	poll_mode_change_handler on_poll_mode_change;
+	/**
+	 * Event handler called when the NIC should poll its buffers for a new frame
+	 * (in NIC_POLL_PERIODIC or NIC_POLL_ON_DEMAND) modes.
+	 * Called with the main_lock locked for reading.
+	 * The implementation is optional.
+	 */
+	poll_request_handler on_poll_request;
+	/** Data specific for particular driver */
+	void *specific;
+};
+
+/**
+ * Structure keeping global data
+ */
+typedef struct nic_globals {
+	list_t frame_list_cache;
+	size_t frame_list_cache_size;
+	list_t frame_cache;
+	size_t frame_cache_size;
+	fibril_mutex_t lock;
+} nic_globals_t;
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/nic/include/nic_impl.h
===================================================================
--- uspace/lib/nic/include/nic_impl.h	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
+++ uspace/lib/nic/include/nic_impl.h	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2011 Radim Vansa
+ * 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 libnic
+ * @{
+ */
+/**
+ * @file
+ * @brief Prototypes of default DDF NIC interface methods implementations
+ */
+
+#ifndef NIC_IMPL_H__
+#define NIC_IMPL_H__
+
+#include <assert.h>
+#include <net/device.h>
+#include <ddf/driver.h>
+#include <nil_remote.h>
+
+/* Inclusion of this file is not prohibited, because drivers could want to
+ * inject some adaptation layer between the DDF call and NICF implementation */
+
+extern int nic_get_address_impl(ddf_fun_t *dev_fun, nic_address_t *address);
+extern int nic_send_message_impl(ddf_fun_t *dev_fun, packet_id_t packet_id);
+extern int nic_connect_to_nil_impl(ddf_fun_t *dev_fun, services_t nil_service,
+	int device_id);
+extern int nic_get_state_impl(ddf_fun_t *dev_fun, nic_device_state_t *state);
+extern int nic_set_state_impl(ddf_fun_t *dev_fun, nic_device_state_t state);
+extern int nic_get_stats_impl(ddf_fun_t *dev_fun, nic_device_stats_t *stats);
+extern int nic_unicast_get_mode_impl(ddf_fun_t *dev_fun,
+	nic_unicast_mode_t *, size_t, nic_address_t *, size_t *);
+extern int nic_unicast_set_mode_impl(ddf_fun_t *dev_fun,
+	nic_unicast_mode_t, const nic_address_t *, size_t);
+extern int nic_multicast_get_mode_impl(ddf_fun_t *dev_fun,
+	nic_multicast_mode_t *, size_t, nic_address_t *, size_t *);
+extern int nic_multicast_set_mode_impl(ddf_fun_t *dev_fun,
+	nic_multicast_mode_t, const nic_address_t *, size_t);
+extern int nic_broadcast_get_mode_impl(ddf_fun_t *, nic_broadcast_mode_t *);
+extern int nic_broadcast_set_mode_impl(ddf_fun_t *, nic_broadcast_mode_t);
+extern int nic_blocked_sources_get_impl(ddf_fun_t *,
+	size_t, nic_address_t *, size_t *);
+extern int nic_blocked_sources_set_impl(ddf_fun_t *, const nic_address_t *, size_t);
+extern int nic_vlan_get_mask_impl(ddf_fun_t *, nic_vlan_mask_t *);
+extern int nic_vlan_set_mask_impl(ddf_fun_t *, const nic_vlan_mask_t *);
+extern int nic_wol_virtue_add_impl(ddf_fun_t *dev_fun, nic_wv_type_t type,
+	const void *data, size_t length, nic_wv_id_t *new_id);
+extern int nic_wol_virtue_remove_impl(ddf_fun_t *dev_fun, nic_wv_id_t id);
+extern int nic_wol_virtue_probe_impl(ddf_fun_t *dev_fun, nic_wv_id_t id,
+	nic_wv_type_t *type, size_t max_length, void *data, size_t *length);
+extern int nic_wol_virtue_list_impl(ddf_fun_t *dev_fun, nic_wv_type_t type,
+	size_t max_count, nic_wv_id_t *id_list, size_t *id_count);
+extern int nic_wol_virtue_get_caps_impl(ddf_fun_t *, nic_wv_type_t, int *);
+extern int nic_poll_get_mode_impl(ddf_fun_t *,
+	nic_poll_mode_t *, struct timeval *);
+extern int nic_poll_set_mode_impl(ddf_fun_t *,
+	nic_poll_mode_t, const struct timeval *);
+extern int nic_poll_now_impl(ddf_fun_t *);
+
+extern void nic_default_handler_impl(ddf_fun_t *dev_fun,
+	ipc_callid_t callid, ipc_call_t *call);
+extern int nic_open_impl(ddf_fun_t *fun);
+extern void nic_close_impl(ddf_fun_t *fun);
+
+extern void nic_device_added_impl(ddf_dev_t *dev);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/nic/include/nic_rx_control.h
===================================================================
--- uspace/lib/nic/include/nic_rx_control.h	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
+++ uspace/lib/nic/include/nic_rx_control.h	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2011 Radim Vansa
+ * 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 libnic
+ * @{
+ */
+/**
+ * @file
+ * @brief Incoming packets (frames) filtering control structures
+ */
+
+#ifndef __NIC_FILTERS_H__
+#define __NIC_FILTERS_H__
+
+#ifndef LIBNIC_INTERNAL
+#error "This is internal libnic's header, please do not include it"
+#endif
+
+#include <adt/hash_table.h>
+#include <fibril_synch.h>
+#include <net/device.h>
+#include <net/packet_header.h>
+
+#include "nic_addr_db.h"
+
+/**
+ * General structure describing receive control.
+ * The structure is not synchronized inside, the nic_driver should provide
+ * a synchronized facade.
+ */
+typedef struct nic_rxc {
+	/**
+	 * Allowed unicast destination MAC addresses
+	 */
+	nic_addr_db_t unicast_addrs;
+	/**
+	 * Allowed unicast destination MAC addresses
+	 */
+	nic_addr_db_t multicast_addrs;
+	/**
+	 * Single flag if any source is blocked
+	 */
+	int block_sources;
+	/**
+	 * Blocked source MAC addresses
+	 */
+	nic_addr_db_t blocked_sources;
+	/**
+	 * Selected mode for unicast frames
+	 */
+	nic_unicast_mode_t unicast_mode;
+	/**
+	 * Selected mode for multicast frames
+	 */
+	nic_multicast_mode_t multicast_mode;
+	/**
+	 * Selected mode for broadcast frames
+	 */
+	nic_broadcast_mode_t broadcast_mode;
+	/**
+	 * Mask for VLAN tags. This vector must be at least 512 bytes long.
+	 */
+	nic_vlan_mask_t *vlan_mask;
+	/**
+	 * If true, the NIC is receiving only unicast frames which we really want to
+	 * receive (the filtering is perfect).
+	 */
+	int unicast_exact;
+	/**
+	 * If true, the NIC is receiving only multicast frames which we really want
+	 * to receive (the filtering is perfect).
+	 */
+	int multicast_exact;
+	/**
+	 * If true, the NIC is receiving only frames with VLAN tags which we really
+	 * want to receive (the filtering is perfect).
+	 */
+	int vlan_exact;
+} nic_rxc_t;
+
+#define VLAN_TPID_UPPER 0x81
+#define VLAN_TPID_LOWER 0x00
+
+typedef struct vlan_header {
+	uint8_t tpid_upper;
+	uint8_t tpid_lower;
+	uint8_t vid_upper;
+	uint8_t vid_lower;
+} __attribute__ ((packed)) vlan_header_t;
+
+extern int nic_rxc_init(nic_rxc_t *rxc);
+extern int nic_rxc_clear(nic_rxc_t *rxc);
+extern int nic_rxc_set_addr(nic_rxc_t *rxc,
+	const nic_address_t *prev_addr, const nic_address_t *curr_addr);
+extern int nic_rxc_check(const nic_rxc_t *rxc,
+	const packet_t *packet, nic_frame_type_t *frame_type);
+extern void nic_rxc_hw_filtering(nic_rxc_t *rxc,
+	int unicast_exact, int multicast_exact, int vlan_exact);
+extern uint64_t nic_rxc_mcast_hash(const nic_address_t *list, size_t count);
+extern uint64_t nic_rxc_multicast_get_hash(const nic_rxc_t *rxc);
+extern void nic_rxc_unicast_get_mode(const nic_rxc_t *, nic_unicast_mode_t *,
+	size_t max_count, nic_address_t *address_list, size_t *address_count);
+extern int nic_rxc_unicast_set_mode(nic_rxc_t *rxc, nic_unicast_mode_t mode,
+	const nic_address_t *address_list, size_t address_count);
+extern void nic_rxc_multicast_get_mode(const nic_rxc_t *,
+	nic_multicast_mode_t *, size_t, nic_address_t *, size_t *);
+extern int nic_rxc_multicast_set_mode(nic_rxc_t *, nic_multicast_mode_t mode,
+	const nic_address_t *address_list, size_t address_count);
+extern void nic_rxc_broadcast_get_mode(const nic_rxc_t *,
+	nic_broadcast_mode_t *mode);
+extern int nic_rxc_broadcast_set_mode(nic_rxc_t *,
+	nic_broadcast_mode_t mode);
+extern void nic_rxc_blocked_sources_get(const nic_rxc_t *,
+	size_t max_count, nic_address_t *address_list, size_t *address_count);
+extern int nic_rxc_blocked_sources_set(nic_rxc_t *,
+	const nic_address_t *address_list, size_t address_count);
+extern int nic_rxc_vlan_get_mask(const nic_rxc_t *rxc, nic_vlan_mask_t *mask);
+extern int nic_rxc_vlan_set_mask(nic_rxc_t *rxc, const nic_vlan_mask_t *mask);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/nic/include/nic_wol_virtues.h
===================================================================
--- uspace/lib/nic/include/nic_wol_virtues.h	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
+++ uspace/lib/nic/include/nic_wol_virtues.h	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2011 Radim Vansa
+ * 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 libnic
+ * @{
+ */
+/**
+ * @file
+ * @brief Wake-on-LAN support
+ */
+
+#ifndef __NIC_WOL_VIRTUES_H__
+#define __NIC_WOL_VIRTUES_H__
+
+#ifndef LIBNIC_INTERNAL
+#error "This is internal libnic's header, please do not include it"
+#endif
+
+#include <net/device.h>
+#include <adt/hash_table.h>
+#include "nic.h"
+
+typedef struct nic_wol_virtues {
+	/**
+	 * Operations for table
+	 */
+	hash_table_operations_t table_operations;
+	/**
+	 * WOL virtues hashed by their ID's.
+	 */
+	hash_table_t table;
+	/**
+	 * WOL virtues in lists by their type
+	 */
+	nic_wol_virtue_t *lists[NIC_WV_MAX];
+	/**
+	 * Number of virtues in the wv_types list
+	 */
+	size_t lists_sizes[NIC_WV_MAX];
+	/**
+	 * Counter for the ID's
+	 */
+	nic_wv_id_t next_id;
+	/**
+	 * Maximum capabilities
+	 */
+	int caps_max[NIC_WV_MAX];
+} nic_wol_virtues_t;
+
+extern int nic_wol_virtues_init(nic_wol_virtues_t *);
+extern void nic_wol_virtues_clear(nic_wol_virtues_t *);
+extern int nic_wol_virtues_verify(nic_wv_type_t, const void *, size_t);
+extern int nic_wol_virtues_list(const nic_wol_virtues_t *, nic_wv_type_t type,
+	size_t max_count, nic_wv_id_t *id_list, size_t *id_count);
+extern int nic_wol_virtues_add(nic_wol_virtues_t *, nic_wol_virtue_t *);
+extern nic_wol_virtue_t *nic_wol_virtues_remove(nic_wol_virtues_t *,
+	nic_wv_id_t);
+extern const nic_wol_virtue_t *nic_wol_virtues_find(const nic_wol_virtues_t *,
+	nic_wv_id_t);
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/nic/src/nic_addr_db.c
===================================================================
--- uspace/lib/nic/src/nic_addr_db.c	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
+++ uspace/lib/nic/src/nic_addr_db.c	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2011 Radim Vansa
+ * 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 libnic
+ * @{
+ */
+/**
+ * @file
+ * @brief Generic hash-set based database of addresses
+ */
+#include <assert.h>
+#include <stdlib.h>
+#include <bool.h>
+#include <errno.h>
+#include <mem.h>
+
+#include "nic_addr_db.h"
+
+/**
+ * Hash set helper function
+ */
+static int nic_addr_equals(const link_t *item1, const link_t *item2)
+{
+	assert(item1 && item2);
+	size_t addr_len = ((const nic_addr_entry_t *) item1)->addr_len;
+
+	assert(addr_len	== ((const nic_addr_entry_t *) item2)->addr_len);
+
+	size_t i;
+	for (i = 0; i < addr_len; ++i) {
+		if (((nic_addr_entry_t *) item1)->addr[i] !=
+			((nic_addr_entry_t *) item2)->addr[i])
+			return false;
+	}
+	return true;
+}
+
+/**
+ * Hash set helper function
+ */
+static unsigned long nic_addr_hash(const link_t *item)
+{
+	assert(item);
+	const nic_addr_entry_t *entry = (const nic_addr_entry_t *) item;
+	unsigned long hash = 0;
+
+	size_t i;
+	for (i = 0; i < entry->addr_len; ++i) {
+		hash = (hash << 8) ^ (hash >> 24) ^ entry->addr[i];
+	}
+	return hash;
+}
+
+/**
+ * Helper wrapper
+ */
+static void nic_addr_destroy(link_t *item, void *unused)
+{
+	free(item);
+}
+
+/**
+ * Initialize the database
+ *
+ * @param[in,out]	db			Uninitialized storage
+ * @param[in]		addr_len	Size of addresses in the db
+ *
+ * @return EOK		If successfully initialized
+ * @return EINVAL	If the address length is too big
+ * @return ENOMEM	If there was not enough memory to initialize the storage
+ */
+int nic_addr_db_init(nic_addr_db_t *db, size_t addr_len)
+{
+	assert(db);
+	if (addr_len > NIC_ADDR_MAX_LENGTH) {
+		return EINVAL;
+	}
+	if (!hash_set_init(&db->set, nic_addr_hash, nic_addr_equals,
+		NIC_ADDR_DB_INIT_SIZE)) {
+		return ENOMEM;
+	}
+	db->addr_len = addr_len;
+	return EOK;
+}
+
+/**
+ * Remove all records from the DB
+ *
+ * @param db
+ */
+void nic_addr_db_clear(nic_addr_db_t *db)
+{
+	assert(db);
+	hash_set_clear(&db->set, nic_addr_destroy, NULL);
+}
+
+/**
+ * Free the memory used by db, including all records...
+ *
+ * @param	db
+ */
+void nic_addr_db_destroy(nic_addr_db_t *db)
+{
+	assert(db);
+	hash_set_apply(&db->set, nic_addr_destroy, NULL);
+	hash_set_destroy(&db->set);
+}
+
+/**
+ * Get number of addresses in the db
+ *
+ * @param	db
+ *
+ * @return Number of adresses
+ */
+size_t nic_addr_db_count(const nic_addr_db_t *db)
+{
+	assert(db);
+	return hash_set_count(&db->set);
+}
+
+/**
+ * Insert an address to the db
+ *
+ * @param	db
+ * @param	addr 	Inserted address. Length is implicitly concluded from the
+ * 					db's address length.
+ *
+ * @return EOK		If the address was inserted
+ * @return ENOMEM	If there was not enough memory
+ * @return EEXIST	If this adress already is in the db
+ */
+int nic_addr_db_insert(nic_addr_db_t *db, const uint8_t *addr)
+{
+	assert(db && addr);
+	nic_addr_entry_t *entry = malloc(sizeof (nic_addr_entry_t));
+	if (entry == NULL) {
+		return ENOMEM;
+	}
+	entry->addr_len = db->addr_len;
+	memcpy(entry->addr, addr, db->addr_len);
+
+	return hash_set_insert(&db->set, &entry->item) ? EOK : EEXIST;
+}
+
+/**
+ * Remove the address from the db
+ *
+ * @param	db
+ * @param	addr	Removed address.
+ *
+ * @return EOK		If the address was removed
+ * @return ENOENT	If there is no address
+ */
+int nic_addr_db_remove(nic_addr_db_t *db, const uint8_t *addr)
+{
+	assert(db && addr);
+	nic_addr_entry_t entry;
+	entry.addr_len = db->addr_len;
+	memcpy(entry.addr, addr, db->addr_len);
+
+	link_t *removed = hash_set_remove(&db->set, &entry.item);
+	free(removed);
+	return removed != NULL ? EOK : ENOENT;
+}
+
+/**
+ * Test if the address is contained in the db
+ *
+ * @param	db
+ * @param	addr	Tested addresss
+ *
+ * @return true if the address is in the db, false otherwise
+ */
+int nic_addr_db_contains(const nic_addr_db_t *db, const uint8_t *addr)
+{
+	assert(db && addr);
+	nic_addr_entry_t entry;
+	entry.addr_len = db->addr_len;
+	memcpy(entry.addr, addr, db->addr_len);
+
+	return hash_set_contains(&db->set, &entry.item);
+}
+
+/**
+ * Helper structure for nic_addr_db_foreach
+ */
+typedef struct {
+	void (*func)(const uint8_t *, void *);
+	void *arg;
+} nic_addr_db_fe_arg_t;
+
+/**
+ * Helper function for nic_addr_db_foreach
+ */
+static void nic_addr_db_fe_helper(link_t *item, void *arg) {
+	nic_addr_db_fe_arg_t *hs = (nic_addr_db_fe_arg_t *) arg;
+	hs->func(((nic_addr_entry_t *) item)->addr, hs->arg);
+}
+
+/**
+ * Executes a user-defined function on all addresses in the DB. The function
+ * must not change the addresses.
+ *
+ * @param	db
+ * @param	func	User-defined function
+ * @param	arg		Custom argument passed to the function
+ */
+void nic_addr_db_foreach(const nic_addr_db_t *db,
+	void (*func)(const uint8_t *, void *), void *arg)
+{
+	nic_addr_db_fe_arg_t hs = { .func = func, .arg = arg };
+	hash_set_apply((hash_set_t *) &db->set, nic_addr_db_fe_helper, &hs);
+}
+
+/**
+ * Helper structure for nic_addr_db_remove_selected
+ */
+typedef struct {
+	int (*func)(const uint8_t *, void *);
+	void *arg;
+} nic_addr_db_rs_arg_t;
+
+/**
+ * Helper function for nic_addr_db_foreach
+ */
+static int nic_addr_db_rs_helper(link_t *item, void *arg) {
+	nic_addr_db_rs_arg_t *hs = (nic_addr_db_rs_arg_t *) arg;
+	int retval = hs->func(((nic_addr_entry_t *) item)->addr, hs->arg);
+	if (retval) {
+		free(item);
+	}
+	return retval;
+}
+
+/**
+ * Removes all addresses for which the function returns non-zero.
+ *
+ * @param	db
+ * @param	func	User-defined function
+ * @param	arg		Custom argument passed to the function
+ */
+void nic_addr_db_remove_selected(nic_addr_db_t *db,
+	int (*func)(const uint8_t *, void *), void *arg)
+{
+	nic_addr_db_rs_arg_t hs = { .func = func, .arg = arg };
+	hash_set_remove_selected(&db->set, nic_addr_db_rs_helper, &hs);
+}
+
+/** @}
+ */
Index: uspace/lib/nic/src/nic_driver.c
===================================================================
--- uspace/lib/nic/src/nic_driver.c	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
+++ uspace/lib/nic/src/nic_driver.c	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -0,0 +1,1368 @@
+/*
+ * Copyright (c) 2011 Radim Vansa
+ * Copyright (c) 2011 Jiri Michalec
+ * 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 libnic
+ * @{
+ */
+/**
+ * @file
+ * @brief Internal implementation of general NIC operations
+ */
+
+#include <assert.h>
+#include <fibril_synch.h>
+#include <ns.h>
+#include <stdio.h>
+#include <str_error.h>
+#include <ipc/services.h>
+#include <ipc/ns.h>
+#include <ipc/irc.h>
+#include <sysinfo.h>
+
+#include <devman.h>
+#include <ddf/interrupt.h>
+#include <net_interface.h>
+#include <ops/nic.h>
+#include <packet_client.h>
+#include <packet_remote.h>
+#include <net/packet_header.h>
+#include <errno.h>
+
+#include "nic_driver.h"
+#include "nic_impl.h"
+
+#define NIC_GLOBALS_MAX_CACHE_SIZE 16
+
+nic_globals_t nic_globals;
+
+/**
+ * Initializes libraries required for NIC framework - logger, packet manager
+ *
+ * @param name	Name of the device/driver (used in logging)
+ */
+int nic_driver_init(const char *name)
+{
+	list_initialize(&nic_globals.frame_list_cache);
+	nic_globals.frame_list_cache_size = 0;
+	list_initialize(&nic_globals.frame_cache);
+	nic_globals.frame_cache_size = 0;
+	fibril_mutex_initialize(&nic_globals.lock);
+	
+	char buffer[256];
+	snprintf(buffer, 256, "drv/" DEVICE_CATEGORY_NIC "/%s", name);
+	
+	/* Initialize packet manager */
+	return pm_init();
+}
+
+/**
+ * Fill in the default implementations for device options and NIC interface.
+ *
+ * @param driver_ops
+ * @param dev_ops
+ * @param iface
+ */
+void nic_driver_implement(driver_ops_t *driver_ops, ddf_dev_ops_t *dev_ops,
+    nic_iface_t *iface)
+{
+	if (driver_ops) {
+		if (!driver_ops->device_added)
+			driver_ops->device_added = nic_device_added_impl;
+	}
+
+	if (dev_ops) {
+		if (!dev_ops->open)
+			dev_ops->open = nic_open_impl;
+		if (!dev_ops->close)
+			dev_ops->close = nic_close_impl;
+		if (!dev_ops->interfaces[NIC_DEV_IFACE])
+			dev_ops->interfaces[NIC_DEV_IFACE] = iface;
+		if (!dev_ops->default_handler)
+			dev_ops->default_handler = nic_default_handler_impl;
+	}
+
+	if (iface) {
+		if (!iface->get_state)
+			iface->get_state = nic_get_state_impl;
+		if (!iface->set_state)
+			iface->set_state = nic_set_state_impl;
+		if (!iface->send_message)
+			iface->send_message = nic_send_message_impl;
+		if (!iface->connect_to_nil)
+			iface->connect_to_nil = nic_connect_to_nil_impl;
+		if (!iface->get_address)
+			iface->get_address = nic_get_address_impl;
+		if (!iface->get_stats)
+			iface->get_stats = nic_get_stats_impl;
+		if (!iface->unicast_get_mode)
+			iface->unicast_get_mode = nic_unicast_get_mode_impl;
+		if (!iface->unicast_set_mode)
+			iface->unicast_set_mode = nic_unicast_set_mode_impl;
+		if (!iface->multicast_get_mode)
+			iface->multicast_get_mode = nic_multicast_get_mode_impl;
+		if (!iface->multicast_set_mode)
+			iface->multicast_set_mode = nic_multicast_set_mode_impl;
+		if (!iface->broadcast_get_mode)
+			iface->broadcast_get_mode = nic_broadcast_get_mode_impl;
+		if (!iface->broadcast_set_mode)
+			iface->broadcast_set_mode = nic_broadcast_set_mode_impl;
+		if (!iface->blocked_sources_get)
+			iface->blocked_sources_get = nic_blocked_sources_get_impl;
+		if (!iface->blocked_sources_set)
+			iface->blocked_sources_set = nic_blocked_sources_set_impl;
+		if (!iface->vlan_get_mask)
+			iface->vlan_get_mask = nic_vlan_get_mask_impl;
+		if (!iface->vlan_set_mask)
+			iface->vlan_set_mask = nic_vlan_set_mask_impl;
+		if (!iface->wol_virtue_add)
+			iface->wol_virtue_add = nic_wol_virtue_add_impl;
+		if (!iface->wol_virtue_remove)
+			iface->wol_virtue_remove = nic_wol_virtue_remove_impl;
+		if (!iface->wol_virtue_probe)
+			iface->wol_virtue_probe = nic_wol_virtue_probe_impl;
+		if (!iface->wol_virtue_list)
+			iface->wol_virtue_list = nic_wol_virtue_list_impl;
+		if (!iface->wol_virtue_get_caps)
+			iface->wol_virtue_get_caps = nic_wol_virtue_get_caps_impl;
+		if (!iface->poll_get_mode)
+			iface->poll_get_mode = nic_poll_get_mode_impl;
+		if (!iface->poll_set_mode)
+			iface->poll_set_mode = nic_poll_set_mode_impl;
+		if (!iface->poll_now)
+			iface->poll_now = nic_poll_now_impl;
+	}
+}
+
+/**
+ * Setup write packet handler. This MUST be called in the add_device handler
+ * if the nic_send_message_impl function is used for sending messages (filled
+ * as send_message member of the nic_iface_t structure). The function must not
+ * be called anywhere else.
+ *
+ * @param nic_data
+ * @param wpfunc		Function handling the write_packet request
+ */
+void nic_set_write_packet_handler(nic_t *nic_data, write_packet_handler wpfunc)
+{
+	nic_data->write_packet = wpfunc;
+}
+
+/**
+ * Setup event handlers for transitions between driver states.
+ * This function can be called only in the add_device handler.
+ *
+ * @param on_activating	Called when device is going to the ACTIVE state.
+ * @param on_going_down Called when device is going to the DOWN state.
+ * @param on_stopping	Called when device is going to the STOP state.
+ */
+void nic_set_state_change_handlers(nic_t *nic_data,
+	state_change_handler on_activating, state_change_handler on_going_down,
+	state_change_handler on_stopping)
+{
+	nic_data->on_activating = on_activating;
+	nic_data->on_going_down = on_going_down;
+	nic_data->on_stopping = on_stopping;
+}
+
+/**
+ * Setup event handlers for changing the filtering modes.
+ * This function can be called only in the add_device handler.
+ *
+ * @param nic_data
+ * @param on_unicast_mode_change
+ * @param on_multicast_mode_change
+ * @param on_broadcast_mode_change
+ * @param on_blocked_sources_change
+ * @param on_vlan_mask_change
+ */
+void nic_set_filtering_change_handlers(nic_t *nic_data,
+	unicast_mode_change_handler on_unicast_mode_change,
+	multicast_mode_change_handler on_multicast_mode_change,
+	broadcast_mode_change_handler on_broadcast_mode_change,
+	blocked_sources_change_handler on_blocked_sources_change,
+	vlan_mask_change_handler on_vlan_mask_change)
+{
+	nic_data->on_unicast_mode_change = on_unicast_mode_change;
+	nic_data->on_multicast_mode_change = on_multicast_mode_change;
+	nic_data->on_broadcast_mode_change = on_broadcast_mode_change;
+	nic_data->on_blocked_sources_change = on_blocked_sources_change;
+	nic_data->on_vlan_mask_change = on_vlan_mask_change;
+}
+
+/**
+ * Setup filters for WOL virtues add and removal.
+ * This function can be called only in the add_device handler. Both handlers
+ * must be set or none of them.
+ *
+ * @param on_wv_add		Called when a virtue is added
+ * @param on_wv_remove	Called when a virtue is removed
+ */
+void nic_set_wol_virtue_change_handlers(nic_t *nic_data,
+	wol_virtue_add_handler on_wv_add, wol_virtue_remove_handler on_wv_remove)
+{
+	assert(on_wv_add != NULL && on_wv_remove != NULL);
+	nic_data->on_wol_virtue_add = on_wv_add;
+	nic_data->on_wol_virtue_remove = on_wv_remove;
+}
+
+/**
+ * Setup poll handlers.
+ * This function can be called only in the add_device handler.
+ *
+ * @param on_poll_mode_change	Called when the mode is about to be changed
+ * @param on_poll_request		Called when poll request is triggered
+ */
+void nic_set_poll_handlers(nic_t *nic_data,
+	poll_mode_change_handler on_poll_mode_change, poll_request_handler on_poll_req)
+{
+	nic_data->on_poll_mode_change = on_poll_mode_change;
+	nic_data->on_poll_request = on_poll_req;
+}
+
+/**
+ * Connect to the parent's driver and get HW resources list in parsed format.
+ * Note: this function should be called only from add_device handler, therefore
+ * we don't need to use locks.
+ *
+ * @param		nic_data
+ * @param[out]	resources	Parsed lists of resources.
+ *
+ * @return EOK or negative error code
+ */
+int nic_get_resources(nic_t *nic_data, hw_res_list_parsed_t *resources)
+{
+	ddf_dev_t *dev = nic_data->dev;
+	
+	/* Connect to the parent's driver. */
+	dev->parent_sess = devman_parent_device_connect(EXCHANGE_SERIALIZE,
+		dev->handle, IPC_FLAG_BLOCKING);
+	if (dev->parent_sess == NULL)
+		return EPARTY;
+	
+	return hw_res_get_list_parsed(nic_data->dev->parent_sess, resources, 0);
+}
+
+/**
+ * Just a wrapper over the packet_get_1_remote function
+ */
+packet_t *nic_alloc_packet(nic_t *nic_data, size_t data_size)
+{
+	return packet_get_1_remote(nic_data->net_session, data_size);
+}
+
+
+/**
+ * Just a wrapper over the pq_release_remote function
+ */
+void nic_release_packet(nic_t *nic_data, packet_t *packet)
+{
+	pq_release_remote(nic_data->net_session, packet_get_id(packet));
+}
+
+/** Allocate frame and packet
+ *
+ *  @param nic_data 	The NIC driver data
+ *  @param packet_size	Size of packet
+ *  @param offload_size	Size of packet offload
+ *  @return pointer to allocated frame if success, NULL otherwise
+ */
+nic_frame_t *nic_alloc_frame(nic_t *nic_data, size_t packet_size)
+{
+	nic_frame_t *frame;
+	fibril_mutex_lock(&nic_globals.lock);
+	if (nic_globals.frame_cache_size > 0) {
+		link_t *first = list_first(&nic_globals.frame_cache);
+		list_remove(first);
+		nic_globals.frame_cache_size--;
+		frame = list_get_instance(first, nic_frame_t, link);
+		fibril_mutex_unlock(&nic_globals.lock);
+	} else {
+		fibril_mutex_unlock(&nic_globals.lock);
+		frame = malloc(sizeof(nic_frame_t));
+		if (!frame)
+			return NULL;
+		
+		link_initialize(&frame->link);
+	}
+
+	packet_t *packet = nic_alloc_packet(nic_data, packet_size);
+	if (!packet) {
+		free(frame);
+		return NULL;
+	}
+
+	frame->packet = packet;
+	return frame;
+}
+
+/** Release frame
+ *
+ * @param nic_data	The driver data
+ * @param frame		The frame to release
+ */
+void nic_release_frame(nic_t *nic_data, nic_frame_t *frame)
+{
+	if (!frame)
+		return;
+	if (frame->packet != NULL) {
+		nic_release_packet(nic_data, frame->packet);
+	}
+	fibril_mutex_lock(&nic_globals.lock);
+	if (nic_globals.frame_cache_size >= NIC_GLOBALS_MAX_CACHE_SIZE) {
+		fibril_mutex_unlock(&nic_globals.lock);
+		free(frame);
+	} else {
+		list_prepend(&frame->link, &nic_globals.frame_cache);
+		nic_globals.frame_cache_size++;
+		fibril_mutex_unlock(&nic_globals.lock);
+	}
+}
+
+/**
+ * Allocate a new frame list
+ *
+ * @return New frame list or NULL on error.
+ */
+nic_frame_list_t *nic_alloc_frame_list(void)
+{
+	nic_frame_list_t *frames;
+	fibril_mutex_lock(&nic_globals.lock);
+	
+	if (nic_globals.frame_list_cache_size > 0) {
+		frames =
+		    list_get_instance(list_first(&nic_globals.frame_list_cache),
+		    nic_frame_list_t, head);
+		list_remove(&frames->head);
+		list_initialize(frames);
+		nic_globals.frame_list_cache_size--;
+		fibril_mutex_unlock(&nic_globals.lock);
+	} else {
+		fibril_mutex_unlock(&nic_globals.lock);
+		
+		frames = malloc(sizeof (nic_frame_list_t));
+		if (frames != NULL)
+			list_initialize(frames);
+	}
+	
+	return frames;
+}
+
+static void nic_driver_release_frame_list(nic_frame_list_t *frames)
+{
+	if (!frames)
+		return;
+	fibril_mutex_lock(&nic_globals.lock);
+	if (nic_globals.frame_list_cache_size >= NIC_GLOBALS_MAX_CACHE_SIZE) {
+		fibril_mutex_unlock(&nic_globals.lock);
+		free(frames);
+	} else {
+		list_prepend(&frames->head, &nic_globals.frame_list_cache);
+		nic_globals.frame_list_cache_size++;
+		fibril_mutex_unlock(&nic_globals.lock);
+	}
+}
+
+/**
+ * Append a frame to the frame list
+ *
+ * @param frames	Frame list
+ * @param frame		Appended frame
+ */
+void nic_frame_list_append(nic_frame_list_t *frames,
+	nic_frame_t *frame)
+{
+	assert(frame != NULL && frames != NULL);
+	list_append(&frame->link, frames);
+}
+
+
+/**
+ * Enable interrupts for this driver.
+ *
+ * @param nic_data
+ * @param irq			The IRQ number for this device
+ */
+void nic_enable_interrupt(nic_t *nic_data, int irq)
+{
+	async_exch_t *exch = async_exchange_begin(nic_data->irc_session);
+	async_msg_1(exch, IRC_ENABLE_INTERRUPT, irq);
+	async_exchange_end(exch);
+}
+
+/**
+ * Disable interrupts for this driver.
+ *
+ * @param nic_data
+ * @param irq			The IRQ number for this device
+ */
+void nic_disable_interrupt(nic_t *nic_data, int irq)
+{
+	async_exch_t *exch = async_exchange_begin(nic_data->irc_session);
+	async_msg_1(exch, IRC_CLEAR_INTERRUPT, irq);
+	async_exchange_end(exch);
+}
+
+/** Get the polling mode information from the device 
+ *
+ *	The main lock should be locked, otherwise the inconsistency between
+ *	mode and period can occure.
+ *
+ *  @param nic_data The controller data
+ *  @param period [out] The the period. Valid only if mode == NIC_POLL_PERIODIC
+ *  @return Current polling mode of the controller
+ */
+nic_poll_mode_t nic_query_poll_mode(nic_t *nic_data, struct timeval *period)
+{
+	if (period)
+		*period = nic_data->poll_period;
+	return nic_data->poll_mode;
+};
+
+/**
+ * Connect to the NET and IRQ services. This function should be called only from
+ * the add_device handler, thus no locking is required.
+ *
+ * @param nic_data
+ *
+ * @return EOK		If connection was successful.
+ * @return EINVAL	If the IRC service cannot be determined.
+ * @return EREFUSED	If NET or IRC service cannot be connected.
+ */
+int nic_connect_to_services(nic_t *nic_data)
+{
+	/* NET service */
+	nic_data->net_session = service_connect_blocking(EXCHANGE_SERIALIZE,
+		SERVICE_NETWORKING, 0, 0);
+	if (nic_data->net_session == NULL)
+		return errno;
+	
+	/* IRC service */
+	sysarg_t apic;
+	sysarg_t i8259;
+	services_t irc_service = -1;
+	if (((sysinfo_get_value("apic", &apic) == EOK) && (apic)) ||
+	    ((sysinfo_get_value("i8259", &i8259) == EOK) && (i8259)))
+		irc_service = SERVICE_IRC;
+	else
+		return EINVAL;
+	
+	nic_data->irc_session = service_connect_blocking(EXCHANGE_SERIALIZE,
+		irc_service, 0, 0);
+	if (nic_data->irc_session == NULL)
+		return errno;
+	
+	return EOK;
+}
+
+/** Notify the NET service that the device is ready
+ *
+ * @param nic NICF structure
+ *
+ * @return EOK on success
+ *
+ */
+int nic_ready(nic_t *nic)
+{
+	fibril_rwlock_read_lock(&nic->main_lock);
+	
+	async_sess_t *session = nic->net_session;
+	devman_handle_t handle = nic->dev->handle;
+	
+	fibril_rwlock_read_unlock(&nic->main_lock);
+	
+	if (session == NULL)
+		return EINVAL;
+	
+	return net_driver_ready(session, handle);
+}
+
+/** Inform the NICF about poll mode
+ *
+ *  @param nic_data The controller data
+ *  @param mode
+ *  @param period [out] The the period. Valid only if mode == NIC_POLL_PERIODIC
+ *  @return EOK
+ *  @return EINVAL
+ */
+int nic_report_poll_mode(nic_t *nic_data, nic_poll_mode_t mode,
+	struct timeval *period)
+{
+	int rc = EOK;
+	fibril_rwlock_write_lock(&nic_data->main_lock);
+	nic_data->poll_mode = mode;
+	nic_data->default_poll_mode = mode;
+	if (mode == NIC_POLL_PERIODIC) {
+		if (period) {
+			memcpy(&nic_data->default_poll_period, period, sizeof (struct timeval));
+			memcpy(&nic_data->poll_period, period, sizeof (struct timeval));
+		} else {
+			rc = EINVAL;
+		}
+	}
+	fibril_rwlock_write_unlock(&nic_data->main_lock);
+	return rc;
+}
+
+/** Inform the NICF about device's MAC adress.
+ *
+ * @return EOK On success
+ *
+ */
+int nic_report_address(nic_t *nic_data, const nic_address_t *address)
+{
+	assert(nic_data);
+	
+	if (address->address[0] & 1)
+		return EINVAL;
+	
+	fibril_rwlock_write_lock(&nic_data->main_lock);
+	
+	/* Notify NIL layer (and uppper) if bound - not in add_device */
+	if (nic_data->nil_session != NULL) {
+		int rc = nil_addr_changed_msg(nic_data->nil_session,
+		    nic_data->device_id, address);
+		if (rc != EOK) {
+			fibril_rwlock_write_unlock(&nic_data->main_lock);
+			return rc;
+		}
+	}
+	
+	fibril_rwlock_write_lock(&nic_data->rxc_lock);
+	
+	/*
+	 * The initial address (all zeroes) shouldn't be
+	 * there and we will ignore that error -- in next
+	 * calls this should not happen.
+	 */
+	int rc = nic_rxc_set_addr(&nic_data->rx_control,
+	    &nic_data->mac, address);
+	
+	/* For the first time also record the default MAC */
+	if (MAC_IS_ZERO(nic_data->default_mac.address)) {
+		assert(MAC_IS_ZERO(nic_data->mac.address));
+		memcpy(&nic_data->default_mac, address, sizeof(nic_address_t));
+	}
+	
+	fibril_rwlock_write_unlock(&nic_data->rxc_lock);
+	
+	if ((rc != EOK) && (rc != ENOENT)) {
+		fibril_rwlock_write_unlock(&nic_data->main_lock);
+		return rc;
+	}
+	
+	memcpy(&nic_data->mac, address, sizeof(nic_address_t));
+	
+	fibril_rwlock_write_unlock(&nic_data->main_lock);
+	
+	return EOK;
+}
+
+/**
+ * Used to obtain devices MAC address.
+ *
+ * The main lock should be locked, otherwise the inconsistent address
+ * can be returend.
+ *
+ * @param nic_data The controller data
+ * @param address The output for address.
+ */
+void nic_query_address(nic_t *nic_data, nic_address_t *addr) {
+	if (!addr)
+		return;
+	if (!nic_data)
+		memset(addr, 0, sizeof(nic_address_t));
+
+	memcpy(addr, &nic_data->mac, sizeof(nic_address_t));
+};
+
+/**
+ * The busy flag can be set to 1 only in the write_packet handler, to 0 it can
+ * be set anywhere.
+ *
+ * @param nic_data
+ * @param busy
+ */
+void nic_set_tx_busy(nic_t *nic_data, int busy)
+{
+	/*
+	 * When the function is called in write_packet handler the main lock is
+	 * locked so no race can happen.
+	 * Otherwise, when it is unexpectedly set to 0 (even with main lock held
+	 * by other fibril) it cannot crash anything.
+	 */
+	nic_data->tx_busy = busy;
+}
+
+/**
+ * Provided for correct naming conventions.
+ * The packet is checked by filters and then sent up to the NIL layer or
+ * discarded, the frame is released.
+ *
+ * @param nic_data
+ * @param frame		The frame containing received packet
+ */
+void nic_received_frame(nic_t *nic_data, nic_frame_t *frame)
+{
+	nic_received_packet(nic_data, frame->packet);
+	frame->packet = NULL;
+	nic_release_frame(nic_data, frame);
+}
+
+/**
+ * This is the function that the driver should call when it receives a packet.
+ * The packet is checked by filters and then sent up to the NIL layer or
+ * discarded.
+ *
+ * @param nic_data
+ * @param packet		The received packet
+ */
+void nic_received_packet(nic_t *nic_data, packet_t *packet)
+{
+	/* Note: this function must not lock main lock, because loopback driver
+	 * 		 calls it inside write_packet handler (with locked main lock) */
+	packet_id_t pid = packet_get_id(packet);
+	
+	fibril_rwlock_read_lock(&nic_data->rxc_lock);
+	nic_frame_type_t frame_type;
+	int check = nic_rxc_check(&nic_data->rx_control, packet, &frame_type);
+	fibril_rwlock_read_unlock(&nic_data->rxc_lock);
+	/* Update statistics */
+	fibril_rwlock_write_lock(&nic_data->stats_lock);
+	/* Both sending message up and releasing packet are atomic IPC calls */
+	if (nic_data->state == NIC_STATE_ACTIVE && check) {
+		nic_data->stats.receive_packets++;
+		nic_data->stats.receive_bytes += packet_get_data_length(packet);
+		switch (frame_type) {
+		case NIC_FRAME_MULTICAST:
+			nic_data->stats.receive_multicast++;
+			break;
+		case NIC_FRAME_BROADCAST:
+			nic_data->stats.receive_broadcast++;
+			break;
+		default:
+			break;
+		}
+		fibril_rwlock_write_unlock(&nic_data->stats_lock);
+		nil_received_msg(nic_data->nil_session, nic_data->device_id, pid);
+	} else {
+		switch (frame_type) {
+		case NIC_FRAME_UNICAST:
+			nic_data->stats.receive_filtered_unicast++;
+			break;
+		case NIC_FRAME_MULTICAST:
+			nic_data->stats.receive_filtered_multicast++;
+			break;
+		case NIC_FRAME_BROADCAST:
+			nic_data->stats.receive_filtered_broadcast++;
+			break;
+		}
+		fibril_rwlock_write_unlock(&nic_data->stats_lock);
+		nic_release_packet(nic_data, packet);
+	}
+}
+
+/**
+ * This function is to be used only in the loopback driver. It's workaround
+ * for the situation when the packet does not contain ethernet address.
+ * The filtering is therefore not applied here.
+ *
+ * @param nic_data
+ * @param packet
+ */
+void nic_received_noneth_packet(nic_t *nic_data, packet_t *packet)
+{
+	fibril_rwlock_write_lock(&nic_data->stats_lock);
+	nic_data->stats.receive_packets++;
+	nic_data->stats.receive_bytes += packet_get_data_length(packet);
+	fibril_rwlock_write_unlock(&nic_data->stats_lock);
+	
+	nil_received_msg(nic_data->nil_session, nic_data->device_id,
+	    packet_get_id(packet));
+}
+
+/**
+ * Some NICs can receive multiple packets during single interrupt. These can
+ * send them in whole list of frames (actually nic_frame_t structures), then
+ * the list is deallocated and each packet is passed to the
+ * nic_received_packet function.
+ *
+ * @param nic_data
+ * @param frames		List of received frames
+ */
+void nic_received_frame_list(nic_t *nic_data, nic_frame_list_t *frames)
+{
+	if (frames == NULL)
+		return;
+	while (!list_empty(frames)) {
+		nic_frame_t *frame =
+			list_get_instance(list_first(frames), nic_frame_t, link);
+
+		list_remove(&frame->link);
+		nic_received_packet(nic_data, frame->packet);
+		frame->packet = NULL;
+		nic_release_frame(nic_data, frame);
+	}
+	nic_driver_release_frame_list(frames);
+}
+
+/** Allocate and initialize the driver data.
+ *
+ * @return Allocated structure or NULL.
+ *
+ */
+static nic_t *nic_create(void)
+{
+	nic_t *nic_data = malloc(sizeof(nic_t));
+	if (nic_data == NULL)
+		return NULL;
+	
+	/* Force zero to all uninitialized fields (e.g. added in future) */
+	bzero(nic_data, sizeof(nic_t));
+	if (nic_rxc_init(&nic_data->rx_control) != EOK) {
+		free(nic_data);
+		return NULL;
+	}
+	
+	if (nic_wol_virtues_init(&nic_data->wol_virtues) != EOK) {
+		free(nic_data);
+		return NULL;
+	}
+	
+	nic_data->dev = NULL;
+	nic_data->fun = NULL;
+	nic_data->device_id = NIC_DEVICE_INVALID_ID;
+	nic_data->state = NIC_STATE_STOPPED;
+	nic_data->net_session = NULL;
+	nic_data->nil_session = NULL;
+	nic_data->irc_session = NULL;
+	nic_data->poll_mode = NIC_POLL_IMMEDIATE;
+	nic_data->default_poll_mode = NIC_POLL_IMMEDIATE;
+	nic_data->write_packet = NULL;
+	nic_data->on_activating = NULL;
+	nic_data->on_going_down = NULL;
+	nic_data->on_stopping = NULL;
+	nic_data->specific = NULL;
+	
+	fibril_rwlock_initialize(&nic_data->main_lock);
+	fibril_rwlock_initialize(&nic_data->stats_lock);
+	fibril_rwlock_initialize(&nic_data->rxc_lock);
+	fibril_rwlock_initialize(&nic_data->wv_lock);
+	
+	bzero(&nic_data->mac, sizeof(nic_address_t));
+	bzero(&nic_data->default_mac, sizeof(nic_address_t));
+	bzero(&nic_data->stats, sizeof(nic_device_stats_t));
+	
+	return nic_data;
+}
+
+/** Create NIC structure for the device and bind it to dev_fun_t
+ *
+ * The pointer to the created and initialized NIC structure will
+ * be stored in device->nic_data.
+ *
+ * @param device The NIC device structure
+ *
+ * @return Pointer to created nic_t structure or NULL
+ *
+ */
+nic_t *nic_create_and_bind(ddf_dev_t *device)
+{
+	assert(device);
+	assert(!device->driver_data);
+	
+	nic_t *nic_data = nic_create();
+	if (!nic_data)
+		return NULL;
+	
+	nic_data->dev = device;
+	device->driver_data = nic_data;
+	
+	return nic_data;
+}
+
+/**
+ * Hangs up the phones in the structure, deallocates specific data and then
+ * the structure itself.
+ *
+ * @param data
+ */
+static void nic_destroy(nic_t *nic_data) {
+	if (nic_data->net_session != NULL) {
+		async_hangup(nic_data->net_session);
+	}
+
+	if (nic_data->nil_session != NULL) {
+		async_hangup(nic_data->nil_session);
+	}
+
+	free(nic_data->specific);
+	free(nic_data);
+}
+
+/**
+ * Unbind and destroy nic_t stored in ddf_dev_t.nic_data.
+ * The ddf_dev_t.nic_data will be set to NULL, specific driver data will be
+ * destroyed.
+ *
+ * @param device The NIC device structure
+ */
+void nic_unbind_and_destroy(ddf_dev_t *device){
+	if (!device)
+		return;
+	if (!device->driver_data)
+		return;
+
+	nic_destroy((nic_t *) device->driver_data);
+	device->driver_data = NULL;
+	return;
+}
+
+/**
+ * Creates an exposed DDF function for the device, named "port0".
+ * Device options are set as this function's options. The function is bound
+ * (see ddf_fun_bind) and then registered to the DEVICE_CATEGORY_NIC class.
+ * Note: this function should be called only from add_device handler, therefore
+ * we don't need to use locks.
+ *
+ * @param nic_data	The NIC structure
+ * @param ops		Device options for the DDF function.
+ */
+int nic_register_as_ddf_fun(nic_t *nic_data, ddf_dev_ops_t *ops)
+{
+	int rc;
+	assert(nic_data);
+
+	nic_data->fun = ddf_fun_create(nic_data->dev, fun_exposed, "port0");
+	if (nic_data->fun == NULL)
+		return ENOMEM;
+	
+	nic_data->fun->ops = ops;
+	nic_data->fun->driver_data = nic_data;
+
+	rc = ddf_fun_bind(nic_data->fun);
+	if (rc != EOK) {
+		ddf_fun_destroy(nic_data->fun);
+		return rc;
+	}
+
+	rc = ddf_fun_add_to_category(nic_data->fun, DEVICE_CATEGORY_NIC);
+	if (rc != EOK) {
+		ddf_fun_destroy(nic_data->fun);
+		return rc;
+	}
+	
+	return EOK;
+}
+
+/**
+ * Set information about current HW filtering.
+ *  1 ...	Only those frames we want to receive are passed through HW
+ *  0 ...	The HW filtering is imperfect
+ * -1 ...	Don't change the setting
+ * Can be called only from the on_*_change handler.
+ *
+ * @param	nic_data
+ * @param	unicast_exact	Unicast frames
+ * @param	mcast_exact		Multicast frames
+ * @param	vlan_exact		VLAN tags
+ */
+void nic_report_hw_filtering(nic_t *nic_data,
+	int unicast_exact, int multicast_exact, int vlan_exact)
+{
+	nic_rxc_hw_filtering(&nic_data->rx_control,
+		unicast_exact, multicast_exact, vlan_exact);
+}
+
+/**
+ * Computes hash for the address list based on standard multicast address
+ * hashing.
+ *
+ * @param address_list
+ * @param count
+ *
+ * @return Multicast hash
+ *
+ * @see multicast_hash
+ */
+uint64_t nic_mcast_hash(const nic_address_t *list, size_t count)
+{
+	return nic_rxc_mcast_hash(list, count);
+}
+
+/**
+ * Computes hash for multicast addresses currently set up in the RX multicast
+ * filtering. For promiscuous mode returns all ones, for blocking all zeroes.
+ * Can be called only from the state change handlers (on_activating,
+ * on_going_down and on_stopping).
+ *
+ * @param nic_data
+ *
+ * @return Multicast hash
+ *
+ * @see multicast_hash
+ */
+uint64_t nic_query_mcast_hash(nic_t *nic_data)
+{
+	fibril_rwlock_read_lock(&nic_data->rxc_lock);
+	uint64_t hash = nic_rxc_multicast_get_hash(&nic_data->rx_control);
+	fibril_rwlock_read_unlock(&nic_data->rxc_lock);
+	return hash;
+}
+
+/**
+ * Queries the current mode of unicast frames receiving.
+ * Can be called only from the on_*_change handler.
+ *
+ * @param nic_data
+ * @param mode			The new unicast mode
+ * @param max_count		Max number of addresses that can be written into the
+ * 						address_list.
+ * @param address_list	List of MAC addresses or NULL.
+ * @param address_count Number of addresses in the list
+ */
+void nic_query_unicast(const nic_t *nic_data,
+	nic_unicast_mode_t *mode,
+	size_t max_count, nic_address_t *address_list, size_t *address_count)
+{
+	assert(mode != NULL);
+	nic_rxc_unicast_get_mode(&nic_data->rx_control, mode,
+		max_count, address_list, address_count);
+}
+
+/**
+ * Queries the current mode of multicast frames receiving.
+ * Can be called only from the on_*_change handler.
+ *
+ * @param nic_data
+ * @param mode			The current multicast mode
+ * @param max_count		Max number of addresses that can be written into the
+ * 						address_list.
+ * @param address_list	List of MAC addresses or NULL.
+ * @param address_count Number of addresses in the list
+ */
+void nic_query_multicast(const nic_t *nic_data,
+	nic_multicast_mode_t *mode,
+	size_t max_count, nic_address_t *address_list, size_t *address_count)
+{
+	assert(mode != NULL);
+	nic_rxc_multicast_get_mode(&nic_data->rx_control, mode,
+		max_count, address_list, address_count);
+}
+
+/**
+ * Queries the current mode of broadcast frames receiving.
+ * Can be called only from the on_*_change handler.
+ *
+ * @param nic_data
+ * @param mode			The new broadcast mode
+ */
+void nic_query_broadcast(const nic_t *nic_data,
+	nic_broadcast_mode_t *mode)
+{
+	assert(mode != NULL);
+	nic_rxc_broadcast_get_mode(&nic_data->rx_control, mode);
+}
+
+/**
+ * Queries the current blocked source addresses.
+ * Can be called only from the on_*_change handler.
+ *
+ * @param nic_data
+ * @param max_count		Max number of addresses that can be written into the
+ * 						address_list.
+ * @param address_list	List of MAC addresses or NULL.
+ * @param address_count Number of addresses in the list
+ */
+void nic_query_blocked_sources(const nic_t *nic_data,
+	size_t max_count, nic_address_t *address_list, size_t *address_count)
+{
+	nic_rxc_blocked_sources_get(&nic_data->rx_control,
+		max_count, address_list, address_count);
+}
+
+/**
+ * Query mask used for filtering according to the VLAN tags.
+ * Can be called only from the on_*_change handler.
+ *
+ * @param nic_data
+ * @param mask		Must be 512 bytes long
+ *
+ * @return EOK
+ * @return ENOENT
+ */
+int nic_query_vlan_mask(const nic_t *nic_data, nic_vlan_mask_t *mask)
+{
+	assert(mask);
+	return nic_rxc_vlan_get_mask(&nic_data->rx_control, mask);
+}
+
+/**
+ * Query maximum number of WOL virtues of specified type allowed on the device.
+ * Can be called only from add_device and on_wol_virtue_* handlers.
+ *
+ * @param nic_data
+ * @param type		The type of the WOL virtues
+ *
+ * @return	Maximal number of allowed virtues of this type. -1 means this type
+ * 			is not supported at all.
+ */
+int nic_query_wol_max_caps(const nic_t *nic_data, nic_wv_type_t type)
+{
+	return nic_data->wol_virtues.caps_max[type];
+}
+
+/**
+ * Sets maximum number of WOL virtues of specified type allowed on the device.
+ * Can be called only from add_device and on_wol_virtue_* handlers.
+ *
+ * @param nic_data
+ * @param type		The type of the WOL virtues
+ * @param count		Maximal number of allowed virtues of this type. -1 means
+ * 					this type is not supported at all.
+ */
+void nic_set_wol_max_caps(nic_t *nic_data, nic_wv_type_t type, int count)
+{
+	nic_data->wol_virtues.caps_max[type] = count;
+}
+
+/**
+ * @param nic_data
+ * @return The driver-specific structure for this NIC.
+ */
+void *nic_get_specific(nic_t *nic_data)
+{
+	return nic_data->specific;
+}
+
+/**
+ * @param nic_data
+ * @param specific The driver-specific structure for this NIC.
+ */
+void nic_set_specific(nic_t *nic_data, void *specific)
+{
+	nic_data->specific = specific;
+}
+
+/**
+ * You can call the function only from one of the state change handlers.
+ * @param	nic_data
+ * @return	Current state of the NIC, prior to the actually executed change
+ */
+nic_device_state_t nic_query_state(nic_t *nic_data)
+{
+	return nic_data->state;
+}
+
+/**
+ * @param nic_data
+ * @return DDF device associated with this NIC.
+ */
+ddf_dev_t *nic_get_ddf_dev(nic_t *nic_data)
+{
+	return nic_data->dev;
+}
+
+/**
+ * @param nic_data
+ * @return DDF function associated with this NIC.
+ */
+ddf_fun_t *nic_get_ddf_fun(nic_t *nic_data)
+{
+	return nic_data->fun;
+}
+
+/** 
+ * @param dev DDF device associated with NIC
+ * @return The associated NIC structure
+ */
+nic_t *nic_get_from_ddf_dev(ddf_dev_t *dev)
+{
+	return (nic_t *) dev->driver_data;
+};
+
+/** 
+ * @param dev DDF function associated with NIC
+ * @return The associated NIC structure
+ */
+nic_t *nic_get_from_ddf_fun(ddf_fun_t *fun)
+{
+	return (nic_t *) fun->driver_data;
+};
+
+/**
+ * Raises the send_packets and send_bytes in device statistics.
+ *
+ * @param nic_data
+ * @param packets	Number of received packets
+ * @param bytes		Number of received bytes
+ */
+void nic_report_send_ok(nic_t *nic_data, size_t packets, size_t bytes)
+{
+	fibril_rwlock_write_lock(&nic_data->stats_lock);
+	nic_data->stats.send_packets += packets;
+	nic_data->stats.send_bytes += bytes;
+	fibril_rwlock_write_unlock(&nic_data->stats_lock);
+}
+
+/**
+ * Raises total error counter (send_errors) and the concrete send error counter
+ * determined by the cause argument.
+ *
+ * @param nic_data
+ * @param cause		The concrete error cause.
+ */
+void nic_report_send_error(nic_t *nic_data, nic_send_error_cause_t cause, 
+    unsigned count)
+{
+	if (count == 0)
+		return;
+	
+	fibril_rwlock_write_lock(&nic_data->stats_lock);
+	nic_data->stats.send_errors += count;
+	switch (cause) {
+	case NIC_SEC_BUFFER_FULL:
+		nic_data->stats.send_dropped += count;
+		break;
+	case NIC_SEC_ABORTED:
+		nic_data->stats.send_aborted_errors += count;
+		break;
+	case NIC_SEC_CARRIER_LOST:
+		nic_data->stats.send_carrier_errors += count;
+		break;
+	case NIC_SEC_FIFO_OVERRUN:
+		nic_data->stats.send_fifo_errors += count;
+		break;
+	case NIC_SEC_HEARTBEAT:
+		nic_data->stats.send_heartbeat_errors += count;
+		break;
+	case NIC_SEC_WINDOW_ERROR:
+		nic_data->stats.send_window_errors += count;
+		break;
+	case NIC_SEC_OTHER:
+		break;
+	}
+	fibril_rwlock_write_unlock(&nic_data->stats_lock);
+}
+
+/**
+ * Raises total error counter (receive_errors) and the concrete receive error
+ * counter determined by the cause argument.
+ *
+ * @param nic_data
+ * @param cause		The concrete error cause
+ */
+void nic_report_receive_error(nic_t *nic_data,
+	nic_receive_error_cause_t cause, unsigned count)
+{
+	fibril_rwlock_write_lock(&nic_data->stats_lock);
+	nic_data->stats.receive_errors += count;
+	switch (cause) {
+	case NIC_REC_BUFFER_FULL:
+		nic_data->stats.receive_dropped += count;
+		break;
+	case NIC_REC_LENGTH:
+		nic_data->stats.receive_length_errors += count;
+		break;
+	case NIC_REC_BUFFER_OVERFLOW:
+		nic_data->stats.receive_dropped += count;
+		break;
+	case NIC_REC_CRC:
+		nic_data->stats.receive_crc_errors += count;
+		break;
+	case NIC_REC_FRAME_ALIGNMENT:
+		nic_data->stats.receive_frame_errors += count;
+		break;
+	case NIC_REC_FIFO_OVERRUN:
+		nic_data->stats.receive_fifo_errors += count;
+		break;
+	case NIC_REC_MISSED:
+		nic_data->stats.receive_missed_errors += count;
+		break;
+	case NIC_REC_OTHER:
+		break;
+	}
+	fibril_rwlock_write_unlock(&nic_data->stats_lock);
+}
+
+/**
+ * Raises the collisions counter in device statistics.
+ */
+void nic_report_collisions(nic_t *nic_data, unsigned count)
+{
+	fibril_rwlock_write_lock(&nic_data->stats_lock);
+	nic_data->stats.collisions += count;
+	fibril_rwlock_write_unlock(&nic_data->stats_lock);
+}
+
+/** Just wrapper for checking nonzero time interval 
+ *
+ *  @oaram t The interval to check
+ *  @returns Zero if the t is nonzero interval
+ *  @returns Nonzero if t is zero interval
+ */
+static int timeval_nonpositive(struct timeval t) {
+	return (t.tv_sec <= 0) && (t.tv_usec <= 0);
+}
+
+/** Main function of software period fibrill
+ *
+ *  Just calls poll() in the nic->poll_period period
+ *
+ *  @param  data The NIC structure pointer
+ *
+ *  @return 0, never reached
+ */
+static int period_fibril_fun(void *data)
+{
+	nic_t *nic = data;
+	struct sw_poll_info *info = &nic->sw_poll_info;
+	while (true) {
+		fibril_rwlock_read_lock(&nic->main_lock);
+		int run = info->run;
+		int running = info->running;
+		struct timeval remaining = nic->poll_period;
+		fibril_rwlock_read_unlock(&nic->main_lock);
+
+		if (!running) {
+			remaining.tv_sec = 5;
+			remaining.tv_usec = 0;
+		}
+
+		/* Wait the period (keep attention to overflows) */
+		while (!timeval_nonpositive(remaining)) {
+			suseconds_t wait = 0;
+			if (remaining.tv_sec > 0) {
+				time_t wait_sec = remaining.tv_sec;
+				/* wait maximaly 5 seconds to get reasonable reaction time
+				 * when period is reset
+				 */
+				if (wait_sec > 5)
+					wait_sec = 5;
+
+				wait = (suseconds_t) wait_sec * 1000000;
+
+				remaining.tv_sec -= wait_sec;
+			} else {
+				wait = remaining.tv_usec;
+
+				if (wait > 5 * 1000000) {
+					wait = 5 * 1000000;
+				}
+
+				remaining.tv_usec -= wait;
+			}
+			async_usleep(wait);
+			
+			/* Check if the period was not reset */
+			if (info->run != run)
+				break;
+		}
+		
+		/* Provide polling if the period finished */
+		fibril_rwlock_read_lock(&nic->main_lock);
+		if (info->running && info->run == run) {
+			nic->on_poll_request(nic);
+		}
+		fibril_rwlock_read_unlock(&nic->main_lock);
+	}
+	return 0;
+}
+
+/** Starts software periodic polling
+ *
+ *  Reset to new period if the original period was running
+ *
+ *  @param nic_data Nic data structure
+ */
+void nic_sw_period_start(nic_t *nic_data)
+{
+	/* Create the fibril if it is not crated */
+	if (nic_data->sw_poll_info.fibril == 0) {
+		nic_data->sw_poll_info.fibril = fibril_create(period_fibril_fun, 
+		    nic_data);
+		nic_data->sw_poll_info.running = 0;
+		nic_data->sw_poll_info.run = 0;
+
+		/* Start fibril */
+		fibril_add_ready(nic_data->sw_poll_info.fibril);
+	}
+
+	/* Inform fibril about running with new period */
+	nic_data->sw_poll_info.run = (nic_data->sw_poll_info.run + 1) % 100;
+	nic_data->sw_poll_info.running = 1;
+}
+
+/** Stops software periodic polling
+ *
+ *  @param nic_data Nic data structure
+ */
+void nic_sw_period_stop(nic_t *nic_data)
+{
+	nic_data->sw_poll_info.running = 0;
+}
+
+// FIXME: Later
+#if 0
+
+/** Lock packet for DMA usage
+ *
+ * @param packet
+ * @return physical address of packet
+ */
+void *nic_dma_lock_packet(packet_t *packet)
+{
+	void *phys_addr;
+	size_t locked;
+	int rc = dma_lock(packet, &phys_addr, 1, &locked);
+	if (rc != EOK)
+		return NULL;
+	
+	assert(locked == 1);
+	return phys_addr;
+}
+
+/** Unlock packet after DMA usage
+ *
+ * @param packet
+ */
+void nic_dma_unlock_packet(packet_t *packet)
+{
+	size_t unlocked;
+	int rc = dma_unlock(packet, 1, &unlocked);
+	if (rc != EOK)
+		return;
+	
+	assert(unlocked == 1);
+}
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/nic/src/nic_impl.c
===================================================================
--- uspace/lib/nic/src/nic_impl.c	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
+++ uspace/lib/nic/src/nic_impl.c	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -0,0 +1,878 @@
+/*
+ * Copyright (c) 2011 Radim Vansa
+ * 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 libnic
+ * @{
+ */
+/**
+ * @file
+ * @brief Default DDF NIC interface methods implementations
+ */
+
+#include <str_error.h>
+#include <ipc/services.h>
+#include <ns.h>
+#include <packet_client.h>
+#include <packet_remote.h>
+#include "nic_driver.h"
+#include "nic_impl.h"
+
+/**
+ * Default implementation of the set_state method. Trivial.
+ *
+ * @param		fun
+ * @param[out]	state
+ *
+ * @return EOK always.
+ */
+int nic_get_state_impl(ddf_fun_t *fun, nic_device_state_t *state)
+{
+	nic_t *nic_data = (nic_t *) fun->driver_data;
+	fibril_rwlock_read_lock(&nic_data->main_lock);
+	*state = nic_data->state;
+	fibril_rwlock_read_unlock(&nic_data->main_lock);
+	return EOK;
+}
+
+/**
+ * Default implementation of the set_state method. Changes the internal
+ * driver's state, calls the appropriate callback and notifies the NIL service
+ * about this change.
+ *
+ * @param	fun
+ * @param	state	The new device's state
+ *
+ * @return EOK		If the state was changed
+ * @return EINVAL	If the state cannot be changed
+ */
+int nic_set_state_impl(ddf_fun_t *fun, nic_device_state_t state)
+{
+	if (state >= NIC_STATE_MAX) {
+		return EINVAL;
+	}
+
+	nic_t *nic_data = (nic_t *) fun->driver_data;
+
+	fibril_rwlock_write_lock(&nic_data->main_lock);
+	if (nic_data->state == state) {
+		/* No change, nothing to do */
+		fibril_rwlock_write_unlock(&nic_data->main_lock);
+		return EOK;
+	}
+	if (state == NIC_STATE_ACTIVE) {
+		if (nic_data->nil_session == NULL || nic_data->net_session == NULL
+		    || nic_data->device_id < 0) {
+			fibril_rwlock_write_unlock(&nic_data->main_lock);
+			return EINVAL;
+		}
+	}
+
+	state_change_handler event_handler = NULL;
+	switch (state) {
+	case NIC_STATE_STOPPED:
+		event_handler = nic_data->on_stopping;
+		break;
+	case NIC_STATE_DOWN:
+		event_handler = nic_data->on_going_down;
+		break;
+	case NIC_STATE_ACTIVE:
+		event_handler = nic_data->on_activating;
+		break;
+	default:
+		break;
+	}
+	if (event_handler != NULL) {
+		int rc = event_handler(nic_data);
+		if (rc != EOK) {
+			fibril_rwlock_write_unlock(&nic_data->main_lock);
+			return EINVAL;
+		}
+	}
+
+	if (state == NIC_STATE_STOPPED) {
+		/* Notify upper layers that we are reseting the MAC */
+		int rc = nil_addr_changed_msg(nic_data->nil_session,
+			nic_data->device_id, &nic_data->default_mac);
+		nic_data->poll_mode = nic_data->default_poll_mode;
+		memcpy(&nic_data->poll_period, &nic_data->default_poll_period,
+			sizeof (struct timeval));
+		if (rc != EOK) {
+			/* We have already ran the on stopped handler, even if we
+			 * terminated the state change we would end up in undefined state.
+			 * Therefore we just log the problem. */
+		}
+
+		fibril_rwlock_write_lock(&nic_data->stats_lock);
+		bzero(&nic_data->stats, sizeof (nic_device_stats_t));
+		fibril_rwlock_write_unlock(&nic_data->stats_lock);
+
+		fibril_rwlock_write_lock(&nic_data->rxc_lock);
+		nic_rxc_clear(&nic_data->rx_control);
+		/* Reinsert device's default MAC */
+		nic_rxc_set_addr(&nic_data->rx_control, NULL,
+			&nic_data->default_mac);
+		fibril_rwlock_write_unlock(&nic_data->rxc_lock);
+		memcpy(&nic_data->mac, &nic_data->default_mac, sizeof (nic_address_t));
+
+		fibril_rwlock_write_lock(&nic_data->wv_lock);
+		nic_wol_virtues_clear(&nic_data->wol_virtues);
+		fibril_rwlock_write_unlock(&nic_data->wv_lock);
+
+		/* Ensure stopping period of NIC_POLL_SOFTWARE_PERIODIC */
+		nic_sw_period_stop(nic_data);
+	}
+
+	nic_data->state = state;
+
+	nil_device_state_msg(nic_data->nil_session, nic_data->device_id, state);
+
+	fibril_rwlock_write_unlock(&nic_data->main_lock);
+
+	return EOK;
+}
+
+/**
+ * Default implementation of the send_message method.
+ * Send messages to the network.
+ *
+ * @param	fun
+ * @param	packet_id	ID of the first packet in a queue of sent packets
+ *
+ * @return EOK		If the message was sent
+ * @return EBUSY	If the device is not in state when the packet can be set.
+ * @return EINVAL	If the packet ID is invalid
+ */
+int nic_send_message_impl(ddf_fun_t *fun, packet_id_t packet_id)
+{
+	nic_t *nic_data = (nic_t *) fun->driver_data;
+	packet_t *packet, *next;
+
+	fibril_rwlock_read_lock(&nic_data->main_lock);
+	if (nic_data->state != NIC_STATE_ACTIVE || nic_data->tx_busy) {
+		fibril_rwlock_read_unlock(&nic_data->main_lock);
+		pq_release_remote(nic_data->net_session, packet_id);
+		return EBUSY;
+	}
+
+	int rc = packet_translate_remote(nic_data->net_session, &packet, packet_id);
+
+	if (rc != EOK) {
+		fibril_rwlock_read_unlock(&nic_data->main_lock);
+		return EINVAL;
+	}
+
+	/*
+	 * Process the packet queue. Each sent packet must be detached from the
+	 * queue and destroyed. This is why the cycle differs from loopback's
+	 * cycle, where the packets are immediately used in upper layers and
+	 * therefore they must not be destroyed (released).
+	 */
+	assert(nic_data->write_packet != NULL);
+	do {
+		next = pq_detach(packet);
+		nic_data->write_packet(nic_data, packet);
+		packet = next;
+	} while (packet);
+	fibril_rwlock_read_unlock(&nic_data->main_lock);
+	return EOK;
+}
+
+/**
+ * Default implementation of the connect_to_nil method.
+ * Connects the driver to the NIL service.
+ *
+ * @param	fun
+ * @param	nil_service	ID of the server implementing the NIL service
+ * @param	device_id	ID of the device as used in higher layers
+ *
+ * @return EOK		If the services were bound
+ * @return 			Negative error code from service_connect_blocking
+ */
+int nic_connect_to_nil_impl(ddf_fun_t *fun, services_t nil_service,
+    nic_device_id_t device_id)
+{
+	nic_t *nic_data = (nic_t *) fun->driver_data;
+	fibril_rwlock_write_lock(&nic_data->main_lock);
+	
+	nic_data->device_id = device_id;
+	
+	nic_data->nil_session = service_connect_blocking(EXCHANGE_SERIALIZE,
+	    nil_service, 0, 0);
+	if (nic_data->nil_session != NULL) {
+		fibril_rwlock_write_unlock(&nic_data->main_lock);
+		return EOK;
+	}
+	
+	fibril_rwlock_write_unlock(&nic_data->main_lock);
+	return EHANGUP;
+}
+
+/**
+ * Default implementation of the get_address method.
+ * Retrieves the NIC's physical address.
+ *
+ * @param	fun
+ * @param	address	Pointer to the structure where the address will be stored.
+ *
+ * @return EOK		If the services were bound
+ * @return ELIMIT	If the buffer is too short
+ */
+int nic_get_address_impl(ddf_fun_t *fun, nic_address_t *address)
+{
+	assert(address);
+	nic_t *nic_data = (nic_t *) fun->driver_data;
+	fibril_rwlock_read_lock(&nic_data->main_lock);
+	memcpy(address, &nic_data->mac, sizeof (nic_address_t));
+	fibril_rwlock_read_unlock(&nic_data->main_lock);
+	return EOK;
+}
+
+/**
+ * Default implementation of the get_stats method. Copies the statistics from
+ * the drivers data to supplied buffer.
+ *
+ * @param		fun
+ * @param[out]	stats	The buffer for statistics
+ *
+ * @return EOK (cannot fail)
+ */
+int nic_get_stats_impl(ddf_fun_t *fun, nic_device_stats_t *stats)
+{
+	nic_t *nic_data = (nic_t *) fun->driver_data;
+	assert (stats != NULL);
+	fibril_rwlock_read_lock(&nic_data->stats_lock);
+	memcpy(stats, &nic_data->stats, sizeof (nic_device_stats_t));
+	fibril_rwlock_read_unlock(&nic_data->stats_lock);
+	return EOK;
+}
+
+/**
+ * Default implementation of unicast_get_mode method.
+ *
+ * @param		fun
+ * @param[out]	mode		Current operation mode
+ * @param[in]	max_count	Max number of addresses that can be written into the
+ * 							buffer (addr_list).
+ * @param[out]	addr_list	Buffer for addresses
+ * @param[out]	addr_count	Number of addresses written into the list
+ *
+ * @return EOK
+ */
+int nic_unicast_get_mode_impl(ddf_fun_t *fun, nic_unicast_mode_t *mode,
+	size_t max_count, nic_address_t *addr_list, size_t *addr_count)
+{
+	nic_t *nic_data = (nic_t *) fun->driver_data;
+	fibril_rwlock_read_lock(&nic_data->rxc_lock);
+	nic_rxc_unicast_get_mode(&nic_data->rx_control, mode, max_count,
+		addr_list, addr_count);
+	fibril_rwlock_read_unlock(&nic_data->rxc_lock);
+	return EOK;
+}
+
+/**
+ * Default implementation of unicast_set_mode method.
+ *
+ * @param		fun
+ * @param[in]	mode		New operation mode
+ * @param[in]	addr_list	List of unicast addresses
+ * @param[in]	addr_count	Number of addresses in the list
+ *
+ * @return EOK
+ * @return EINVAL
+ * @return ENOTSUP
+ * @return ENOMEM
+ */
+int nic_unicast_set_mode_impl(ddf_fun_t *fun,
+	nic_unicast_mode_t mode, const nic_address_t *addr_list, size_t addr_count)
+{
+	assert((addr_count == 0 && addr_list == NULL)
+		|| (addr_count != 0 && addr_list != NULL));
+	size_t i;
+	for (i = 0; i < addr_count; ++i) {
+		if (addr_list[i].address[0] & 1)
+			return EINVAL;
+	}
+
+	nic_t *nic_data = (nic_t *) fun->driver_data;
+	fibril_rwlock_write_lock(&nic_data->rxc_lock);
+	int rc = ENOTSUP;
+	if (nic_data->on_unicast_mode_change) {
+		rc = nic_data->on_unicast_mode_change(nic_data,
+			mode, addr_list, addr_count);
+	}
+	if (rc == EOK) {
+		rc = nic_rxc_unicast_set_mode(&nic_data->rx_control, mode,
+			addr_list, addr_count);
+		/* After changing the mode the addr db gets cleared, therefore we have
+		 * to reinsert also the physical address of NIC.
+		 */
+		nic_rxc_set_addr(&nic_data->rx_control, NULL, &nic_data->mac);
+	}
+	fibril_rwlock_write_unlock(&nic_data->rxc_lock);
+	return rc;
+}
+
+
+/**
+ * Default implementation of multicast_get_mode method.
+ *
+ * @param		fun
+ * @param[out]	mode		Current operation mode
+ * @param[in]	max_count	Max number of addresses that can be written into the
+ * 							buffer (addr_list).
+ * @param[out]	addr_list	Buffer for addresses
+ * @param[out]	addr_count	Number of addresses written into the list
+ *
+ * @return EOK
+ */
+int nic_multicast_get_mode_impl(ddf_fun_t *fun, nic_multicast_mode_t *mode,
+	size_t max_count, nic_address_t *addr_list, size_t *addr_count)
+{
+	nic_t *nic_data = (nic_t *) fun->driver_data;
+	fibril_rwlock_read_lock(&nic_data->rxc_lock);
+	nic_rxc_multicast_get_mode(&nic_data->rx_control, mode, max_count,
+		addr_list, addr_count);
+	fibril_rwlock_read_unlock(&nic_data->rxc_lock);
+	return EOK;
+}
+
+/**
+ * Default implementation of multicast_set_mode method.
+ *
+ * @param		fun
+ * @param[in]	mode		New operation mode
+ * @param[in]	addr_list	List of multicast addresses
+ * @param[in]	addr_count	Number of addresses in the list
+ *
+ * @return EOK
+ * @return EINVAL
+ * @return ENOTSUP
+ * @return ENOMEM
+ */
+int nic_multicast_set_mode_impl(ddf_fun_t *fun,	nic_multicast_mode_t mode,
+	const nic_address_t *addr_list, size_t addr_count)
+{
+	assert((addr_count == 0 && addr_list == NULL)
+		|| (addr_count != 0 && addr_list != NULL));
+	size_t i;
+	for (i = 0; i < addr_count; ++i) {
+		if (!(addr_list[i].address[0] & 1))
+			return EINVAL;
+	}
+
+	nic_t *nic_data = (nic_t *) fun->dev->driver_data;
+	fibril_rwlock_write_lock(&nic_data->rxc_lock);
+	int rc = ENOTSUP;
+	if (nic_data->on_multicast_mode_change) {
+		rc = nic_data->on_multicast_mode_change(nic_data, mode, addr_list, addr_count);
+	}
+	if (rc == EOK) {
+		rc = nic_rxc_multicast_set_mode(&nic_data->rx_control, mode,
+			addr_list, addr_count);
+	}
+	fibril_rwlock_write_unlock(&nic_data->rxc_lock);
+	return rc;
+}
+
+/**
+ * Default implementation of broadcast_get_mode method.
+ *
+ * @param		fun
+ * @param[out]	mode		Current operation mode
+ *
+ * @return EOK
+ */
+int nic_broadcast_get_mode_impl(ddf_fun_t *fun, nic_broadcast_mode_t *mode)
+{
+	nic_t *nic_data = (nic_t *) fun->driver_data;
+	fibril_rwlock_read_lock(&nic_data->rxc_lock);
+	nic_rxc_broadcast_get_mode(&nic_data->rx_control, mode);
+	fibril_rwlock_read_unlock(&nic_data->rxc_lock);
+	return EOK;
+}
+
+/**
+ * Default implementation of broadcast_set_mode method.
+ *
+ * @param		fun
+ * @param[in]	mode		New operation mode
+ *
+ * @return EOK
+ * @return EINVAL
+ * @return ENOTSUP
+ * @return ENOMEM
+ */
+int nic_broadcast_set_mode_impl(ddf_fun_t *fun, nic_broadcast_mode_t mode)
+{
+	nic_t *nic_data = (nic_t *) fun->driver_data;
+	fibril_rwlock_write_lock(&nic_data->rxc_lock);
+	int rc = ENOTSUP;
+	if (nic_data->on_broadcast_mode_change) {
+		rc = nic_data->on_broadcast_mode_change(nic_data, mode);
+	}
+	if (rc == EOK) {
+		rc = nic_rxc_broadcast_set_mode(&nic_data->rx_control, mode);
+	}
+	fibril_rwlock_write_unlock(&nic_data->rxc_lock);
+	return rc;
+}
+
+/**
+ * Default implementation of blocked_sources_get method.
+ *
+ * @param		fun
+ * @param[in]	max_count	Max number of addresses that can be written into the
+ * 							buffer (addr_list).
+ * @param[out]	addr_list	Buffer for addresses
+ * @param[out]	addr_count	Number of addresses written into the list
+ *
+ * @return EOK
+ */
+int nic_blocked_sources_get_impl(ddf_fun_t *fun,
+	size_t max_count, nic_address_t *addr_list, size_t *addr_count)
+{
+	nic_t *nic_data = (nic_t *) fun->driver_data;
+	fibril_rwlock_read_lock(&nic_data->rxc_lock);
+	nic_rxc_blocked_sources_get(&nic_data->rx_control,
+		max_count, addr_list, addr_count);
+	fibril_rwlock_read_unlock(&nic_data->rxc_lock);
+	return EOK;
+}
+
+/**
+ * Default implementation of blocked_sources_set method.
+ *
+ * @param		fun
+ * @param[in]	addr_list	List of blocked addresses
+ * @param[in]	addr_count	Number of addresses in the list
+ *
+ * @return EOK
+ * @return EINVAL
+ * @return ENOTSUP
+ * @return ENOMEM
+ */
+int nic_blocked_sources_set_impl(ddf_fun_t *fun,
+	const nic_address_t *addr_list, size_t addr_count)
+{
+	nic_t *nic_data = (nic_t *) fun->driver_data;
+	fibril_rwlock_write_lock(&nic_data->rxc_lock);
+	if (nic_data->on_blocked_sources_change) {
+		nic_data->on_blocked_sources_change(nic_data, addr_list, addr_count);
+	}
+	int rc = nic_rxc_blocked_sources_set(&nic_data->rx_control,
+		addr_list, addr_count);
+	fibril_rwlock_write_unlock(&nic_data->rxc_lock);
+	return rc;
+}
+
+/**
+ * Default implementation of vlan_get_mask method.
+ *
+ * @param		fun
+ * @param[out]	mask	Current VLAN mask
+ *
+ * @return EOK
+ * @return ENOENT	If the mask is not set
+ */
+int nic_vlan_get_mask_impl(ddf_fun_t *fun, nic_vlan_mask_t *mask)
+{
+	nic_t *nic_data = (nic_t *) fun->driver_data;
+	fibril_rwlock_read_lock(&nic_data->rxc_lock);
+	int rc = nic_rxc_vlan_get_mask(&nic_data->rx_control, mask);
+	fibril_rwlock_read_unlock(&nic_data->rxc_lock);
+	return rc;
+}
+
+/**
+ * Default implementation of vlan_set_mask method.
+ *
+ * @param		fun
+ * @param[in]	mask	The new VLAN mask
+ *
+ * @return EOK
+ * @return ENOMEM
+ */
+int nic_vlan_set_mask_impl(ddf_fun_t *fun, const nic_vlan_mask_t *mask)
+{
+	nic_t *nic_data = (nic_t *) fun->driver_data;
+	fibril_rwlock_write_lock(&nic_data->rxc_lock);
+	int rc = nic_rxc_vlan_set_mask(&nic_data->rx_control, mask);
+	if (rc == EOK && nic_data->on_vlan_mask_change) {
+		nic_data->on_vlan_mask_change(nic_data, mask);
+	}
+	fibril_rwlock_write_unlock(&nic_data->rxc_lock);
+	return rc;
+}
+
+/**
+ * Default implementation of the wol_virtue_add method.
+ * Create a new WOL virtue.
+ *
+ * @param[in]	fun
+ * @param[in]	type		Type of the virtue
+ * @param[in]	data		Data required for this virtue (depends on type)
+ * @param[in]	length		Length of the data
+ * @param[out]	filter		Identifier of the new virtue
+ *
+ * @return EOK		If the operation was successfully completed
+ * @return EINVAL	If virtue type is not supported or the data are invalid
+ * @return ELIMIT	If the driver does not allow to create more virtues
+ * @return ENOMEM	If there was not enough memory to complete the operation
+ */
+int nic_wol_virtue_add_impl(ddf_fun_t *fun, nic_wv_type_t type,
+	const void *data, size_t length, nic_wv_id_t *new_id)
+{
+	nic_t *nic_data = (nic_t *) fun->driver_data;
+	if (nic_data->on_wol_virtue_add == NULL
+		|| nic_data->on_wol_virtue_remove == NULL) {
+		return ENOTSUP;
+	}
+	if (type == NIC_WV_NONE || type >= NIC_WV_MAX) {
+		return EINVAL;
+	}
+	if (nic_wol_virtues_verify(type, data, length) != EOK) {
+		return EINVAL;
+	}
+	nic_wol_virtue_t *virtue = malloc(sizeof (nic_wol_virtue_t));
+	if (virtue == NULL) {
+		return ENOMEM;
+	}
+	bzero(virtue, sizeof (nic_wol_virtue_t));
+	if (length != 0) {
+		virtue->data = malloc(length);
+		if (virtue->data == NULL) {
+			free(virtue);
+			return ENOMEM;
+		}
+		memcpy((void *) virtue->data, data, length);
+	}
+	virtue->type = type;
+	virtue->length = length;
+
+	fibril_rwlock_write_lock(&nic_data->wv_lock);
+	/* Check if we haven't reached the maximum */
+	if (nic_data->wol_virtues.caps_max[type] < 0) {
+		fibril_rwlock_write_unlock(&nic_data->wv_lock);
+		return EINVAL;
+	}
+	if ((int) nic_data->wol_virtues.lists_sizes[type] >=
+		nic_data->wol_virtues.caps_max[type]) {
+		fibril_rwlock_write_unlock(&nic_data->wv_lock);
+		return ELIMIT;
+	}
+	/* Call the user-defined add callback */
+	int rc = nic_data->on_wol_virtue_add(nic_data, virtue);
+	if (rc != EOK) {
+		free(virtue->data);
+		free(virtue);
+		fibril_rwlock_write_unlock(&nic_data->wv_lock);
+		return rc;
+	}
+	rc = nic_wol_virtues_add(&nic_data->wol_virtues, virtue);
+	if (rc != EOK) {
+		/* If the adding fails, call user-defined remove callback */
+		nic_data->on_wol_virtue_remove(nic_data, virtue);
+		fibril_rwlock_write_unlock(&nic_data->wv_lock);
+		free(virtue->data);
+		free(virtue);
+		return rc;
+	} else {
+		*new_id = virtue->id;
+		fibril_rwlock_write_unlock(&nic_data->wv_lock);
+	}
+	return EOK;
+}
+
+/**
+ * Default implementation of the wol_virtue_remove method.
+ * Destroys the WOL virtue.
+ *
+ * @param[in] fun
+ * @param[in] id	WOL virtue identification
+ *
+ * @return EOK		If the operation was successfully completed
+ * @return ENOTSUP	If the function is not supported by the driver or device
+ * @return ENOENT	If the virtue identifier is not valid.
+ */
+int nic_wol_virtue_remove_impl(ddf_fun_t *fun, nic_wv_id_t id)
+{
+	nic_t *nic_data = (nic_t *) fun->driver_data;
+	if (nic_data->on_wol_virtue_add == NULL
+		|| nic_data->on_wol_virtue_remove == NULL) {
+		return ENOTSUP;
+	}
+	fibril_rwlock_write_lock(&nic_data->wv_lock);
+	nic_wol_virtue_t *virtue =
+		nic_wol_virtues_remove(&nic_data->wol_virtues, id);
+	if (virtue == NULL) {
+		fibril_rwlock_write_unlock(&nic_data->wv_lock);
+		return ENOENT;
+	}
+	/* The event handler is called after the filter was removed */
+	nic_data->on_wol_virtue_remove(nic_data, virtue);
+	fibril_rwlock_write_unlock(&nic_data->wv_lock);
+	free(virtue->data);
+	free(virtue);
+	return EOK;
+}
+
+/**
+ * Default implementation of the wol_virtue_probe method.
+ * Queries the type and data of the virtue.
+ *
+ * @param[in]	fun
+ * @param[in]	id		Virtue identifier
+ * @param[out]	type		Type of the virtue. Can be NULL.
+ * @param[out]	data		Data used when the virtue was created. Can be NULL.
+ * @param[out]	length		Length of the data. Can be NULL.
+ *
+ * @return EOK		If the operation was successfully completed
+ * @return ENOENT	If the virtue identifier is not valid.
+ * @return ENOMEM	If there was not enough memory to complete the operation
+ */
+int nic_wol_virtue_probe_impl(ddf_fun_t *fun, nic_wv_id_t id,
+	nic_wv_type_t *type, size_t max_length, void *data, size_t *length)
+{
+	nic_t *nic_data = (nic_t *) fun->driver_data;
+	fibril_rwlock_read_lock(&nic_data->wv_lock);
+	const nic_wol_virtue_t *virtue =
+			nic_wol_virtues_find(&nic_data->wol_virtues, id);
+	if (virtue == NULL) {
+		*type = NIC_WV_NONE;
+		*length = 0;
+		fibril_rwlock_read_unlock(&nic_data->wv_lock);
+		return ENOENT;
+	} else {
+		*type = virtue->type;
+		if (max_length > virtue->length) {
+			max_length = virtue->length;
+		}
+		memcpy(data, virtue->data, max_length);
+		*length = virtue->length;
+		fibril_rwlock_read_unlock(&nic_data->wv_lock);
+		return EOK;
+	}
+}
+
+/**
+ * Default implementation of the wol_virtue_list method.
+ * List filters of the specified type. If NIC_WV_NONE is the type, it lists all
+ * filters.
+ *
+ * @param[in]	fun
+ * @param[in]	type	Type of the virtues
+ * @param[out]	virtues	Vector of virtue ID's.
+ * @param[out]	count	Length of the data. Can be NULL.
+ *
+ * @return EOK		If the operation was successfully completed
+ * @return ENOENT	If the filter identification is not valid.
+ * @return ENOMEM	If there was not enough memory to complete the operation
+ */
+int nic_wol_virtue_list_impl(ddf_fun_t *fun, nic_wv_type_t type,
+	size_t max_count, nic_wv_id_t *id_list, size_t *id_count)
+{
+	nic_t *nic_data = (nic_t *) fun->driver_data;
+	fibril_rwlock_read_lock(&nic_data->wv_lock);
+	int rc = nic_wol_virtues_list(&nic_data->wol_virtues, type,
+		max_count, id_list, id_count);
+	fibril_rwlock_read_unlock(&nic_data->wv_lock);
+	return rc;
+}
+
+/**
+ * Default implementation of the wol_virtue_get_caps method.
+ * Queries for the current capabilities for some type of filter.
+ *
+ * @param[in]	fun
+ * @param[in]	type	Type of the virtues
+ * @param[out]	count	Number of virtues of this type that can be currently set
+ *
+ * @return EOK		If the operation was successfully completed
+  */
+int nic_wol_virtue_get_caps_impl(ddf_fun_t *fun, nic_wv_type_t type, int *count)
+{
+	nic_t *nic_data = (nic_t *) fun->driver_data;
+	fibril_rwlock_read_lock(&nic_data->wv_lock);
+	*count = nic_data->wol_virtues.caps_max[type]
+	    - (int) nic_data->wol_virtues.lists_sizes[type];
+	fibril_rwlock_read_unlock(&nic_data->wv_lock);
+	return EOK;
+}
+
+/**
+ * Default implementation of the poll_get_mode method.
+ * Queries the current interrupt/poll mode of the NIC
+ *
+ * @param[in]	fun
+ * @param[out]	mode		Current poll mode
+ * @param[out]	period		Period used in periodic polling. Can be NULL.
+ *
+ * @return EOK		If the operation was successfully completed
+ * @return ENOTSUP	This function is not supported.
+ * @return EPARTY	Error in communication protocol
+ */
+int nic_poll_get_mode_impl(ddf_fun_t *fun,
+	nic_poll_mode_t *mode, struct timeval *period)
+{
+	nic_t *nic_data = (nic_t *) fun->driver_data;
+	fibril_rwlock_read_lock(&nic_data->main_lock);
+	*mode = nic_data->poll_mode;
+	memcpy(period, &nic_data->poll_period, sizeof (struct timeval));
+	fibril_rwlock_read_unlock(&nic_data->main_lock);
+	return EOK;
+}
+
+/**
+ * Default implementation of the poll_set_mode_impl method.
+ * Sets the interrupt/poll mode of the NIC.
+ *
+ * @param[in]	fun
+ * @param[in]	mode		The new poll mode
+ * @param[in]	period		Period used in periodic polling. Can be NULL.
+ *
+ * @return EOK		If the operation was successfully completed
+ * @return ENOTSUP	This operation is not supported.
+ * @return EPARTY	Error in communication protocol
+ */
+int nic_poll_set_mode_impl(ddf_fun_t *fun,
+	nic_poll_mode_t mode, const struct timeval *period)
+{
+	nic_t *nic_data = (nic_t *) fun->driver_data;
+	/* If the driver does not implement the poll mode change handler it cannot
+	 * switch off interrupts and this is not supported. */
+	if (nic_data->on_poll_mode_change == NULL)
+		return ENOTSUP;
+
+	if ((mode == NIC_POLL_ON_DEMAND) && nic_data->on_poll_request == NULL)
+		return ENOTSUP;
+
+	if (mode == NIC_POLL_PERIODIC || mode == NIC_POLL_SOFTWARE_PERIODIC) {
+		if (period == NULL)
+			return EINVAL;
+		if (period->tv_sec == 0 && period->tv_usec == 0)
+			return EINVAL;
+		if (period->tv_sec < 0 || period->tv_usec < 0)
+			return EINVAL;
+	}
+	fibril_rwlock_write_lock(&nic_data->main_lock);
+	int rc = nic_data->on_poll_mode_change(nic_data, mode, period);
+	assert(rc == EOK || rc == ENOTSUP || rc == EINVAL);
+	if (rc == ENOTSUP && (nic_data->on_poll_request != NULL) && 
+	    (mode == NIC_POLL_PERIODIC || mode == NIC_POLL_SOFTWARE_PERIODIC) ) {
+
+		rc = nic_data->on_poll_mode_change(nic_data, NIC_POLL_ON_DEMAND, NULL);
+		assert(rc == EOK || rc == ENOTSUP);
+		if (rc == EOK) 
+			nic_sw_period_start(nic_data);
+	}
+	if (rc == EOK) {
+		nic_data->poll_mode = mode;
+		if (period)
+			nic_data->poll_period = *period;
+	}
+	fibril_rwlock_write_unlock(&nic_data->main_lock);
+	return rc;
+}
+
+/**
+ * Default implementation of the poll_now method.
+ * Wrapper for the actual poll implementation.
+ *
+ * @param[in]	fun
+ *
+ * @return EOK		If the NIC was polled
+ * @return ENOTSUP	If the function is not supported
+ * @return EINVAL	If the NIC is not in state where it allows on demand polling
+ */
+int nic_poll_now_impl(ddf_fun_t *fun) {
+	nic_t *nic_data = (nic_t *) fun->driver_data;
+	fibril_rwlock_read_lock(&nic_data->main_lock);
+	if (nic_data->poll_mode != NIC_POLL_ON_DEMAND) {
+		fibril_rwlock_read_unlock(&nic_data->main_lock);
+		return EINVAL;
+	}
+	if (nic_data->on_poll_request != NULL) {
+		nic_data->on_poll_request(nic_data);
+		fibril_rwlock_read_unlock(&nic_data->main_lock);
+		return EOK;
+	} else {
+		fibril_rwlock_read_unlock(&nic_data->main_lock);
+		return ENOTSUP;
+	}
+}
+
+/** Default implementation of the device_added method
+ *
+ * Just calls nic_ready.
+ *
+ * @param dev
+ *
+ */
+void nic_device_added_impl(ddf_dev_t *dev)
+{
+	nic_ready((nic_t *) dev->driver_data);
+}
+
+/**
+ * Default handler for unknown methods (outside of the NIC interface).
+ * Logs a warning message and returns ENOTSUP to the caller.
+ *
+ * @param fun		The DDF function where the method should be called.
+ * @param callid	IPC call identifier
+ * @param call		IPC call data
+ */
+void nic_default_handler_impl(ddf_fun_t *fun, ipc_callid_t callid,
+    ipc_call_t *call)
+{
+	async_answer_0(callid, ENOTSUP);
+}
+
+/**
+ * Default (empty) OPEN function implementation.
+ *
+ * @param fun	The DDF function
+ *
+ * @return EOK always.
+ */
+int nic_open_impl(ddf_fun_t *fun)
+{
+	return EOK;
+}
+
+/**
+ * Default (empty) OPEN function implementation.
+ *
+ * @param fun	The DDF function
+ */
+void nic_close_impl(ddf_fun_t *fun)
+{
+}
+
+/** @}
+ */
Index: uspace/lib/nic/src/nic_rx_control.c
===================================================================
--- uspace/lib/nic/src/nic_rx_control.c	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
+++ uspace/lib/nic/src/nic_rx_control.c	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -0,0 +1,539 @@
+/*
+ * Copyright (c) 2011 Radim Vansa
+ * 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 libnic
+ * @{
+ */
+/**
+ * @file
+ * @brief Incoming packets (frames) filtering functions
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <bool.h>
+#include <errno.h>
+#include <net/device.h>
+#include <net_checksum.h>
+#include <packet_client.h>
+#include "nic_rx_control.h"
+
+/**
+ * Initializes the receive control structure
+ *
+ * @param rxc
+ *
+ * @return EOK		On success
+ * @return ENOMEM	On not enough memory
+ * @return EINVAL	Internal error, should not happen
+ */
+int nic_rxc_init(nic_rxc_t *rxc)
+{
+	bzero(rxc, sizeof (nic_rxc_t));
+	int rc;
+	rc = nic_addr_db_init(&rxc->blocked_sources, ETH_ADDR);
+	if (rc != EOK) {
+		return rc;
+	}
+	rc = nic_addr_db_init(&rxc->unicast_addrs, ETH_ADDR);
+	if (rc != EOK) {
+		return rc;
+	}
+	rc = nic_addr_db_init(&rxc->multicast_addrs, ETH_ADDR);
+	if (rc != EOK) {
+		return rc;
+	}
+	rxc->block_sources = false;
+	rxc->unicast_mode = NIC_UNICAST_DEFAULT;
+	rxc->multicast_mode = NIC_MULTICAST_BLOCKED;
+	rxc->broadcast_mode = NIC_BROADCAST_ACCEPTED;
+
+	/* Default NIC behavior */
+	rxc->unicast_exact = true;
+	rxc->multicast_exact = false;
+	rxc->vlan_exact = true;
+	return EOK;
+}
+
+/** Reinitialize the structure.
+ *
+ * @param filters
+ */
+int nic_rxc_clear(nic_rxc_t *rxc)
+{
+	nic_addr_db_destroy(&rxc->unicast_addrs);
+	nic_addr_db_destroy(&rxc->multicast_addrs);
+	nic_addr_db_destroy(&rxc->blocked_sources);
+	return nic_rxc_init(rxc);
+}
+
+/** Set the NIC's address that should be used as the default address during
+ * the checks.
+ *
+ * @param rxc
+ * @param prev_addr Previously used default address. Can be NULL
+ *                  if this is the first call after filters' initialization.
+ * @param curr_addr The new default address.
+ *
+ * @return EOK On success
+ *
+ */
+int nic_rxc_set_addr(nic_rxc_t *rxc, const nic_address_t *prev_addr,
+    const nic_address_t *curr_addr)
+{
+	if (prev_addr != NULL) {
+		int rc = nic_addr_db_remove(&rxc->unicast_addrs,
+		    (const uint8_t *) &prev_addr->address);
+		if (rc != EOK)
+			return rc;
+	}
+	
+	return nic_addr_db_insert(&rxc->unicast_addrs,
+	    (const uint8_t *) &curr_addr->address);
+}
+
+/* Helper structure */
+typedef struct {
+	size_t max_count;
+	nic_address_t *address_list;
+	size_t address_count;
+} nic_rxc_add_addr_t;
+
+/** Helper function */
+static void nic_rxc_add_addr(const uint8_t *addr, void *arg)
+{
+	nic_rxc_add_addr_t *hs = (nic_rxc_add_addr_t *) arg;
+	if (hs->address_count < hs->max_count && hs->address_list != NULL) {
+		memcpy(&hs->address_list[hs->address_count].address, addr, ETH_ADDR);
+	}
+	hs->address_count++;
+}
+
+/**
+ * Queries the current mode of unicast frames receiving.
+ *
+ * @param rxc
+ * @param mode			The new unicast mode
+ * @param max_count		Max number of addresses that can be written into the
+ * 						address_list.
+ * @param address_list	List of MAC addresses or NULL.
+ * @param address_count Number of accepted addresses (can be > max_count)
+ */
+void nic_rxc_unicast_get_mode(const nic_rxc_t *rxc, nic_unicast_mode_t *mode,
+	size_t max_count, nic_address_t *address_list, size_t *address_count)
+{
+	*mode = rxc->unicast_mode;
+	if (rxc->unicast_mode == NIC_UNICAST_LIST) {
+		nic_rxc_add_addr_t hs = {
+			.max_count = max_count,
+			.address_list = address_list,
+			.address_count = 0
+		};
+		nic_addr_db_foreach(&rxc->unicast_addrs, nic_rxc_add_addr, &hs);
+		if (address_count) {
+			*address_count = hs.address_count;
+		}
+	}
+}
+
+/**
+ * Sets the current mode of unicast frames receiving.
+ *
+ * @param rxc
+ * @param mode			The current unicast mode
+ * @param address_list	List of MAC addresses or NULL.
+ * @param address_count Number of addresses in the list
+ *
+ * @return EOK		On success
+ * @return EINVAL	If any of the MAC addresses is not a unicast address.
+ * @return ENOMEM	If there was not enough memory
+ */
+int nic_rxc_unicast_set_mode(nic_rxc_t *rxc, nic_unicast_mode_t mode,
+	const nic_address_t *address_list, size_t address_count)
+{
+	if (mode == NIC_UNICAST_LIST && address_list == NULL) {
+		return EINVAL;
+	} else if (mode != NIC_UNICAST_LIST && address_list != NULL) {
+		return EINVAL;
+	}
+
+	if (rxc->unicast_mode == NIC_UNICAST_LIST) {
+		nic_addr_db_clear(&rxc->unicast_addrs);
+	}
+	rxc->unicast_mode = mode;
+	size_t i;
+	for (i = 0; i < address_count; ++i) {
+		int rc = nic_addr_db_insert(&rxc->unicast_addrs,
+			(const uint8_t *) &address_list[i].address);
+		if (rc == ENOMEM) {
+			return ENOMEM;
+		}
+	}
+	return EOK;
+}
+
+/**
+ * Queries the current mode of multicast frames receiving.
+ *
+ * @param rxc
+ * @param mode			The current multicast mode
+ * @param max_count		Max number of addresses that can be written into the
+ * 						address_list.
+ * @param address_list	List of MAC addresses or NULL.
+ * @param address_count Number of accepted addresses (can be > max_count)
+ */
+void nic_rxc_multicast_get_mode(const nic_rxc_t *rxc,
+	nic_multicast_mode_t *mode, size_t max_count, nic_address_t *address_list,
+	size_t *address_count)
+{
+	*mode = rxc->multicast_mode;
+	if (rxc->multicast_mode == NIC_MULTICAST_LIST) {
+		nic_rxc_add_addr_t hs = {
+			.max_count = max_count,
+			.address_list = address_list,
+			.address_count = 0
+		};
+		nic_addr_db_foreach(&rxc->multicast_addrs, nic_rxc_add_addr, &hs);
+		if (address_count) {
+			*address_count = hs.address_count;
+		}
+	}
+}
+
+/**
+ * Sets the current mode of multicast frames receiving.
+ *
+ * @param rxc
+ * @param mode			The new multicast mode
+ * @param address_list	List of MAC addresses or NULL.
+ * @param address_count Number of addresses in the list
+ *
+ * @return EOK		On success
+ * @return EINVAL	If any of the MAC addresses is not a multicast address.
+ * @return ENOMEM	If there was not enough memory
+ */
+int nic_rxc_multicast_set_mode(nic_rxc_t *rxc, nic_multicast_mode_t mode,
+	const nic_address_t *address_list, size_t address_count)
+{
+	if (mode == NIC_MULTICAST_LIST && address_list == NULL)
+		return EINVAL;
+	else if (mode != NIC_MULTICAST_LIST && address_list != NULL)
+		return EINVAL;
+	
+	if (rxc->multicast_mode == NIC_MULTICAST_LIST)
+		nic_addr_db_clear(&rxc->multicast_addrs);
+	
+	rxc->multicast_mode = mode;
+	size_t i;
+	for (i = 0; i < address_count; ++i) {
+		int rc = nic_addr_db_insert(&rxc->multicast_addrs,
+			(const uint8_t *)&address_list[i].address);
+		if (rc == ENOMEM) {
+			return ENOMEM;
+		}
+	}
+	return EOK;
+}
+
+/**
+ * Queries the current mode of broadcast frames receiving.
+ *
+ * @param rxc
+ * @param mode			The new broadcast mode
+ */
+void nic_rxc_broadcast_get_mode(const nic_rxc_t *rxc, nic_broadcast_mode_t *mode)
+{
+	*mode = rxc->broadcast_mode;
+}
+
+/**
+ * Sets the current mode of broadcast frames receiving.
+ *
+ * @param rxc
+ * @param mode			The new broadcast mode
+ *
+ * @return EOK		On success
+ */
+int nic_rxc_broadcast_set_mode(nic_rxc_t *rxc, nic_broadcast_mode_t mode)
+{
+	rxc->broadcast_mode = mode;
+	return EOK;
+}
+
+/**
+ * Queries the current blocked source addresses.
+ *
+ * @param rxc
+ * @param max_count		Max number of addresses that can be written into the
+ * 						address_list.
+ * @param address_list	List of MAC addresses or NULL.
+ * @param address_count Number of blocked addresses (can be > max_count)
+ */
+void nic_rxc_blocked_sources_get(const nic_rxc_t *rxc,
+	size_t max_count, nic_address_t *address_list, size_t *address_count)
+{
+	nic_rxc_add_addr_t hs = {
+		.max_count = max_count,
+		.address_list = address_list,
+		.address_count = 0
+	};
+	nic_addr_db_foreach(&rxc->blocked_sources, nic_rxc_add_addr, &hs);
+	if (address_count) {
+		*address_count = hs.address_count;
+	}
+}
+
+/**
+ * Clears the currently blocked addresses and sets the addresses contained in
+ * the list as the set of blocked source addresses (no frame with this source
+ * address will be received). Duplicated addresses are ignored.
+ *
+ * @param rxc
+ * @param address_list	List of the blocked addresses. Can be NULL.
+ * @param address_count Number of addresses in the list
+ *
+ * @return EOK		On success
+ * @return ENOMEM	If there was not enough memory
+ */
+int nic_rxc_blocked_sources_set(nic_rxc_t *rxc,
+	const nic_address_t *address_list, size_t address_count)
+{
+	assert((address_count == 0 && address_list == NULL)
+		|| (address_count != 0 && address_list != NULL));
+
+	nic_addr_db_clear(&rxc->blocked_sources);
+	rxc->block_sources = (address_count != 0);
+	size_t i;
+	for (i = 0; i < address_count; ++i) {
+		int rc = nic_addr_db_insert(&rxc->blocked_sources,
+			(const uint8_t *) &address_list[i].address);
+		if (rc == ENOMEM) {
+			return ENOMEM;
+		}
+	}
+	return EOK;
+}
+
+/**
+ * Query mask used for filtering according to the VLAN tags.
+ *
+ * @param rxc
+ * @param mask		Must be 512 bytes long
+ *
+ * @return EOK
+ * @return ENOENT
+ */
+int nic_rxc_vlan_get_mask(const nic_rxc_t *rxc, nic_vlan_mask_t *mask)
+{
+	if (rxc->vlan_mask == NULL) {
+		return ENOENT;
+	}
+	memcpy(mask, rxc->vlan_mask, sizeof (nic_vlan_mask_t));
+	return EOK;
+}
+
+/**
+ * Set mask for filtering according to the VLAN tags.
+ *
+ * @param rxc
+ * @param mask		Must be 512 bytes long
+ *
+ * @return EOK
+ * @return ENOMEM
+ */
+int nic_rxc_vlan_set_mask(nic_rxc_t *rxc, const nic_vlan_mask_t *mask)
+{
+	if (mask == NULL) {
+		if (rxc->vlan_mask) {
+			free(rxc->vlan_mask);
+		}
+		rxc->vlan_mask = NULL;
+		return EOK;
+	}
+	if (!rxc->vlan_mask) {
+		rxc->vlan_mask = malloc(sizeof (nic_vlan_mask_t));
+		if (rxc->vlan_mask == NULL) {
+			return ENOMEM;
+		}
+	}
+	memcpy(rxc->vlan_mask, mask, sizeof (nic_vlan_mask_t));
+	return EOK;
+}
+
+
+/**
+ * Check if the frame passes through the receive control.
+ *
+ * @param rxc
+ * @param packet	The probed frame
+ *
+ * @return True if the frame passes, false if it does not
+ */
+int nic_rxc_check(const nic_rxc_t *rxc, const packet_t *packet,
+	nic_frame_type_t *frame_type)
+{
+	assert(frame_type != NULL);
+	uint8_t *dest_addr = (uint8_t *) packet + packet->data_start;
+	uint8_t *src_addr = dest_addr + ETH_ADDR;
+
+	if (dest_addr[0] & 1) {
+		/* Multicast or broadcast */
+		if (*(uint32_t *) dest_addr == 0xFFFFFFFF &&
+		    *(uint16_t *) (dest_addr + 4) == 0xFFFF) {
+			/* It is broadcast */
+			*frame_type = NIC_FRAME_BROADCAST;
+			if (rxc->broadcast_mode == NIC_BROADCAST_BLOCKED)
+				return false;
+		} else {
+			*frame_type = NIC_FRAME_MULTICAST;
+			/* In promiscuous mode the multicast_exact should be set to true */
+			if (!rxc->multicast_exact) {
+				if (rxc->multicast_mode == NIC_MULTICAST_BLOCKED)
+					return false;
+				else {
+					if (!nic_addr_db_contains(&rxc->multicast_addrs,
+					    dest_addr))
+						return false;
+				}
+			}
+		}
+	} else {
+		/* Unicast */
+		*frame_type = NIC_FRAME_UNICAST;
+		/* In promiscuous mode the unicast_exact should be set to true */
+		if (!rxc->unicast_exact) {
+			if (rxc->unicast_mode == NIC_UNICAST_BLOCKED)
+				return false;
+			else {
+				if (!nic_addr_db_contains(&rxc->unicast_addrs,
+				    dest_addr))
+					return false;
+			}
+		}
+	}
+	/* Blocked source addresses */
+	if (rxc->block_sources) {
+		if (nic_addr_db_contains(&rxc->blocked_sources, src_addr))
+			return false;
+	}
+	/* VLAN filtering */
+	if (!rxc->vlan_exact && rxc->vlan_mask != NULL) {
+		vlan_header_t *vlan_header = (vlan_header_t *)
+			((uint8_t *) packet + packet->data_start + 2 * ETH_ADDR);
+		if (vlan_header->tpid_upper == VLAN_TPID_UPPER &&
+			vlan_header->tpid_lower == VLAN_TPID_LOWER) {
+			int index = ((int) (vlan_header->vid_upper & 0xF) << 5) |
+			    (vlan_header->vid_lower >> 3);
+			if (!(rxc->vlan_mask->bitmap[index] &
+			    (1 << (vlan_header->vid_lower & 0x7))))
+				return false;
+		}
+	}
+	
+	return true;
+}
+
+/**
+ * Set information about current HW filtering.
+ *  1 ...	Only those frames we want to receive are passed through HW
+ *  0 ...	The HW filtering is imperfect
+ * -1 ...	Don't change the setting
+ * This function should be called only from the mode change event handler.
+ *
+ * @param	rxc
+ * @param	unicast_exact	Unicast frames
+ * @param	mcast_exact		Multicast frames
+ * @param	vlan_exact		VLAN tags
+ */
+void nic_rxc_hw_filtering(nic_rxc_t *rxc,
+	int unicast_exact, int multicast_exact, int vlan_exact)
+{
+	if (unicast_exact >= 0)
+		rxc->unicast_exact = unicast_exact;
+	if (multicast_exact >= 0)
+		rxc->multicast_exact = multicast_exact;
+	if (vlan_exact >= 0)
+		rxc->vlan_exact = vlan_exact;
+}
+
+/**
+ * Computes hash for the address list based on standard multicast address
+ * hashing.
+ *
+ * @param address_list
+ * @param count
+ *
+ * @return Multicast hash
+ *
+ * @see multicast_hash
+ */
+uint64_t nic_rxc_mcast_hash(const nic_address_t *address_list, size_t count)
+{
+	size_t i;
+	uint64_t hash = 0;
+	for (i = 0; i < count; ++i) {
+		hash |= multicast_hash(address_list[i].address);
+	}
+	return hash;
+}
+
+static void nic_rxc_hash_addr(const uint8_t *address, void *arg)
+{
+	*((uint64_t *) arg) |= multicast_hash(address);
+}
+
+/**
+ * Computes hash for multicast addresses currently set up in the RX multicast
+ * filtering. For promiscuous mode returns all ones, for blocking all zeroes.
+ * Can be called only from the on_*_change handler.
+ *
+ * @param rxc
+ *
+ * @return Multicast hash
+ *
+ * @see multicast_hash
+ */
+uint64_t nic_rxc_multicast_get_hash(const nic_rxc_t *rxc)
+{
+	switch (rxc->multicast_mode) {
+	case NIC_MULTICAST_UNKNOWN:
+	case NIC_MULTICAST_BLOCKED:
+		return 0;
+	case NIC_MULTICAST_LIST:
+		break;
+	case NIC_MULTICAST_PROMISC:
+		return ~ (uint64_t) 0;
+	}
+	uint64_t hash;
+	nic_addr_db_foreach(&rxc->multicast_addrs, nic_rxc_hash_addr, &hash);
+	return hash;
+}
+
+/** @}
+ */
Index: uspace/lib/nic/src/nic_wol_virtues.c
===================================================================
--- uspace/lib/nic/src/nic_wol_virtues.c	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
+++ uspace/lib/nic/src/nic_wol_virtues.c	(revision 7a68fe54c12652c8610c2dd4dc3a6726a771a930)
@@ -0,0 +1,296 @@
+/*
+ * Copyright (c) 2011 Radim Vansa
+ * 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 libnic
+ * @{
+ */
+/**
+ * @file
+ * @brief Wake-on-LAN support
+ */
+
+#include "nic_wol_virtues.h"
+#include <assert.h>
+
+#define NIC_WV_HASH_COUNT 32
+
+/**
+ * Hash table helper function
+ */
+static int nic_wv_compare(unsigned long key[], hash_count_t keys,
+	link_t *item)
+{
+	nic_wol_virtue_t *virtue = (nic_wol_virtue_t *) item;
+	return (virtue->id == (nic_wv_id_t) key[0]);
+}
+
+/**
+ * Hash table helper function
+ */
+static void nic_wv_rc(link_t *item)
+{
+}
+
+/**
+ * Hash table helper function
+ */
+static hash_index_t nic_wv_hash(unsigned long keys[])
+{
+	return keys[0] % NIC_WV_HASH_COUNT;
+}
+
+/**
+ * Initializes the WOL virtues structure
+ *
+ * @param wvs
+ *
+ * @return EOK		On success
+ * @return ENOMEM	On not enough memory
+ */
+int nic_wol_virtues_init(nic_wol_virtues_t *wvs)
+{
+	bzero(wvs, sizeof (nic_wol_virtues_t));
+	wvs->table_operations.compare = nic_wv_compare;
+	wvs->table_operations.hash = nic_wv_hash;
+	wvs->table_operations.remove_callback = nic_wv_rc;
+	if (!hash_table_create(&wvs->table, NIC_WV_HASH_COUNT, 1,
+		&wvs->table_operations)) {
+		return ENOMEM;
+	}
+	size_t i;
+	for (i = 0; i < NIC_WV_MAX; ++i) {
+		wvs->caps_max[i] = -1;
+	}
+	wvs->next_id = 0;
+	return EOK;
+}
+
+/**
+ * Reinitializes the structure, destroying all virtues. The next_id is not
+ * changed (some apps could still hold the filter IDs).
+ *
+ * @param wvs
+ */
+void nic_wol_virtues_clear(nic_wol_virtues_t *wvs)
+{
+	hash_table_clear(&wvs->table);
+	nic_wv_type_t type;
+	for (type = NIC_WV_NONE; type < NIC_WV_MAX; ++type) {
+		nic_wol_virtue_t *virtue = wvs->lists[type];
+		while (virtue != NULL) {
+			nic_wol_virtue_t *next = virtue->next;
+			free(virtue->data);
+			free(virtue);
+			virtue = next;
+		}
+		wvs->lists_sizes[type] = 0;
+	}
+}
+
+/**
+ * Verifies that the arguments for the WOL virtues are correct.
+ *
+ * @param type		Type of the virtue
+ * @param data		Data argument for the virtue
+ * @param length	Length of the data
+ *
+ * @return EOK		The arguments are correct
+ * @return EINVAL	The arguments are incorrect
+ * @return ENOTSUP	This type is unknown
+ */
+int nic_wol_virtues_verify(nic_wv_type_t type, const void *data, size_t length)
+{
+	switch (type) {
+	case NIC_WV_ARP_REQUEST:
+	case NIC_WV_BROADCAST:
+	case NIC_WV_LINK_CHANGE:
+		return EOK;
+	case NIC_WV_DESTINATION:
+		return length == sizeof (nic_address_t) ? EOK : EINVAL;
+	case NIC_WV_DIRECTED_IPV4:
+		return length == sizeof (nic_wv_ipv4_data_t) ? EOK : EINVAL;
+	case NIC_WV_DIRECTED_IPV6:
+		return length == sizeof (nic_wv_ipv6_data_t) ? EOK : EINVAL;
+	case NIC_WV_FULL_MATCH:
+		return length % 2 == 0 ? EOK : EINVAL;
+	case NIC_WV_MAGIC_PACKET:
+		return data == NULL || length == sizeof (nic_wv_magic_packet_data_t) ?
+			EOK : EINVAL;
+	default:
+		return ENOTSUP;
+	}
+}
+
+/**
+ * Adds the virtue to the list of known virtues, activating it.
+ *
+ * @param wvs
+ * @param virtue	The virtue structure
+ *
+ * @return EOK		On success
+ * @return ENOTSUP	If the virtue type is not supported
+ * @return EINVAL	If the virtue type is a single-filter and there's already
+ * 					a virtue of this type defined, or there is something wrong
+ * 					with the data
+ * @return ENOMEM	Not enough memory to activate the virtue
+ */
+int nic_wol_virtues_add(nic_wol_virtues_t *wvs, nic_wol_virtue_t *virtue)
+{
+	if (!nic_wv_is_multi(virtue->type) &&
+		wvs->lists[virtue->type] != NULL) {
+		return EINVAL;
+	}
+	do {
+		virtue->id = wvs->next_id++;
+	} while (NULL !=
+		hash_table_find(&wvs->table, (unsigned long *) &virtue->id));
+	hash_table_insert(&wvs->table,
+		(unsigned long *) &virtue->id, &virtue->item);
+	virtue->next = wvs->lists[virtue->type];
+	wvs->lists[virtue->type] = virtue;
+	wvs->lists_sizes[virtue->type]++;
+	return EOK;
+}
+
+/**
+ * Removes the virtue from the list of virtues, but NOT deallocating the
+ * nic_wol_virtue structure.
+ *
+ * @param wvs
+ * @param id	Identifier of the removed virtue
+ *
+ * @return Removed virtue structure or NULL if not found.
+ */
+nic_wol_virtue_t *nic_wol_virtues_remove(nic_wol_virtues_t *wvs, nic_wv_id_t id)
+{
+	nic_wol_virtue_t *virtue = (nic_wol_virtue_t *)
+		hash_table_find(&wvs->table, (unsigned long *) &id);
+	if (virtue == NULL) {
+		return NULL;
+	}
+
+	/* Remove from filter_table */
+	hash_table_remove(&wvs->table, (unsigned long *) &id, 1);
+
+	/* Remove from filter_types */
+	assert(wvs->lists[virtue->type] != NULL);
+	if (wvs->lists[virtue->type] == virtue) {
+		wvs->lists[virtue->type] = virtue->next;
+	} else {
+		nic_wol_virtue_t *wv = wvs->lists[virtue->type];
+		while (wv->next != virtue) {
+			wv = wv->next;
+			assert(wv != NULL);
+		}
+		wv->next = virtue->next;
+	}
+	wvs->lists_sizes[virtue->type]--;
+
+	virtue->next = NULL;
+	return virtue;
+}
+
+
+/**
+ * Searches the filters table for a filter with specified ID
+ *
+ * @param wvs
+ * @param id	Identifier of the searched virtue
+ *
+ * @return Requested filter or NULL if not found.
+ */
+const nic_wol_virtue_t *nic_wol_virtues_find(const nic_wol_virtues_t *wvs,
+	nic_wv_id_t id)
+{
+	/*
+	 * The hash_table_find cannot be const, because it would require the
+	 * returned link to be const as well. But in this case, when we're returning
+	 * constant virtue the retyping is correct.
+	 */
+	link_t *virtue = hash_table_find(
+		&((nic_wol_virtues_t *) wvs)->table, (unsigned long *) &id);
+	return (const nic_wol_virtue_t *) virtue;
+}
+
+/**
+ * Fill identifiers of current wol virtues of the specified type into the list.
+ * If the type is set to NIC_WV_NONE, all virtues are used.
+ *
+ * @param		wvs
+ * @param[in]	type		Type of the virtues or NIC_WV_NONE
+ * @param[out]	id_list		The new vector of filter IDs. Can be NULL.
+ * @param[out]	count		Number of IDs in the filter_list. Can be NULL.
+ *
+ * @return EOK		If it completes successfully
+ * @return EINVAL	If the filter type is invalid
+ */
+int nic_wol_virtues_list(const nic_wol_virtues_t *wvs, nic_wv_type_t type,
+	size_t max_count, nic_wv_id_t *id_list, size_t *id_count)
+{
+	size_t count = 0;
+	if (type == NIC_WV_NONE) {
+		size_t i;
+		for (i = NIC_WV_NONE; i < NIC_WV_MAX; ++i) {
+			if (id_list != NULL) {
+				nic_wol_virtue_t *virtue = wvs->lists[i];
+				while (virtue != NULL) {
+					if (count < max_count) {
+						id_list[count] = virtue->id;
+					}
+					++count;
+					virtue = virtue->next;
+				}
+			} else {
+				count += wvs->lists_sizes[i];
+			}
+		}
+	} else if (type >= NIC_WV_MAX) {
+		return EINVAL;
+	} else {
+		if (id_list != NULL) {
+			nic_wol_virtue_t *virtue = wvs->lists[type];
+			while (virtue != NULL) {
+				if (count < max_count) {
+					id_list[count] = virtue->id;
+				}
+				++count;
+				virtue = virtue->next;
+			}
+		} else {
+			count = wvs->lists_sizes[type];
+		}
+	}
+	if (id_count != NULL) {
+		*id_count = count;
+	}
+	return EOK;
+}
+
+/** @}
+ */
Index: uspace/lib/packet/Makefile
===================================================================
--- uspace/lib/packet/Makefile	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ 	(revision )
@@ -1,37 +1,0 @@
-#
-# Copyright (c) 2005 Martin Decky
-# Copyright (c) 2007 Jakub Jermar
-# 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.
-#
-
-USPACE_PREFIX = ../..
-EXTRA_CFLAGS = -Iinclude
-LIBRARY = libpacket
-
-SOURCES = \
-	generic/packet_server.c
-
-include $(USPACE_PREFIX)/Makefile.common
Index: uspace/lib/packet/generic/packet_server.c
===================================================================
--- uspace/lib/packet/generic/packet_server.c	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ 	(revision )
@@ -1,374 +1,0 @@
-/*
- * 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 libpacket
- *  @{
- */
-
-/** @file
- * Packet server implementation.
- */
-
-#include <packet_server.h>
-#include <align.h>
-#include <assert.h>
-#include <async.h>
-#include <errno.h>
-#include <fibril_synch.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <ipc/packet.h>
-#include <ipc/net.h>
-#include <net/packet.h>
-#include <net/packet_header.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 = FIBRIL_MUTEX_INITIALIZER(ps_globals.lock),
-	.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
-};
-
-/** 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(packet_t),
-	    packet->length - sizeof(packet_t));
-	
-	/* Clear the packet header */
-	packet->order = 0;
-	packet->metric = 0;
-	packet->previous = 0;
-	packet->next = 0;
-	packet->addr_len = 0;
-	packet->src_addr = sizeof(packet_t);
-	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 new packet of dimensions at least as given.
- *
- * @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.
- * @return		The packet of dimensions at least as given.
- * @return		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)
-{
-	packet_t *packet;
-	int rc;
-
-	assert(fibril_mutex_is_locked(&ps_globals.lock));
-
-	/* 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;
-	rc = pm_add(packet);
-	if (rc != EOK) {
-		munmap(packet, packet->length);
-		return NULL;
-	}
-	
-	return packet;
-}
-
-/** Return the packet of dimensions at least as given.
- *
- * Try to reuse free packets first.
- * Create a new packet aligned to the memory page size if none available.
- * Lock 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.
- * @return		The packet of dimensions at least as given.
- * @return		NULL if there is not enough memory left.
- */
-static packet_t *
-packet_get_local(size_t addr_len, size_t max_prefix, size_t max_content,
-    size_t max_suffix)
-{
-	size_t length = ALIGN_UP(sizeof(packet_t) + 2 * addr_len +
-	    max_prefix + max_content + max_suffix, PAGE_SIZE);
-	
-	fibril_mutex_lock(&ps_globals.lock);
-	
-	packet_t *packet;
-	unsigned int index;
-	
-	for (index = 0; index < FREE_QUEUES_COUNT; index++) {
-		if ((length > ps_globals.sizes[index]) &&
-		    (index < FREE_QUEUES_COUNT - 1))
-			continue;
-		
-		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);
-			
-			return packet;
-		}
-	}
-	
-	packet = packet_create(length, addr_len, max_prefix, max_content,
-	    max_suffix);
-	
-	fibril_mutex_unlock(&ps_globals.lock);
-	
-	return packet;
-}
-
-/** Release the packet and returns it to the appropriate free packet queue.
- *
- * @param[in] packet	The packet to be released.
- *
- */
-static void packet_release(packet_t *packet)
-{
-	int index;
-	int result;
-
-	assert(fibril_mutex_is_locked(&ps_globals.lock));
-
-	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.
- * @return		EOK on success.
- * @return		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;
-}
-
-/** Shares the packet memory block.
- * @param[in] packet	The packet to be shared.
- * @return		EOK on success.
- * @return		EINVAL if the packet is not valid.
- * @return		EINVAL if the calling module does not accept the memory.
- * @return		ENOMEM if the desired and actual sizes differ.
- * @return		Other error codes as defined for the
- *			async_share_in_finalize() function.
- */
-static int packet_reply(packet_t *packet)
-{
-	ipc_callid_t callid;
-	size_t size;
-
-	if (!packet_is_valid(packet))
-		return EINVAL;
-
-	if (!async_share_in_receive(&callid, &size)) {
-		async_answer_0(callid, EINVAL);
-		return EINVAL;
-	}
-
-	if (size != packet->length) {
-		async_answer_0(callid, ENOMEM);
-		return ENOMEM;
-	}
-	
-	return async_share_in_finalize(callid, packet,
-	    PROTO_READ | PROTO_WRITE);
-}
-
-/** Processes the packet server message.
- *
- * @param[in] callid	The message identifier.
- * @param[in] call	The message parameters.
- * @param[out] answer	The message answer parameters.
- * @param[out] answer_count The last parameter for the actual answer in the
- *			answer parameter.
- * @return		EOK on success.
- * @return		ENOMEM if there is not enough memory left.
- * @return		ENOENT if there is no such packet as in the packet
- *			message parameter.
- * @return		ENOTSUP if the message is not known.
- * @return		Other error codes as defined for the
- *			packet_release_wrapper() function.
- */
-int packet_server_message(ipc_callid_t callid, ipc_call_t *call, ipc_call_t *answer,
-    size_t *answer_count)
-{
-	packet_t *packet;
-	
-	if (!IPC_GET_IMETHOD(*call))
-		return EOK;
-	
-	*answer_count = 0;
-	switch (IPC_GET_IMETHOD(*call)) {
-	case NET_PACKET_CREATE_1:
-		packet = packet_get_local(DEFAULT_ADDR_LEN, DEFAULT_PREFIX,
-		    IPC_GET_CONTENT(*call), DEFAULT_SUFFIX);
-		if (!packet)
-			return ENOMEM;
-		*answer_count = 2;
-		IPC_SET_ARG1(*answer, (sysarg_t) packet->packet_id);
-		IPC_SET_ARG2(*answer, (sysarg_t) packet->length);
-		return EOK;
-	
-	case NET_PACKET_CREATE_4:
-		packet = packet_get_local(
-		    ((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, (sysarg_t) packet->packet_id);
-		IPC_SET_ARG2(*answer, (sysarg_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, (sysarg_t) packet->length);
-		*answer_count = 1;
-		return EOK;
-	
-	case NET_PACKET_RELEASE:
-		return packet_release_wrapper(IPC_GET_ID(*call));
-	}
-	
-	return ENOTSUP;
-}
-
-/** @}
- */
Index: uspace/lib/packet/include/packet_server.h
===================================================================
--- uspace/lib/packet/include/packet_server.h	(revision e68c8340d47c44d590ec9f47a0e81614a5ae66a3)
+++ 	(revision )
@@ -1,55 +1,0 @@
-/*
- * 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 libpacket
- * @{
- */
-
-/** @file
- * Packet server.
- * The hosting module has to be compiled with both the packet.c and the
- * packet_server.c source files. To function correctly, initialization of the
- * packet map by the pm_init() function has to happen at the first place. Then
- * the packet messages have to be processed by the packet_server_message()
- * function. The packet map should be released by the pm_destroy() function
- * during the module termination.
- * @see IS_NET_PACKET_MESSAGE()
- */
-
-#ifndef LIBPACKET_PACKET_SERVER_H_
-#define LIBPACKET_PACKET_SERVER_H_
-
-#include <ipc/common.h>
-
-extern int packet_server_message(ipc_callid_t, ipc_call_t *, ipc_call_t *,
-    size_t *);
-
-#endif
-
-/** @}
- */
