Index: uspace/app/nic/nic.c
===================================================================
--- uspace/app/nic/nic.c	(revision f93ba6d5f7e19b94e89a6ccab96897a149761b41)
+++ uspace/app/nic/nic.c	(revision c62a82757f97403f2ba31f76aafdf68ae74e4003)
@@ -49,4 +49,7 @@
 	nic_cable_state_t link_state;
 	nic_channel_mode_t duplex;
+	nic_unicast_mode_t unicast_mode;
+	nic_multicast_mode_t multicast_mode;
+	nic_broadcast_mode_t broadcast_mode;
 	int speed;
 } nic_info_t;
@@ -62,4 +65,7 @@
 	printf("\tduplex <half|full|simplex> - set duplex mode\n");
 	printf("\tauto - enable autonegotiation\n");
+	printf("\tunicast <block|default|list|promisc> - set unicast receive filtering\n");
+	printf("\tmulticast <block|list|promisc> - set multicast receive filtering\n");
+	printf("\tbroadcast <block|allow> - block or allow incoming broadcast frames\n");
 }
 
@@ -145,4 +151,24 @@
 	}
 
+	rc = nic_unicast_get_mode(sess, &info->unicast_mode, 0, NULL, NULL);
+	if (rc != EOK) {
+		printf("Error gettinc NIC unicast receive mode.\n");
+		rc = EIO;
+		goto error;
+	}
+
+	rc = nic_multicast_get_mode(sess, &info->multicast_mode, 0, NULL, NULL);
+	if (rc != EOK) {
+		printf("Error gettinc NIC multicast receive mode.\n");
+		rc = EIO;
+		goto error;
+	}
+
+	rc = nic_broadcast_get_mode(sess, &info->broadcast_mode);
+	if (rc != EOK) {
+		printf("Error gettinc NIC broadcast receive mode.\n");
+		rc = EIO;
+		goto error;
+	}
 
 	return EOK;
@@ -167,4 +193,37 @@
 	case NIC_CM_HALF_DUPLEX: return "half-duplex";
 	case NIC_CM_SIMPLEX: return "simplex";
