Index: uspace/lib/nic/src/nic_impl.c
===================================================================
--- uspace/lib/nic/src/nic_impl.c	(revision 00d7e1bfe06501df61aed156666d5597397d910a)
+++ uspace/lib/nic/src/nic_impl.c	(revision 00d7e1bfe06501df61aed156666d5597397d910a)
@@ -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)
+{
+}
+
+/** @}
+ */