+	default: assert(false); return NULL;
+	}
+}
+
+static const char *nic_unicast_mode_str(nic_unicast_mode_t mode)
+{
+	switch (mode) {
+	case NIC_UNICAST_UNKNOWN: return "unknown";
+	case NIC_UNICAST_BLOCKED: return "blocked";
+	case NIC_UNICAST_DEFAULT: return "default";
+	case NIC_UNICAST_LIST: return "list";
+	case NIC_UNICAST_PROMISC: return "promisc";
+	default: assert(false); return NULL;
+	}
+}
+
+static const char *nic_multicast_mode_str(nic_unicast_mode_t mode)
+{
+	switch (mode) {
+	case NIC_MULTICAST_UNKNOWN: return "unknown";
+	case NIC_MULTICAST_BLOCKED: return "blocked";
+	case NIC_MULTICAST_LIST: return "list";
+	case NIC_MULTICAST_PROMISC: return "promisc";
+	default: assert(false); return NULL;
+	}
+}
+
+static const char *nic_broadcast_mode_str(nic_unicast_mode_t mode)
+{
+	switch (mode) {
+	case NIC_BROADCAST_UNKNOWN: return "unknown";
+	case NIC_BROADCAST_BLOCKED: return "blocked";
+	case NIC_BROADCAST_ACCEPTED: return "accepted";
 	default: assert(false); return NULL;
 	}
@@ -234,4 +293,10 @@
 		printf("\tLink state: %s\n",
 		    nic_link_state_str(nic_info.link_state));
+		printf("\tUnicast receive mode: %s\n",
+		    nic_unicast_mode_str(nic_info.unicast_mode));
+		printf("\tMulticast receive mode: %s\n",
+		    nic_multicast_mode_str(nic_info.multicast_mode));
+		printf("\tBroadcast receive mode: %s\n",
+		    nic_broadcast_mode_str(nic_info.broadcast_mode));
 
 		if (nic_info.link_state == NIC_CS_PLUGGED) {
@@ -369,4 +434,92 @@
 
 	return nic_set_address(sess, &addr);
+}
+
+static int nic_set_rx_unicast(int i, char *str)
+{
+	async_sess_t *sess;
+
+	sess = get_nic_by_index(i);
+	if (sess == NULL) {
+		printf("Specified NIC doesn't exist or cannot connect to it.\n");
+		return EINVAL;
+	}
+
+	if (!str_cmp(str, "block")) {
+		nic_unicast_set_mode(sess, NIC_UNICAST_BLOCKED, NULL, 0);
+		return EOK;
+	}
+
+	if (!str_cmp(str, "default")) {
+		nic_unicast_set_mode(sess, NIC_UNICAST_DEFAULT, NULL, 0);
+		return EOK;
+	}
+
+	if (!str_cmp(str, "list")) {
+		nic_unicast_set_mode(sess, NIC_UNICAST_LIST, NULL, 0);
+		return EOK;
+	}
+
+	if (!str_cmp(str, "promisc")) {
+		nic_unicast_set_mode(sess, NIC_UNICAST_PROMISC, NULL, 0);
+		return EOK;
+	}
+
+
+	printf("Invalid pameter - should be one of: block, default, promisc\n");
+	return EINVAL;
+}
+
+static int nic_set_rx_multicast(int i, char *str)
+{
+	async_sess_t *sess;
+
+	sess = get_nic_by_index(i);
+	if (sess == NULL) {
+		printf("Specified NIC doesn't exist or cannot connect to it.\n");
+		return EINVAL;
+	}
+
+	if (!str_cmp(str, "block")) {
+		nic_multicast_set_mode(sess, NIC_MULTICAST_BLOCKED, NULL, 0);
+		return EOK;
+	}
+
+	if (!str_cmp(str, "list")) {
+		nic_multicast_set_mode(sess, NIC_MULTICAST_LIST, NULL, 0);
+		return EOK;
+	}
+
+	if (!str_cmp(str, "promisc")) {
+		nic_multicast_set_mode(sess, NIC_MULTICAST_PROMISC, NULL, 0);
+		return EOK;
+	}
+
+	printf("Invalid pameter - should be one of: block, promisc\n");
+	return EINVAL;
+}
+
+static int nic_set_rx_broadcast(int i, char *str)
+{
+	async_sess_t *sess;
+
+	sess = get_nic_by_index(i);
+	if (sess == NULL) {
+		printf("Specified NIC doesn't exist or cannot connect to it.\n");
+		return EINVAL;
+	}
+
+	if (!str_cmp(str, "block")) {
+		nic_broadcast_set_mode(sess, NIC_BROADCAST_BLOCKED);
+		return EOK;
+	}
+
+	if (!str_cmp(str, "accept")) {
+		nic_broadcast_set_mode(sess, NIC_BROADCAST_ACCEPTED);
+		return EOK;
+	}
+
+	printf("Invalid pameter - should be 'block' or 'accept'\n");
+	return EINVAL;
 }
 
@@ -400,4 +553,13 @@
 			return nic_set_autoneg(index);
 
+		if (!str_cmp(argv[2], "unicast"))
+			return nic_set_rx_unicast(index, argv[3]);
+
+		if (!str_cmp(argv[2], "multicast"))
+			return nic_set_rx_multicast(index, argv[3]);
+
+		if (!str_cmp(argv[2], "broadcast"))
+			return nic_set_rx_broadcast(index, argv[3]);
+
 	} else {
 		printf(NAME ": Invalid argument.\n");
Index: uspace/drv/nic/rtl8169/driver.c
===================================================================
--- uspace/drv/nic/rtl8169/driver.c	(revision f93ba6d5f7e19b94e89a6ccab96897a149761b41)
+++ uspace/drv/nic/rtl8169/driver.c	(revision c62a82757f97403f2ba31f76aafdf68ae74e4003)
@@ -27,6 +27,4 @@
  */
 
-#define	_DDF_DATA_IMPLANT
-
 #include <assert.h>
 #include <errno.h>
@@ -330,4 +328,12 @@
 }
 
+static void rtl8169_dev_cleanup(ddf_dev_t *dev)
+{
+	assert(dev);
+
+	if (ddf_dev_data_get(dev))
+		nic_unbind_and_destroy(dev);
+}
+
 static int rtl8169_dev_initialize(ddf_dev_t *dev)
 {
@@ -351,5 +357,5 @@
 failed:
 	ddf_msg(LVL_ERROR, "The device initialization failed");
-//	rtl8139_dev_cleanup(dev);
+	rtl8169_dev_cleanup(dev);
 	return ret;
 
@@ -439,5 +445,4 @@
 	nic_set_ddf_fun(nic_data, fun);
 	ddf_fun_set_ops(fun, &rtl8169_dev_ops);
-//	ddf_fun_data_implant(fun, nic_data);
 
 	rc = ddf_fun_bind(fun);
@@ -467,5 +472,5 @@
 err_pio:
 err_destroy:
-	//rtl8169_dev_cleanup(dev);
+	rtl8169_dev_cleanup(dev);
 	return rc;
 
@@ -733,12 +738,8 @@
 	/* Configure Receive Control Register */
 	uint32_t rcr = pio_read_32(rtl8169->regs + RCR);
-	rcr |= RCR_ACCEPT_ALL_PHYS | RCR_ACCEPT_PHYS_MATCH \
-	    | RCR_ACCEPT_BROADCAST | RCR_ACCEPT_ERROR \
-	    | RCR_ACCEPT_RUNT;
+	rtl8169->rcr_ucast = RCR_ACCEPT_PHYS_MATCH;
+	rcr |= RCR_ACCEPT_PHYS_MATCH | RCR_ACCEPT_ERROR | RCR_ACCEPT_RUNT;
 	pio_write_32(rtl8169->regs + RCR, rcr);
 	pio_write_16(rtl8169->regs + RMS, BUFFER_SIZE);
-
-	ddf_msg(LVL_NOTE, "RCR: 0x%08x", pio_read_32(rtl8169->regs + RCR));
-
 
 	pio_write_16(rtl8169->regs + IMR, 0xffff);
@@ -793,7 +794,74 @@
 }
 
+/** Notify NIC framework about HW filtering state when promisc mode was disabled
+ *
+ *  @param nic_data     The NIC data
+ *  @param mcast_mode   Current multicast mode
+ *  @param was_promisc  Sign if the promiscuous mode was active before disabling
+ */
+inline static void rtl8169_rcx_promics_rem(nic_t *nic_data,
+    nic_multicast_mode_t mcast_mode, uint8_t was_promisc)
+{
+	assert(nic_data);
+
+	if (was_promisc != 0) {
+		if (mcast_mode == NIC_MULTICAST_LIST)
+			nic_report_hw_filtering(nic_data, 1, 0, -1);
+		else
+			nic_report_hw_filtering(nic_data, 1, 1, -1);
+	} else {
+		nic_report_hw_filtering(nic_data, 1, -1, -1);
+	}
+}
+
 static int rtl8169_unicast_set(nic_t *nic_data, nic_unicast_mode_t mode,
     const nic_address_t *addr, size_t addr_count)
 {
+	rtl8169_t *rtl8169 = nic_get_specific(nic_data);
+	uint32_t rcr = pio_read_32(rtl8169->regs + RCR);
+	uint8_t was_promisc = rcr & RCR_ACCEPT_ALL_PHYS;
+	nic_multicast_mode_t mcast_mode;
+
+	nic_query_multicast(nic_data, &mcast_mode, 0, NULL, NULL);
+
+	ddf_msg(LVL_DEBUG, "Unicast RX filter mode: %d", mode);
+
+
+	switch (mode) {
+	case NIC_UNICAST_BLOCKED:
+		rtl8169->rcr_ucast = 0;
+		rtl8169_rcx_promics_rem(nic_data, mcast_mode, was_promisc);
+		break;
+	case NIC_UNICAST_DEFAULT:
+		rtl8169->rcr_ucast = RCR_ACCEPT_PHYS_MATCH;
+		rtl8169_rcx_promics_rem(nic_data, mcast_mode, was_promisc);
+		break;
+	case NIC_UNICAST_LIST:
+		rtl8169->rcr_ucast = RCR_ACCEPT_PHYS_MATCH | RCR_ACCEPT_ALL_PHYS;
+
+		if (mcast_mode == NIC_MULTICAST_PROMISC)
+			nic_report_hw_filtering(nic_data, 0, 1, -1);
+		else
+			nic_report_hw_filtering(nic_data, 0, 0, -1);
+		break;
+	case NIC_UNICAST_PROMISC:
+		rtl8169->rcr_ucast = RCR_ACCEPT_PHYS_MATCH | RCR_ACCEPT_ALL_PHYS;
+
+		if (mcast_mode == NIC_MULTICAST_PROMISC)
+			nic_report_hw_filtering(nic_data, 1, 1, -1);
+		else
+			nic_report_hw_filtering(nic_data, 1, 0, -1);
+		break;
+	default:
+		return ENOTSUP;
+	}
+
+	fibril_mutex_lock(&rtl8169->rx_lock);
+
+	rcr &= ~(RCR_ACCEPT_PHYS_MATCH | RCR_ACCEPT_ALL_PHYS);
+	pio_write_32(rtl8169->regs + RCR, rcr | rtl8169->rcr_ucast | rtl8169->rcr_mcast);
+	ddf_msg(LVL_DEBUG, "new RCR value: 0x%08x", rcr | rtl8169->rcr_ucast | rtl8169->rcr_mcast);
+
+	fibril_mutex_unlock(&rtl8169->rx_lock);
 	return EOK;
 }
@@ -802,4 +870,42 @@
     const nic_address_t *addr, size_t addr_count)
 {
+	rtl8169_t *rtl8169 = nic_get_specific(nic_data);
+	uint32_t rcr = pio_read_32(rtl8169->regs + RCR);
+	uint64_t mask;
+
+	ddf_msg(LVL_DEBUG, "Multicast RX filter mode: %d", mode);
+
+	switch (mode) {
+	case NIC_MULTICAST_BLOCKED:
+		rtl8169->rcr_mcast = 0;
+		if ((rtl8169->rcr_ucast & RCR_ACCEPT_ALL_PHYS) != 0)
+			nic_report_hw_filtering(nic_data, -1, 0, -1);
+		else
+			nic_report_hw_filtering(nic_data, -1, 1, -1);
+		break;
+	case NIC_MULTICAST_LIST:
+		mask = nic_mcast_hash(addr, addr_count);
+		pio_write_32(rtl8169->regs + MAR0, (uint32_t)mask);
+		pio_write_32(rtl8169->regs + MAR0 + 4, (uint32_t)(mask >> 32));
+		rtl8169->rcr_mcast = RCR_ACCEPT_MULTICAST;
+		nic_report_hw_filtering(nic_data, -1, 0, -1);
+		break;
+	case NIC_MULTICAST_PROMISC:
+		pio_write_32(rtl8169->regs + MAR0, 0xffffffffULL);
+		pio_write_32(rtl8169->regs + MAR0 + 4, (uint32_t)(0xffffffffULL >> 32));
+		rtl8169->rcr_mcast = RCR_ACCEPT_MULTICAST;
+		nic_report_hw_filtering(nic_data, -1, 1, -1);
+		break;
+	default:
+		return ENOTSUP;
+	}
+
+	fibril_mutex_lock(&rtl8169->rx_lock);
+
+	rcr &= ~(RCR_ACCEPT_PHYS_MATCH | RCR_ACCEPT_ALL_PHYS);
+	pio_write_32(rtl8169->regs + RCR, rcr | rtl8169->rcr_ucast | rtl8169->rcr_mcast);
+	ddf_msg(LVL_DEBUG, "new RCR value: 0x%08x", rcr | rtl8169->rcr_ucast | rtl8169->rcr_mcast);
+
+	fibril_mutex_unlock(&rtl8169->rx_lock);
 	return EOK;
 }
@@ -807,4 +913,25 @@
 static int rtl8169_broadcast_set(nic_t *nic_data, nic_broadcast_mode_t mode)
 {
+	rtl8169_t *rtl8169 = nic_get_specific(nic_data);
+	
+	/* Configure Receive Control Register */
+	uint32_t rcr = pio_read_32(rtl8169->regs + RCR);
+
+	ddf_msg(LVL_DEBUG, "Broadcast RX filter mode: %d", mode);
+
+	switch (mode) {
+	case NIC_BROADCAST_BLOCKED:
+		rcr &= RCR_ACCEPT_BROADCAST;
+		break;
+	case NIC_BROADCAST_ACCEPTED:
+		rcr |= RCR_ACCEPT_BROADCAST;
+		break;
+	default:
+		return ENOTSUP;
+	}
+
+	pio_write_32(rtl8169->regs + RCR, rcr);
+	ddf_msg(LVL_DEBUG," new RCR value: 0x%08x", rcr);
+
 	return EOK;
 }
@@ -816,6 +943,7 @@
 	rtl8169_t *rtl8169 = nic_get_specific(nic_data);
 	rtl8169_descr_t *descr;
-
-	ddf_msg(LVL_NOTE, "rtl8169_transmit_done()");
+	int sent = 0;
+
+	ddf_msg(LVL_DEBUG, "rtl8169_transmit_done()");
 
 	fibril_mutex_lock(&rtl8169->tx_lock);
@@ -828,8 +956,12 @@
 		descr->control &= (~CONTROL_OWN);
 		write_barrier();
-		ddf_msg(LVL_NOTE, "TX status for descr %d: 0x%08x", tail, descr->control);
+		ddf_msg(LVL_DEBUG, "TX status for descr %d: 0x%08x", tail, descr->control);
 	
 		tail = (tail + 1) % TX_BUFFERS_COUNT;
-	}
+		sent++;
+	}
+
+	if (sent != 0)
+		nic_set_tx_busy(nic_data, 0);
 
 	rtl8169->tx_tail = tail;
@@ -849,5 +981,5 @@
 	int frame_size;
 
-	ddf_msg(LVL_NOTE, "rtl8169_receive_done()");
+	ddf_msg(LVL_DEBUG, "rtl8169_receive_done()");
 
 	fibril_mutex_lock(&rtl8169->rx_lock);
@@ -862,5 +994,5 @@
 
 		if (descr->control & RXSTATUS_RES) {
-			ddf_msg(LVL_NOTE, "error at slot %d: 0x%08x\n", tail, descr->control);
+			ddf_msg(LVL_WARN, "error at slot %d: 0x%08x\n", tail, descr->control);
 			tail = (tail + 1) % RX_BUFFERS_COUNT;
 			continue;
@@ -871,6 +1003,5 @@
 		
 		if (descr->control & CONTROL_LS) {
-
-			ddf_msg(LVL_NOTE, "received message at slot %d, control 0x%08x", tail, descr->control);
+			ddf_msg(LVL_DEBUG, "received message at slot %d, control 0x%08x", tail, descr->control);
 
 			if (fsidx != tail)
@@ -907,5 +1038,5 @@
 	rtl8169_t *rtl8169 = nic_get_specific(nic_data);
 
-	ddf_msg(LVL_NOTE, "rtl8169_irq_handler(): isr=0x%04x", isr);
+	ddf_msg(LVL_DEBUG, "rtl8169_irq_handler(): isr=0x%04x", isr);
 	pio_write_16(rtl8169->regs + IMR, 0xffff);
 
@@ -963,5 +1094,5 @@
 	fibril_mutex_lock(&rtl8169->tx_lock);
 
-	ddf_msg(LVL_NOTE, "send_frame: size: %zu, tx_head=%d tx_tail=%d",
+	ddf_msg(LVL_DEBUG, "send_frame: size: %zu, tx_head=%d tx_tail=%d",
 	    size, rtl8169->tx_head, rtl8169->tx_tail);
 
@@ -986,5 +1117,5 @@
 	prev = &rtl8169->tx_ring[(head - 1) % TX_BUFFERS_COUNT];
 
-	ddf_msg(LVL_NOTE, "current_descr=%p, prev_descr=%p", descr, prev);
+	ddf_msg(LVL_DEBUG, "current_descr=%p, prev_descr=%p", descr, prev);
 
 	descr->control = CONTROL_OWN | CONTROL_FS | CONTROL_LS;
Index: uspace/drv/nic/rtl8169/driver.h
===================================================================
--- uspace/drv/nic/rtl8169/driver.h	(revision f93ba6d5f7e19b94e89a6ccab96897a149761b41)
+++ uspace/drv/nic/rtl8169/driver.h	(revision c62a82757f97403f2ba31f76aafdf68ae74e4003)
@@ -86,4 +86,8 @@
 	size_t tx_used;
 
+	/** Receive Control Register masks */
+	uint32_t rcr_ucast;
+	uint32_t rcr_mcast;
+
 	/** Lock for receiver */
 	fibril_mutex_t rx_lock;
Index: uspace/lib/c/generic/iplink.c
===================================================================
--- uspace/lib/c/generic/iplink.c	(revision f93ba6d5f7e19b94e89a6ccab96897a149761b41)
+++ uspace/lib/c/generic/iplink.c	(revision c62a82757f97403f2ba31f76aafdf68ae74e4003)
@@ -171,4 +171,27 @@
 }
 
+int iplink_set_mac48(iplink_t *iplink, addr48_t mac)
+{
+	async_exch_t *exch = async_exchange_begin(iplink->sess);
+	
+	ipc_call_t answer;
+	aid_t req = async_send_0(exch, IPLINK_GET_MAC48, &answer);
+	
+	int rc = async_data_read_start(exch, mac, sizeof(addr48_t));
+	
+	loc_exchange_end(exch);
+	
+	if (rc != EOK) {
+		async_forget(req);
+		return rc;
+	}
+	
+	sysarg_t retval;
+	async_wait_for(req, &retval);
+	
+	return (int) retval;
+}
+
+
 int iplink_addr_add(iplink_t *iplink, inet_addr_t *addr)
 {
@@ -230,4 +253,22 @@
 	free(sdu.data);
 	async_answer_0(iid, rc);
+}
+
+static void iplink_ev_change_addr(iplink_t *iplink, ipc_callid_t iid,
+    ipc_call_t *icall)
+{
+	addr48_t *addr;
+	size_t size;
+	
+	int rc = async_data_write_accept((void **)&addr, false,
+	    sizeof(addr48_t), sizeof(addr48_t), 0, &size);
+	if (rc != EOK) {
+		async_answer_0(iid, rc);
+		return;
+	}
+
+	rc = iplink->ev_ops->change_addr(iplink, *addr);
+	free(addr);
+	async_answer_0(iid, EOK);
 }
 
@@ -249,4 +290,6 @@
 			iplink_ev_recv(iplink, callid, &call);
 			break;
+		case IPLINK_EV_CHANGE_ADDR:
+			iplink_ev_change_addr(iplink, callid, &call);
 		default:
 			async_answer_0(callid, ENOTSUP);
Index: uspace/lib/c/generic/iplink_srv.c
===================================================================
--- uspace/lib/c/generic/iplink_srv.c	(revision f93ba6d5f7e19b94e89a6ccab96897a149761b41)
+++ uspace/lib/c/generic/iplink_srv.c	(revision c62a82757f97403f2ba31f76aafdf68ae74e4003)
@@ -81,4 +81,31 @@
 }
 
+static void iplink_set_mac48_srv(iplink_srv_t *srv, ipc_callid_t iid,
+    ipc_call_t *icall)
+{
+	int rc;
+	size_t size;
+	addr48_t mac;
+	ipc_callid_t callid;
+
+	rc = async_data_write_receive(&callid, &size);
+	if (rc != EOK) {
+		async_answer_0(callid, (sysarg_t) rc);
+		async_answer_0(iid, (sysarg_t) rc);
+	}
+
+	rc = srv->ops->set_mac48(srv, &mac);
+	if (rc != EOK) {
+		async_answer_0(iid, rc);
+		return;
+	}
+	
+	rc = async_data_read_finalize(callid, &mac, sizeof(addr48_t));
+	if (rc != EOK)
+		async_answer_0(callid, rc);
+	
+	async_answer_0(iid, (sysarg_t) rc);
+}
+
 static void iplink_addr_add_srv(iplink_srv_t *srv, ipc_callid_t iid,
     ipc_call_t *icall)
@@ -252,4 +279,7 @@
 			iplink_get_mac48_srv(srv, callid, &call);
 			break;
+		case IPLINK_SET_MAC48:
+			iplink_set_mac48_srv(srv, callid, &call);
+			break;
 		case IPLINK_SEND:
 			iplink_send_srv(srv, callid, &call);
@@ -300,4 +330,30 @@
 }
 
+int iplink_ev_change_addr(iplink_srv_t *srv, addr48_t *addr)
+{
+	if (srv->client_sess == NULL)
+		return EIO;
+	
+	async_exch_t *exch = async_exchange_begin(srv->client_sess);
+	
+	ipc_call_t answer;
+	aid_t req = async_send_0(exch, IPLINK_EV_CHANGE_ADDR, &answer);
+	
+	int rc = async_data_write_start(exch, addr, sizeof(addr48_t));
+	async_exchange_end(exch);
+	
+	if (rc != EOK) {
+		async_forget(req);
+		return rc;
+	}
+	
+	sysarg_t retval;
+	async_wait_for(req, &retval);
+	if (retval != EOK)
+		return retval;
+	
+	return EOK;
+}
+
 /** @}
  */
Index: uspace/lib/c/include/inet/iplink.h
===================================================================
--- uspace/lib/c/include/inet/iplink.h	(revision f93ba6d5f7e19b94e89a6ccab96897a149761b41)
+++ uspace/lib/c/include/inet/iplink.h	(revision c62a82757f97403f2ba31f76aafdf68ae74e4003)
@@ -78,4 +78,5 @@
 typedef struct iplink_ev_ops {
 	int (*recv)(iplink_t *, iplink_recv_sdu_t *, ip_ver_t);
+	int (*change_addr)(iplink_t *, addr48_t);
 } iplink_ev_ops_t;
 
@@ -88,4 +89,5 @@
 extern int iplink_get_mtu(iplink_t *, size_t *);
 extern int iplink_get_mac48(iplink_t *, addr48_t *);
+extern int iplink_set_mac48(iplink_t *, addr48_t);
 
 #endif
Index: uspace/lib/c/include/inet/iplink_srv.h
===================================================================
--- uspace/lib/c/include/inet/iplink_srv.h	(revision f93ba6d5f7e19b94e89a6ccab96897a149761b41)
+++ uspace/lib/c/include/inet/iplink_srv.h	(revision c62a82757f97403f2ba31f76aafdf68ae74e4003)
@@ -59,4 +59,5 @@
 	int (*get_mtu)(iplink_srv_t *, size_t *);
 	int (*get_mac48)(iplink_srv_t *, addr48_t *);
+	int (*set_mac48)(iplink_srv_t *, addr48_t *);
 	int (*addr_add)(iplink_srv_t *, inet_addr_t *);
 	int (*addr_remove)(iplink_srv_t *, inet_addr_t *);
@@ -67,4 +68,5 @@
 extern int iplink_conn(ipc_callid_t, ipc_call_t *, void *);
 extern int iplink_ev_recv(iplink_srv_t *, iplink_recv_sdu_t *, ip_ver_t);
+extern int iplink_ev_change_addr(iplink_srv_t *, addr48_t *);
 
 #endif
Index: uspace/lib/c/include/ipc/iplink.h
===================================================================
--- uspace/lib/c/include/ipc/iplink.h	(revision f93ba6d5f7e19b94e89a6ccab96897a149761b41)
+++ uspace/lib/c/include/ipc/iplink.h	(revision c62a82757f97403f2ba31f76aafdf68ae74e4003)
@@ -41,4 +41,5 @@
 	IPLINK_GET_MTU = IPC_FIRST_USER_METHOD,
 	IPLINK_GET_MAC48,
+	IPLINK_SET_MAC48,
 	IPLINK_SEND,
 	IPLINK_SEND6,
@@ -48,5 +49,6 @@
 
 typedef enum {
-	IPLINK_EV_RECV = IPC_FIRST_USER_METHOD
+	IPLINK_EV_RECV = IPC_FIRST_USER_METHOD,
+	IPLINK_EV_CHANGE_ADDR,
 } iplink_event_t;
 
Index: uspace/lib/nic/src/nic_driver.c
===================================================================
--- uspace/lib/nic/src/nic_driver.c	(revision f93ba6d5f7e19b94e89a6ccab96897a149761b41)
+++ uspace/lib/nic/src/nic_driver.c	(revision c62a82757f97403f2ba31f76aafdf68ae74e4003)
@@ -47,6 +47,4 @@
 #include <ops/nic.h>
 #include <errno.h>
-
-#include <io/log.h>
 
 #include "nic_driver.h"
@@ -438,5 +436,4 @@
 		int rc = nic_ev_addr_changed(nic_data->client_session,
 		    address);
-		log_msg(LOG_DEFAULT, LVL_WARN, "rc=%d", rc);
 
 		if (rc != EOK) {
Index: uspace/srv/net/ethip/ethip.c
===================================================================
--- uspace/srv/net/ethip/ethip.c	(revision f93ba6d5f7e19b94e89a6ccab96897a149761b41)
+++ uspace/srv/net/ethip/ethip.c	(revision c62a82757f97403f2ba31f76aafdf68ae74e4003)
@@ -59,4 +59,5 @@
 static int ethip_get_mtu(iplink_srv_t *srv, size_t *mtu);
 static int ethip_get_mac48(iplink_srv_t *srv, addr48_t *mac);
+static int ethip_set_mac48(iplink_srv_t *srv, addr48_t *mac);
 static int ethip_addr_add(iplink_srv_t *srv, inet_addr_t *addr);
 static int ethip_addr_remove(iplink_srv_t *srv, inet_addr_t *addr);
@@ -71,4 +72,5 @@
 	.get_mtu = ethip_get_mtu,
 	.get_mac48 = ethip_get_mac48,
+	.set_mac48 = ethip_set_mac48,
 	.addr_add = ethip_addr_add,
 	.addr_remove = ethip_addr_remove
@@ -284,4 +286,14 @@
 }
 
+static int ethip_set_mac48(iplink_srv_t *srv, addr48_t *mac)
+{
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ethip_set_mac48()");
+	
+	ethip_nic_t *nic = (ethip_nic_t *) srv->arg;
+	addr48(*mac, nic->mac_addr);
+	
+	return EOK;
+}
+
 static int ethip_addr_add(iplink_srv_t *srv, inet_addr_t *addr)
 {
Index: uspace/srv/net/ethip/ethip_nic.c
===================================================================
--- uspace/srv/net/ethip/ethip_nic.c	(revision f93ba6d5f7e19b94e89a6ccab96897a149761b41)
+++ uspace/srv/net/ethip/ethip_nic.c	(revision c62a82757f97403f2ba31f76aafdf68ae74e4003)
@@ -245,4 +245,12 @@
 	    addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
 
+	memcpy(&nic->mac_addr, addr, sizeof(nic->mac_addr));
+
+	rc = iplink_ev_change_addr(&nic->iplink, &nic->mac_addr);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_DEBUG, "iplink_ev_change_addr() failed");
+		return;
+	}
+
 	free(addr);
 	async_answer_0(callid, EOK);
@@ -309,5 +317,5 @@
 			break;
 		default:
-			log_msg(LOG_DEFAULT, LVL_DEBUG, "unknown IPC method: %d", (int) IPC_GET_IMETHOD(call));
+			log_msg(LOG_DEFAULT, LVL_DEBUG, "unknown IPC method: %" PRIun, IPC_GET_IMETHOD(call));
 			async_answer_0(callid, ENOTSUP);
 		}
Index: uspace/srv/net/inetsrv/inet_link.c
===================================================================
--- uspace/srv/net/inetsrv/inet_link.c	(revision f93ba6d5f7e19b94e89a6ccab96897a149761b41)
+++ uspace/srv/net/inetsrv/inet_link.c	(revision c62a82757f97403f2ba31f76aafdf68ae74e4003)
@@ -55,8 +55,10 @@
 
 static int inet_iplink_recv(iplink_t *, iplink_recv_sdu_t *, ip_ver_t);
+static int inet_iplink_change_addr(iplink_t *, addr48_t);
 static inet_link_t *inet_link_get_by_id_locked(sysarg_t);
 
 static iplink_ev_ops_t inet_iplink_ev_ops = {
-	.recv = inet_iplink_recv
+	.recv = inet_iplink_recv,
+	.change_addr = inet_iplink_change_addr,
 };
 
@@ -110,4 +112,18 @@
 	
 	return rc;
+}
+
+static int inet_iplink_change_addr(iplink_t *iplink, addr48_t mac)
+{
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "inet_iplink_change_addr(): "
+	    "new addr=%02x:%02x:%02x:%02x:%02x:%02x",
+	    mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+
+	list_foreach(inet_links, link_list, inet_link_t, ilink) {
+		if (ilink->sess == iplink->sess)
+			memcpy(&ilink->mac, mac, sizeof(addr48_t));
+	}
+
+	return EOK;
 }
 
