Index: uspace/srv/net/il/arp/Makefile
===================================================================
--- uspace/srv/net/il/arp/Makefile	(revision 73ac2e9cfc27b4ece704510e8fe908610ae7a583)
+++ uspace/srv/net/il/arp/Makefile	(revision 797b704b28bced20e17a9eb959845c20363ce662)
@@ -34,6 +34,5 @@
 
 SOURCES = \
-	arp.c \
-	arp_module.c
+	arp.c
 
 include $(USPACE_PREFIX)/Makefile.common
Index: uspace/srv/net/il/arp/arp.c
===================================================================
--- uspace/srv/net/il/arp/arp.c	(revision 73ac2e9cfc27b4ece704510e8fe908610ae7a583)
+++ uspace/srv/net/il/arp/arp.c	(revision 797b704b28bced20e17a9eb959845c20363ce662)
@@ -35,9 +35,4 @@
  * @see arp.h
  */
-
-#include "arp.h"
-#include "arp_header.h"
-#include "arp_oc.h"
-#include "arp_module.h"
 
 #include <async.h>
@@ -64,7 +59,7 @@
 #include <packet_client.h>
 #include <packet_remote.h>
-#include <il_interface.h>
-#include <il_local.h>
-
+#include <il_remote.h>
+#include <il_skel.h>
+#include "arp.h"
 
 /** ARP module name. */
@@ -73,4 +68,42 @@
 /** Number of microseconds to wait for an ARP reply. */
 #define ARP_TRANS_WAIT  1000000
+
+/** @name ARP operation codes definitions */
+/*@{*/
+
+/** REQUEST operation code. */
+#define ARPOP_REQUEST  1
+
+/** REPLY operation code. */
+#define ARPOP_REPLY  2
+
+/*@}*/
+
+/** Type definition of an ARP protocol header.
+ * @see arp_header
+ */
+typedef struct arp_header arp_header_t;
+
+/** ARP protocol header. */
+struct arp_header {
+	/**
+	 * Hardware type identifier.
+	 * @see hardware.h
+	 */
+	uint16_t hardware;
+	
+	/** Protocol identifier. */
+	uint16_t protocol;
+	/** Hardware address length in bytes. */
+	uint8_t hardware_length;
+	/** Protocol address length in bytes. */
+	uint8_t protocol_length;
+	
+	/**
+	 * ARP packet type.
+	 * @see arp_oc.h
+	 */
+	uint16_t operation;
+} __attribute__ ((packed));
 
 /** ARP global data. */
@@ -231,4 +264,202 @@
 	
 	return EOK;
+}
+
+/** Process the received ARP packet.
+ *
+ * Update the source hardware address if the source entry exists or the packet
+ * is targeted to my protocol address.
+ *
+ * Respond to the ARP request if the packet is the ARP request and is
+ * targeted to my address.
+ *
+ * @param[in]     device_id Source device identifier.
+ * @param[in,out] packet    Received packet.
+ *
+ * @return EOK on success and the packet is no longer needed.
+ * @return One on success and the packet has been reused.
+ * @return EINVAL if the packet is too small to carry an ARP
+ *         packet.
+ * @return EINVAL if the received address lengths differs from
+ *         the registered values.
+ * @return ENOENT if the device is not found in the cache.
+ * @return ENOENT if the protocol for the device is not found in
+ *         the cache.
+ * @return ENOMEM if there is not enough memory left.
+ *
+ */
+static int arp_receive_message(device_id_t device_id, packet_t *packet)
+{
+	int rc;
+	
+	size_t length = packet_get_data_length(packet);
+	if (length <= sizeof(arp_header_t))
+		return EINVAL;
+	
+	arp_device_t *device = arp_cache_find(&arp_globals.cache, device_id);
+	if (!device)
+		return ENOENT;
+	
+	arp_header_t *header = (arp_header_t *) packet_get_data(packet);
+	if ((ntohs(header->hardware) != device->hardware) ||
+	    (length < sizeof(arp_header_t) + header->hardware_length * 2U +
+	    header->protocol_length * 2U)) {
+		return EINVAL;
+	}
+	
+	arp_proto_t *proto = arp_protos_find(&device->protos,
+	    protocol_unmap(device->service, ntohs(header->protocol)));
+	if (!proto)
+		return ENOENT;
+	
+	uint8_t *src_hw = ((uint8_t *) header) + sizeof(arp_header_t);
+	uint8_t *src_proto = src_hw + header->hardware_length;
+	uint8_t *des_hw = src_proto + header->protocol_length;
+	uint8_t *des_proto = des_hw + header->hardware_length;
+	
+	arp_trans_t *trans = arp_addr_find(&proto->addresses, src_proto,
+	    header->protocol_length);
+	
+	if ((trans) && (trans->hw_addr)) {
+		/* Translation exists */
+		if (trans->hw_addr->length != header->hardware_length)
+			return EINVAL;
+		
+		memcpy(trans->hw_addr->value, src_hw, trans->hw_addr->length);
+	}
+	
+	/* Is my protocol address? */
+	if (proto->addr->length != header->protocol_length)
+		return EINVAL;
+	
+	if (!bcmp(proto->addr->value, des_proto, proto->addr->length)) {
+		if (!trans) {
+			/* Update the translation */
+			trans = (arp_trans_t *) malloc(sizeof(arp_trans_t));
+			if (!trans)
+				return ENOMEM;
+			
+			trans->hw_addr = NULL;
+			fibril_condvar_initialize(&trans->cv);
+			rc = arp_addr_add(&proto->addresses, src_proto,
+			    header->protocol_length, trans);
+			if (rc != EOK) {
+				/* The generic char map has already freed trans! */
+				return rc;
+			}
+		}
+		
+		if (!trans->hw_addr) {
+			trans->hw_addr = measured_string_create_bulk(src_hw,
+			    header->hardware_length);
+			if (!trans->hw_addr)
+				return ENOMEM;
+			
+			/* Notify the fibrils that wait for the translation. */
+			fibril_condvar_broadcast(&trans->cv);
+		}
+		
+		if (ntohs(header->operation) == ARPOP_REQUEST) {
+			header->operation = htons(ARPOP_REPLY);
+			memcpy(des_proto, src_proto, header->protocol_length);
+			memcpy(src_proto, proto->addr->value,
+			    header->protocol_length);
+			memcpy(src_hw, device->addr->value,
+			    device->packet_dimension.addr_len);
+			memcpy(des_hw, trans->hw_addr->value,
+			    header->hardware_length);
+			
+			rc = packet_set_addr(packet, src_hw, des_hw,
+			    header->hardware_length);
+			if (rc != EOK)
+				return rc;
+			
+			nil_send_msg(device->phone, device_id, packet,
+			    SERVICE_ARP);
+			return 1;
+		}
+	}
+	
+	return EOK;
+}
+
+/** Update the device content length according to the new MTU value.
+ *
+ * @param[in] device_id Device identifier.
+ * @param[in] mtu       New MTU value.
+ *
+ * @return ENOENT if device is not found.
+ * @return EOK on success.
+ *
+ */
+static int arp_mtu_changed_message(device_id_t device_id, size_t mtu)
+{
+	fibril_mutex_lock(&arp_globals.lock);
+	
+	arp_device_t *device = arp_cache_find(&arp_globals.cache, device_id);
+	if (!device) {
+		fibril_mutex_unlock(&arp_globals.lock);
+		return ENOENT;
+	}
+	
+	device->packet_dimension.content = mtu;
+	
+	fibril_mutex_unlock(&arp_globals.lock);
+	
+	printf("%s: Device %d changed MTU to %zu\n", NAME, device_id, mtu);
+	
+	return EOK;
+}
+
+/** Process IPC messages from the registered device driver modules
+ *
+ * @param[in]     iid   Message identifier.
+ * @param[in,out] icall Message parameters.
+ *
+ */
+static void arp_receiver(ipc_callid_t iid, ipc_call_t *icall)
+{
+	packet_t *packet;
+	int rc;
+	
+	while (true) {
+		switch (IPC_GET_IMETHOD(*icall)) {
+		case NET_IL_DEVICE_STATE:
+			/* Do nothing - keep the cache */
+			ipc_answer_0(iid, (sysarg_t) EOK);
+			break;
+		
+		case NET_IL_RECEIVED:
+			rc = packet_translate_remote(arp_globals.net_phone, &packet,
+			    IPC_GET_PACKET(*icall));
+			if (rc == EOK) {
+				fibril_mutex_lock(&arp_globals.lock);
+				do {
+					packet_t *next = pq_detach(packet);
+					rc = arp_receive_message(IPC_GET_DEVICE(*icall), packet);
+					if (rc != 1) {
+						pq_release_remote(arp_globals.net_phone,
+						    packet_get_id(packet));
+					}
+					
+					packet = next;
+				} while (packet);
+				fibril_mutex_unlock(&arp_globals.lock);
+			}
+			ipc_answer_0(iid, (sysarg_t) rc);
+			break;
+		
+		case NET_IL_MTU_CHANGED:
+			rc = arp_mtu_changed_message(IPC_GET_DEVICE(*icall),
+			    IPC_GET_MTU(*icall));
+			ipc_answer_0(iid, (sysarg_t) rc);
+			break;
+		
+		default:
+			ipc_answer_0(iid, (sysarg_t) ENOTSUP);
+		}
+		
+		iid = async_get_call(icall);
+	}
 }
 
@@ -335,5 +566,5 @@
 		device->phone = nil_bind_service(device->service,
 		    (sysarg_t) device->device_id, SERVICE_ARP,
-		    arp_globals.client_connection);
+		    arp_receiver);
 		if (device->phone < 0) {
 			fibril_mutex_unlock(&arp_globals.lock);
@@ -396,169 +627,14 @@
 }
 
-/** Initialize the ARP module.
- *
- *  @param[in] client_connection The client connection processing function.
- *                               The module skeleton propagates its own one.
- *
- *  @return EOK on success.
- *  @return ENOMEM if there is not enough memory left.
- *
- */
-int arp_initialize(async_client_conn_t client_connection)
+int il_initialize(int net_phone)
 {
 	fibril_mutex_initialize(&arp_globals.lock);
 	
 	fibril_mutex_lock(&arp_globals.lock);
-	arp_globals.client_connection = client_connection;
+	arp_globals.net_phone = net_phone;
 	int rc = arp_cache_initialize(&arp_globals.cache);
 	fibril_mutex_unlock(&arp_globals.lock);
 	
 	return rc;
-}
-
-/** Update the device content length according to the new MTU value.
- *
- * @param[in] device_id Device identifier.
- * @param[in] mtu       New MTU value.
- *
- * @return ENOENT if device is not found.
- * @return EOK on success.
- *
- */
-static int arp_mtu_changed_message(device_id_t device_id, size_t mtu)
-{
-	fibril_mutex_lock(&arp_globals.lock);
-	
-	arp_device_t *device = arp_cache_find(&arp_globals.cache, device_id);
-	if (!device) {
-		fibril_mutex_unlock(&arp_globals.lock);
-		return ENOENT;
-	}
-	
-	device->packet_dimension.content = mtu;
-	
-	fibril_mutex_unlock(&arp_globals.lock);
-	
-	printf("%s: Device %d changed MTU to %zu\n", NAME, device_id, mtu);
-	
-	return EOK;
-}
-
-/** Process the received ARP packet.
- *
- * Update the source hardware address if the source entry exists or the packet
- * is targeted to my protocol address.
- *
- * Respond to the ARP request if the packet is the ARP request and is
- * targeted to my address.
- *
- * @param[in]     device_id Source device identifier.
- * @param[in,out] packet    Received packet.
- *
- * @return EOK on success and the packet is no longer needed.
- * @return One on success and the packet has been reused.
- * @return EINVAL if the packet is too small to carry an ARP
- *         packet.
- * @return EINVAL if the received address lengths differs from
- *         the registered values.
- * @return ENOENT if the device is not found in the cache.
- * @return ENOENT if the protocol for the device is not found in
- *         the cache.
- * @return ENOMEM if there is not enough memory left.
- *
- */
-static int arp_receive_message(device_id_t device_id, packet_t *packet)
-{
-	int rc;
-	
-	size_t length = packet_get_data_length(packet);
-	if (length <= sizeof(arp_header_t))
-		return EINVAL;
-	
-	arp_device_t *device = arp_cache_find(&arp_globals.cache, device_id);
-	if (!device)
-		return ENOENT;
-	
-	arp_header_t *header = (arp_header_t *) packet_get_data(packet);
-	if ((ntohs(header->hardware) != device->hardware) ||
-	    (length < sizeof(arp_header_t) + header->hardware_length * 2U +
-	    header->protocol_length * 2U)) {
-		return EINVAL;
-	}
-	
-	arp_proto_t *proto = arp_protos_find(&device->protos,
-	    protocol_unmap(device->service, ntohs(header->protocol)));
-	if (!proto)
-		return ENOENT;
-	
-	uint8_t *src_hw = ((uint8_t *) header) + sizeof(arp_header_t);
-	uint8_t *src_proto = src_hw + header->hardware_length;
-	uint8_t *des_hw = src_proto + header->protocol_length;
-	uint8_t *des_proto = des_hw + header->hardware_length;
-	
-	arp_trans_t *trans = arp_addr_find(&proto->addresses, src_proto,
-	    header->protocol_length);
-	
-	if ((trans) && (trans->hw_addr)) {
-		/* Translation exists */
-		if (trans->hw_addr->length != header->hardware_length)
-			return EINVAL;
-		
-		memcpy(trans->hw_addr->value, src_hw, trans->hw_addr->length);
-	}
-	
-	/* Is my protocol address? */
-	if (proto->addr->length != header->protocol_length)
-		return EINVAL;
-	
-	if (!bcmp(proto->addr->value, des_proto, proto->addr->length)) {
-		if (!trans) {
-			/* Update the translation */
-			trans = (arp_trans_t *) malloc(sizeof(arp_trans_t));
-			if (!trans)
-				return ENOMEM;
-			
-			trans->hw_addr = NULL;
-			fibril_condvar_initialize(&trans->cv);
-			rc = arp_addr_add(&proto->addresses, src_proto,
-			    header->protocol_length, trans);
-			if (rc != EOK) {
-				/* The generic char map has already freed trans! */
-				return rc;
-			}
-		}
-		
-		if (!trans->hw_addr) {
-			trans->hw_addr = measured_string_create_bulk(src_hw,
-			    header->hardware_length);
-			if (!trans->hw_addr)
-				return ENOMEM;
-			
-			/* Notify the fibrils that wait for the translation. */
-			fibril_condvar_broadcast(&trans->cv);
-		}
-		
-		if (ntohs(header->operation) == ARPOP_REQUEST) {
-			header->operation = htons(ARPOP_REPLY);
-			memcpy(des_proto, src_proto, header->protocol_length);
-			memcpy(src_proto, proto->addr->value,
-			    header->protocol_length);
-			memcpy(src_hw, device->addr->value,
-			    device->packet_dimension.addr_len);
-			memcpy(des_hw, trans->hw_addr->value,
-			    header->hardware_length);
-			
-			rc = packet_set_addr(packet, src_hw, des_hw,
-			    header->hardware_length);
-			if (rc != EOK)
-				return rc;
-			
-			nil_send_msg(device->phone, device_id, packet,
-			    SERVICE_ARP);
-			return 1;
-		}
-	}
-	
-	return EOK;
 }
 
@@ -714,5 +790,5 @@
  *
  */
-int arp_message(ipc_callid_t callid, ipc_call_t *call, ipc_call_t *answer,
+int il_module_message(ipc_callid_t callid, ipc_call_t *call, ipc_call_t *answer,
     size_t *count)
 {
@@ -720,6 +796,4 @@
 	measured_string_t *translation;
 	uint8_t *data;
-	packet_t *packet;
-	packet_t *next;
 	int rc;
 	
@@ -784,33 +858,4 @@
 	case NET_ARP_CLEAN_CACHE:
 		return arp_clean_cache_req(0);
-	
-	case NET_IL_DEVICE_STATE:
-		/* Do nothing - keep the cache */
-		return EOK;
-	
-	case NET_IL_RECEIVED:
-		
-		rc = packet_translate_remote(arp_globals.net_phone, &packet,
-		    IPC_GET_PACKET(*call));
-		if (rc != EOK)
-			return rc;
-		
-		fibril_mutex_lock(&arp_globals.lock);
-		do {
-			next = pq_detach(packet);
-			rc = arp_receive_message(IPC_GET_DEVICE(*call), packet);
-			if (rc != 1) {
-				pq_release_remote(arp_globals.net_phone,
-				    packet_get_id(packet));
-			}
-			packet = next;
-		} while (packet);
-		fibril_mutex_unlock(&arp_globals.lock);
-		
-		return EOK;
-	
-	case NET_IL_MTU_CHANGED:
-		return arp_mtu_changed_message(IPC_GET_DEVICE(*call),
-		    IPC_GET_MTU(*call));
 	}
 	
@@ -818,49 +863,8 @@
 }
 
-/** Default thread for new connections.
- *
- * @param[in] iid   Initial message identifier.
- * @param[in] icall Initial message call structure.
- */
-static void il_client_connection(ipc_callid_t iid, ipc_call_t *icall)
-{
-	/*
-	 * Accept the connection
-	 *  - Answer the first IPC_M_CONNECT_ME_TO call.
-	 */
-	ipc_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 = il_module_message(callid, &call, &answer,
-		    &count);
-		
-		/*
-		 * End if told to either by the message or the processing
-		 * result.
-		 */
-		if ((IPC_GET_IMETHOD(call) == IPC_M_PHONE_HUNGUP) ||
-		    (res == EHANGUP))
-			return;
-		
-		/* Answer the message */
-		answer_call(callid, res, &answer, count);
-	}
-}
-
 int main(int argc, char *argv[])
 {
 	/* Start the module */
-	return il_module_start(il_client_connection);
+	return il_module_start(SERVICE_ARP);
 }
 
Index: uspace/srv/net/il/arp/arp.h
===================================================================
--- uspace/srv/net/il/arp/arp.h	(revision 73ac2e9cfc27b4ece704510e8fe908610ae7a583)
+++ uspace/srv/net/il/arp/arp.h	(revision 797b704b28bced20e17a9eb959845c20363ce662)
@@ -125,10 +125,4 @@
 	arp_cache_t cache;
 	
-	/**
-	 * The client connection processing function.
-	 * The module skeleton propagates its own one.
-	 */
-	async_client_conn_t client_connection;
-	
 	/** Networking module phone. */
 	int net_phone;
Index: uspace/srv/net/il/arp/arp_header.h
===================================================================
--- uspace/srv/net/il/arp/arp_header.h	(revision 73ac2e9cfc27b4ece704510e8fe908610ae7a583)
+++ 	(revision )
@@ -1,73 +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 arp
- *  @{
- */
-
-/** @file
- * ARP protocol header.
- * Based on the RFC 826.
- */
-
-#ifndef NET_ARP_HEADER_H_
-#define NET_ARP_HEADER_H_
-
-#include <sys/types.h>
-
-/** Type definition of an ARP protocol header.
- * @see arp_header
- */
-typedef struct arp_header arp_header_t;
-
-/** ARP protocol header. */
-struct arp_header {
-	/**
-	 * Hardware type identifier.
-	 * @see hardware.h
-	 */
-	uint16_t hardware;
-	
-	/** Protocol identifier. */
-	uint16_t protocol;
-	/** Hardware address length in bytes. */
-	uint8_t hardware_length;
-	/** Protocol address length in bytes. */
-	uint8_t protocol_length;
-	
-	/**
-	 * ARP packet type.
-	 * @see arp_oc.h
-	 */
-	uint16_t operation;
-} __attribute__ ((packed));
-
-#endif
-
-/** @}
- */
Index: uspace/srv/net/il/arp/arp_module.c
===================================================================
--- uspace/srv/net/il/arp/arp_module.c	(revision 73ac2e9cfc27b4ece704510e8fe908610ae7a583)
+++ 	(revision )
@@ -1,92 +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 arp
- *  @{
- */
-
-/** @file
- * ARP standalone module implementation.
- * Contains skeleton module functions mapping.
- * The functions are used by the module skeleton as module specific entry
- * points.
- * @see module.c
- */
-
-#include <async.h>
-#include <stdio.h>
-#include <errno.h>
-
-#include <ipc/ipc.h>
-#include <ipc/services.h>
-
-#include <net/modules.h>
-#include <net_interface.h>
-#include <net/packet.h>
-#include <il_local.h>
-
-#include "arp.h"
-#include "arp_module.h"
-
-/** ARP module global data. */
-extern arp_globals_t arp_globals;
-
-int il_module_message(ipc_callid_t callid, ipc_call_t *call,
-    ipc_call_t *answer, size_t *count)
-{
-	return arp_message(callid, call, answer, count);
-}
-
-int il_module_start(async_client_conn_t client_connection)
-{
-	sysarg_t phonehash;
-	
-	async_set_client_connection(client_connection);
-	arp_globals.net_phone = net_connect_module();
-	
-	int rc = pm_init();
-	if (rc != EOK)
-		return rc;
-	
-	rc = arp_initialize(client_connection);
-	if (rc != EOK)
-		goto out;
-	
-	rc = ipc_connect_to_me(PHONE_NS, SERVICE_ARP, 0, 0, &phonehash);
-	if (rc != EOK)
-		goto out;
-	
-	async_manager();
-	
-out:
-	pm_destroy();
-	return rc;
-}
-
-/** @}
- */
Index: uspace/srv/net/il/arp/arp_module.h
===================================================================
--- uspace/srv/net/il/arp/arp_module.h	(revision 73ac2e9cfc27b4ece704510e8fe908610ae7a583)
+++ 	(revision )
@@ -1,51 +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 arp
- * @{
- */
-
-/** @file
- * ARP module functions.
- * The functions are used as ARP module entry points.
- */
-
-#ifndef NET_ARP_MODULE_H_
-#define NET_ARP_MODULE_H_
-
-#include <ipc/ipc.h>
-#include <async.h>
-
-extern int arp_initialize(async_client_conn_t);
-extern int arp_message(ipc_callid_t, ipc_call_t *, ipc_call_t *,
-    size_t *);
-
-#endif
-
-/** @}
- */
Index: uspace/srv/net/il/arp/arp_oc.h
===================================================================
--- uspace/srv/net/il/arp/arp_oc.h	(revision 73ac2e9cfc27b4ece704510e8fe908610ae7a583)
+++ 	(revision )
@@ -1,57 +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 arp
- *  @{
- */
-
-/** @file
- * ARP operation codes according to the on-line IANA - Address Resolution
- * Protocol (ARP) Parameters
- * http://www.iana.org/assignments/arp-parameters/arp-parameters.xml
- * cited January 14 2009.
- */
-
-#ifndef NET_ARP_ARPOP_H_
-#define NET_ARP_ARPOP_H_
-
-/** @name ARP operation codes definitions */
-/*@{*/
-
-/** REQUEST operation code. */
-#define ARPOP_REQUEST	1
-
-/** REPLY operation code. */
-#define ARPOP_REPLY	2
-
-/*@}*/
-
-#endif
-
-/** @}
- */
Index: uspace/srv/net/il/ip/Makefile
===================================================================
--- uspace/srv/net/il/ip/Makefile	(revision 73ac2e9cfc27b4ece704510e8fe908610ae7a583)
+++ uspace/srv/net/il/ip/Makefile	(revision 797b704b28bced20e17a9eb959845c20363ce662)
@@ -34,6 +34,5 @@
 
 SOURCES = \
-	ip.c \
-	ip_module.c
+	ip.c
 
 include $(USPACE_PREFIX)/Makefile.common
Index: uspace/srv/net/il/ip/ip.c
===================================================================
--- uspace/srv/net/il/ip/ip.c	(revision 73ac2e9cfc27b4ece704510e8fe908610ae7a583)
+++ uspace/srv/net/il/ip/ip.c	(revision 797b704b28bced20e17a9eb959845c20363ce662)
@@ -35,7 +35,4 @@
  * @see arp.h
  */
-
-#include "ip.h"
-#include "ip_module.h"
 
 #include <async.h>
@@ -52,4 +49,5 @@
 #include <sys/types.h>
 #include <byteorder.h>
+#include "ip.h"
 
 #include <adt/measured_strings.h>
@@ -70,5 +68,4 @@
 #include <icmp_client.h>
 #include <icmp_interface.h>
-#include <il_interface.h>
 #include <ip_client.h>
 #include <ip_interface.h>
@@ -78,5 +75,6 @@
 #include <tl_interface.h>
 #include <packet_remote.h>
-#include <il_local.h>
+#include <il_remote.h>
+#include <il_skel.h>
 
 /** IP module name. */
@@ -122,4 +120,6 @@
 INT_MAP_IMPLEMENT(ip_protos, ip_proto_t);
 GENERIC_FIELD_IMPLEMENT(ip_routes, ip_route_t);
+
+static void ip_receiver(ipc_callid_t, ipc_call_t *);
 
 /** Releases the packet and returns the result.
@@ -244,19 +244,12 @@
 }
 
-/** Initializes the IP module.
- *
- * @param[in] client_connection The client connection processing function. The
- *			module skeleton propagates its own one.
- * @return		EOK on success.
- * @return		ENOMEM if there is not enough memory left.
- */
-int ip_initialize(async_client_conn_t client_connection)
-{
-	int rc;
-
+int il_initialize(int net_phone)
+{
 	fibril_rwlock_initialize(&ip_globals.lock);
 	fibril_rwlock_write_lock(&ip_globals.lock);
 	fibril_rwlock_initialize(&ip_globals.protos_lock);
 	fibril_rwlock_initialize(&ip_globals.netifs_lock);
+	
+	ip_globals.net_phone = net_phone;
 	ip_globals.packet_counter = 0;
 	ip_globals.gateway.address.s_addr = 0;
@@ -264,7 +257,6 @@
 	ip_globals.gateway.gateway.s_addr = 0;
 	ip_globals.gateway.netif = NULL;
-	ip_globals.client_connection = client_connection;
-	
-	rc = ip_netifs_initialize(&ip_globals.netifs);
+	
+	int rc = ip_netifs_initialize(&ip_globals.netifs);
 	if (rc != EOK)
 		goto out;
@@ -431,5 +423,5 @@
 	ip_netif->phone = nil_bind_service(ip_netif->service,
 	    (sysarg_t) ip_netif->device_id, SERVICE_IP,
-	    ip_globals.client_connection);
+	    ip_receiver);
 	if (ip_netif->phone < 0) {
 		printf("Failed to contact the nil service %d\n",
@@ -487,75 +479,140 @@
 }
 
-/** Updates the device content length according to the new MTU value.
- *
- * @param[in] device_id	The device identifier.
- * @param[in] mtu	The new mtu value.
- * @return		EOK on success.
- * @return		ENOENT if device is not found.
- */
-static int ip_mtu_changed_message(device_id_t device_id, size_t mtu)
-{
+static int ip_device_req_local(int il_phone, device_id_t device_id,
+    services_t netif)
+{
+	ip_netif_t *ip_netif;
+	ip_route_t *route;
+	int index;
+	int rc;
+
+	ip_netif = (ip_netif_t *) malloc(sizeof(ip_netif_t));
+	if (!ip_netif)
+		return ENOMEM;
+
+	rc = ip_routes_initialize(&ip_netif->routes);
+	if (rc != EOK) {
+		free(ip_netif);
+		return rc;
+	}
+
+	ip_netif->device_id = device_id;
+	ip_netif->service = netif;
+	ip_netif->state = NETIF_STOPPED;
+
+	fibril_rwlock_write_lock(&ip_globals.netifs_lock);
+
+	rc = ip_netif_initialize(ip_netif);
+	if (rc != EOK) {
+		fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
+		ip_routes_destroy(&ip_netif->routes);
+		free(ip_netif);
+		return rc;
+	}
+	if (ip_netif->arp)
+		ip_netif->arp->usage++;
+
+	// print the settings
+	printf("%s: Device registered (id: %d, phone: %d, ipv: %d, conf: %s)\n",
+	    NAME, ip_netif->device_id, ip_netif->phone, ip_netif->ipv,
+	    ip_netif->dhcp ? "dhcp" : "static");
+	
+	// TODO ipv6 addresses
+	
+	char address[INET_ADDRSTRLEN];
+	char netmask[INET_ADDRSTRLEN];
+	char gateway[INET_ADDRSTRLEN];
+	
+	for (index = 0; index < ip_routes_count(&ip_netif->routes); index++) {
+		route = ip_routes_get_index(&ip_netif->routes, index);
+		if (route) {
+			inet_ntop(AF_INET, (uint8_t *) &route->address.s_addr,
+			    address, INET_ADDRSTRLEN);
+			inet_ntop(AF_INET, (uint8_t *) &route->netmask.s_addr,
+			    netmask, INET_ADDRSTRLEN);
+			inet_ntop(AF_INET, (uint8_t *) &route->gateway.s_addr,
+			    gateway, INET_ADDRSTRLEN);
+			printf("%s: Route %d (address: %s, netmask: %s, "
+			    "gateway: %s)\n", NAME, index, address, netmask,
+			    gateway);
+		}
+	}
+	
+	inet_ntop(AF_INET, (uint8_t *) &ip_netif->broadcast.s_addr, address,
+	    INET_ADDRSTRLEN);
+	fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
+
+	printf("%s: Broadcast (%s)\n", NAME, address);
+
+	return EOK;
+}
+
+/** Searches the network interfaces if there is a suitable route.
+ *
+ * @param[in] netif	The network interface to be searched for routes. May be
+ *			NULL.
+ * @param[in] destination The destination address.
+ * @return		The found route.
+ * @return		NULL if no route was found.
+ */
+static ip_route_t *ip_netif_find_route(ip_netif_t *netif,
+    in_addr_t destination)
+{
+	int index;
+	ip_route_t *route;
+	
+	if (!netif)
+		return NULL;
+	
+	/* Start with the first one (the direct route) */
+	for (index = 0; index < ip_routes_count(&netif->routes); index++) {
+		route = ip_routes_get_index(&netif->routes, index);
+		if ((route) &&
+		    ((route->address.s_addr & route->netmask.s_addr) ==
+		    (destination.s_addr & route->netmask.s_addr)))
+			return route;
+	}
+
+	return NULL;
+}
+
+/** Searches all network interfaces if there is a suitable route.
+ *
+ * @param[in] destination The destination address.
+ * @return		The found route.
+ * @return		NULL if no route was found.
+ */
+static ip_route_t *ip_find_route(in_addr_t destination) {
+	int index;
+	ip_route_t *route;
 	ip_netif_t *netif;
 
-	fibril_rwlock_write_lock(&ip_globals.netifs_lock);
-	netif = ip_netifs_find(&ip_globals.netifs, device_id);
-	if (!netif) {
-		fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
-		return ENOENT;
-	}
-	netif->packet_dimension.content = mtu;
-	fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
-
-	printf("%s: Device %d changed MTU to %zu\n", NAME, device_id, mtu);
-
-	return EOK;
-}
-
-/** Updates the device state.
- *
- * @param[in] device_id	The device identifier.
- * @param[in] state	The new state value.
- * @return		EOK on success.
- * @return		ENOENT if device is not found.
- */
-static int ip_device_state_message(device_id_t device_id, device_state_t state)
-{
-	ip_netif_t *netif;
-
-	fibril_rwlock_write_lock(&ip_globals.netifs_lock);
-	// find the device
-	netif = ip_netifs_find(&ip_globals.netifs, device_id);
-	if (!netif) {
-		fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
-		return ENOENT;
-	}
-	netif->state = state;
-	fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
-
-	printf("%s: Device %d changed state to %d\n", NAME, device_id, state);
-
-	return EOK;
-}
-
-
-/** Prefixes a middle fragment header based on the last fragment header to the
- * packet.
- *
- * @param[in] packet	The packet to be prefixed.
- * @param[in] last	The last header to be copied.
- * @return		The prefixed middle header.
- * @return		NULL on error.
- */
-static ip_header_t *
-ip_create_middle_header(packet_t *packet, ip_header_t *last)
-{
-	ip_header_t *middle;
-
-	middle = (ip_header_t *) packet_suffix(packet, IP_HEADER_LENGTH(last));
-	if (!middle)
-		return NULL;
-	memcpy(middle, last, IP_HEADER_LENGTH(last));
-	middle->flags |= IPFLAG_MORE_FRAGMENTS;
-	return middle;
+	// start with the last netif - the newest one
+	index = ip_netifs_count(&ip_globals.netifs) - 1;
+	while (index >= 0) {
+		netif = ip_netifs_get_index(&ip_globals.netifs, index);
+		if (netif && (netif->state == NETIF_ACTIVE)) {
+			route = ip_netif_find_route(netif, destination);
+			if (route)
+				return route;
+		}
+		index--;
+	}
+
+	return &ip_globals.gateway;
+}
+
+/** Returns the network interface's IP address.
+ *
+ * @param[in] netif	The network interface.
+ * @return		The IP address.
+ * @return		NULL if no IP address was found.
+ */
+static in_addr_t *ip_netif_address(ip_netif_t *netif)
+{
+	ip_route_t *route;
+
+	route = ip_routes_get_index(&netif->routes, 0);
+	return route ? &route->address : NULL;
 }
 
@@ -626,7 +683,6 @@
  *			function.
  */
-static int
-ip_prepare_packet(in_addr_t *source, in_addr_t dest, packet_t *packet,
-    measured_string_t *destination)
+static int ip_prepare_packet(in_addr_t *source, in_addr_t dest,
+    packet_t *packet, measured_string_t *destination)
 {
 	size_t length;
@@ -757,6 +813,5 @@
  *			function.
  */
-static int
-ip_fragment_packet_data(packet_t *packet, packet_t *new_packet,
+static int ip_fragment_packet_data(packet_t *packet, packet_t *new_packet,
     ip_header_t *header, ip_header_t *new_header, size_t length,
     const struct sockaddr *src, const struct sockaddr *dest, socklen_t addrlen)
@@ -792,4 +847,25 @@
 
 	return pq_insert_after(packet, new_packet);
+}
+
+/** Prefixes a middle fragment header based on the last fragment header to the
+ * packet.
+ *
+ * @param[in] packet	The packet to be prefixed.
+ * @param[in] last	The last header to be copied.
+ * @return		The prefixed middle header.
+ * @return		NULL on error.
+ */
+static ip_header_t *ip_create_middle_header(packet_t *packet,
+    ip_header_t *last)
+{
+	ip_header_t *middle;
+
+	middle = (ip_header_t *) packet_suffix(packet, IP_HEADER_LENGTH(last));
+	if (!middle)
+		return NULL;
+	memcpy(middle, last, IP_HEADER_LENGTH(last));
+	middle->flags |= IPFLAG_MORE_FRAGMENTS;
+	return middle;
 }
 
@@ -996,7 +1072,6 @@
  *			function.
  */
-static int
-ip_send_route(packet_t *packet, ip_netif_t *netif, ip_route_t *route,
-    in_addr_t *src, in_addr_t dest, services_t error)
+static int ip_send_route(packet_t *packet, ip_netif_t *netif,
+    ip_route_t *route, in_addr_t *src, in_addr_t dest, services_t error)
 {
 	measured_string_t destination;
@@ -1061,195 +1136,6 @@
 }
 
-/** Searches the network interfaces if there is a suitable route.
- *
- * @param[in] netif	The network interface to be searched for routes. May be
- *			NULL.
- * @param[in] destination The destination address.
- * @return		The found route.
- * @return		NULL if no route was found.
- */
-static ip_route_t *
-ip_netif_find_route(ip_netif_t *netif, in_addr_t destination)
-{
-	int index;
-	ip_route_t *route;
-	
-	if (!netif)
-		return NULL;
-	
-	/* Start with the first one (the direct route) */
-	for (index = 0; index < ip_routes_count(&netif->routes); index++) {
-		route = ip_routes_get_index(&netif->routes, index);
-		if ((route) &&
-		    ((route->address.s_addr & route->netmask.s_addr) ==
-		    (destination.s_addr & route->netmask.s_addr)))
-			return route;
-	}
-
-	return NULL;
-}
-
-/** Searches all network interfaces if there is a suitable route.
- *
- * @param[in] destination The destination address.
- * @return		The found route.
- * @return		NULL if no route was found.
- */
-static ip_route_t *ip_find_route(in_addr_t destination) {
-	int index;
-	ip_route_t *route;
-	ip_netif_t *netif;
-
-	// start with the last netif - the newest one
-	index = ip_netifs_count(&ip_globals.netifs) - 1;
-	while (index >= 0) {
-		netif = ip_netifs_get_index(&ip_globals.netifs, index);
-		if (netif && (netif->state == NETIF_ACTIVE)) {
-			route = ip_netif_find_route(netif, destination);
-			if (route)
-				return route;
-		}
-		index--;
-	}
-
-	return &ip_globals.gateway;
-}
-
-/** Returns the network interface's IP address.
- *
- * @param[in] netif	The network interface.
- * @return		The IP address.
- * @return		NULL if no IP address was found.
- */
-static in_addr_t *ip_netif_address(ip_netif_t *netif)
-{
-	ip_route_t *route;
-
-	route = ip_routes_get_index(&netif->routes, 0);
-	return route ? &route->address : NULL;
-}
-
-/** Registers the transport layer protocol.
- *
- * The traffic of this protocol will be supplied using either the receive
- * function or IPC message.
- *
- * @param[in] protocol	The transport layer module protocol.
- * @param[in] service	The transport layer module service.
- * @param[in] phone	The transport layer module phone.
- * @param[in] received_msg The receiving function.
- * @return		EOK on success.
- * @return		EINVAL if the protocol parameter and/or the service
- *			parameter is zero.
- * @return		EINVAL if the phone parameter is not a positive number
- *			and the tl_receive_msg is NULL.
- * @return		ENOMEM if there is not enough memory left.
- */
-static int
-ip_register(int protocol, services_t service, int phone,
-    tl_received_msg_t received_msg)
-{
-	ip_proto_t *proto;
-	int index;
-
-	if (!protocol || !service || ((phone < 0) && !received_msg))
-		return EINVAL;
-
-	proto = (ip_proto_t *) malloc(sizeof(ip_protos_t));
-	if (!proto)
-		return ENOMEM;
-
-	proto->protocol = protocol;
-	proto->service = service;
-	proto->phone = phone;
-	proto->received_msg = received_msg;
-
-	fibril_rwlock_write_lock(&ip_globals.protos_lock);
-	index = ip_protos_add(&ip_globals.protos, proto->protocol, proto);
-	if (index < 0) {
-		fibril_rwlock_write_unlock(&ip_globals.protos_lock);
-		free(proto);
-		return index;
-	}
-	fibril_rwlock_write_unlock(&ip_globals.protos_lock);
-
-	printf("%s: Protocol registered (protocol: %d, phone: %d)\n",
-	    NAME, proto->protocol, proto->phone);
-
-	return EOK;
-}
-
-static int
-ip_device_req_local(int il_phone, device_id_t device_id, services_t netif)
-{
-	ip_netif_t *ip_netif;
-	ip_route_t *route;
-	int index;
-	int rc;
-
-	ip_netif = (ip_netif_t *) malloc(sizeof(ip_netif_t));
-	if (!ip_netif)
-		return ENOMEM;
-
-	rc = ip_routes_initialize(&ip_netif->routes);
-	if (rc != EOK) {
-		free(ip_netif);
-		return rc;
-	}
-
-	ip_netif->device_id = device_id;
-	ip_netif->service = netif;
-	ip_netif->state = NETIF_STOPPED;
-
-	fibril_rwlock_write_lock(&ip_globals.netifs_lock);
-
-	rc = ip_netif_initialize(ip_netif);
-	if (rc != EOK) {
-		fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
-		ip_routes_destroy(&ip_netif->routes);
-		free(ip_netif);
-		return rc;
-	}
-	if (ip_netif->arp)
-		ip_netif->arp->usage++;
-
-	// print the settings
-	printf("%s: Device registered (id: %d, phone: %d, ipv: %d, conf: %s)\n",
-	    NAME, ip_netif->device_id, ip_netif->phone, ip_netif->ipv,
-	    ip_netif->dhcp ? "dhcp" : "static");
-	
-	// TODO ipv6 addresses
-	
-	char address[INET_ADDRSTRLEN];
-	char netmask[INET_ADDRSTRLEN];
-	char gateway[INET_ADDRSTRLEN];
-	
-	for (index = 0; index < ip_routes_count(&ip_netif->routes); index++) {
-		route = ip_routes_get_index(&ip_netif->routes, index);
-		if (route) {
-			inet_ntop(AF_INET, (uint8_t *) &route->address.s_addr,
-			    address, INET_ADDRSTRLEN);
-			inet_ntop(AF_INET, (uint8_t *) &route->netmask.s_addr,
-			    netmask, INET_ADDRSTRLEN);
-			inet_ntop(AF_INET, (uint8_t *) &route->gateway.s_addr,
-			    gateway, INET_ADDRSTRLEN);
-			printf("%s: Route %d (address: %s, netmask: %s, "
-			    "gateway: %s)\n", NAME, index, address, netmask,
-			    gateway);
-		}
-	}
-	
-	inet_ntop(AF_INET, (uint8_t *) &ip_netif->broadcast.s_addr, address,
-	    INET_ADDRSTRLEN);
-	fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
-
-	printf("%s: Broadcast (%s)\n", NAME, address);
-
-	return EOK;
-}
-
-static int
-ip_send_msg_local(int il_phone, device_id_t device_id, packet_t *packet,
-    services_t sender, services_t error)
+static int ip_send_msg_local(int il_phone, device_id_t device_id,
+    packet_t *packet, services_t sender, services_t error)
 {
 	int addrlen;
@@ -1355,4 +1241,256 @@
 }
 
+/** Updates the device state.
+ *
+ * @param[in] device_id	The device identifier.
+ * @param[in] state	The new state value.
+ * @return		EOK on success.
+ * @return		ENOENT if device is not found.
+ */
+static int ip_device_state_message(device_id_t device_id, device_state_t state)
+{
+	ip_netif_t *netif;
+
+	fibril_rwlock_write_lock(&ip_globals.netifs_lock);
+	// find the device
+	netif = ip_netifs_find(&ip_globals.netifs, device_id);
+	if (!netif) {
+		fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
+		return ENOENT;
+	}
+	netif->state = state;
+	fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
+
+	printf("%s: Device %d changed state to %d\n", NAME, device_id, state);
+
+	return EOK;
+}
+
+/** Returns the packet destination address from the IP header.
+ *
+ * @param[in] header	The packet IP header to be read.
+ * @return		The packet destination address.
+ */
+static in_addr_t ip_get_destination(ip_header_t *header)
+{
+	in_addr_t destination;
+
+	// TODO search set ipopt route?
+	destination.s_addr = header->destination_address;
+	return destination;
+}
+
+/** Delivers the packet to the local host.
+ *
+ * The packet is either passed to another module or released on error.
+ * The ICMP_PROT_UNREACH error notification may be sent if the protocol is not
+ * found.
+ *
+ * @param[in] device_id	The source device identifier.
+ * @param[in] packet	The packet to be delivered.
+ * @param[in] header	The first packet IP header. May be NULL.
+ * @param[in] error	The packet error service.
+ * @return		EOK on success.
+ * @return		ENOTSUP if the packet is a fragment.
+ * @return		EAFNOSUPPORT if the address family is not supported.
+ * @return		ENOENT if the target protocol is not found.
+ * @return		Other error codes as defined for the packet_set_addr()
+ *			function.
+ * @return		Other error codes as defined for the packet_trim()
+ *			function.
+ * @return		Other error codes as defined for the protocol specific
+ *			tl_received_msg() function.
+ */
+static int ip_deliver_local(device_id_t device_id, packet_t *packet,
+    ip_header_t *header, services_t error)
+{
+	ip_proto_t *proto;
+	int phone;
+	services_t service;
+	tl_received_msg_t received_msg;
+	struct sockaddr *src;
+	struct sockaddr *dest;
+	struct sockaddr_in src_in;
+	struct sockaddr_in dest_in;
+	socklen_t addrlen;
+	int rc;
+
+	if ((header->flags & IPFLAG_MORE_FRAGMENTS) ||
+	    IP_FRAGMENT_OFFSET(header)) {
+		// TODO fragmented
+		return ENOTSUP;
+	}
+	
+	switch (header->version) {
+	case IPVERSION:
+		addrlen = sizeof(src_in);
+		bzero(&src_in, addrlen);
+		src_in.sin_family = AF_INET;
+		memcpy(&dest_in, &src_in, addrlen);
+		memcpy(&src_in.sin_addr.s_addr, &header->source_address,
+		    sizeof(header->source_address));
+		memcpy(&dest_in.sin_addr.s_addr, &header->destination_address,
+		    sizeof(header->destination_address));
+		src = (struct sockaddr *) &src_in;
+		dest = (struct sockaddr *) &dest_in;
+		break;
+
+	default:
+		return ip_release_and_return(packet, EAFNOSUPPORT);
+	}
+
+	rc = packet_set_addr(packet, (uint8_t *) src, (uint8_t *) dest,
+	    addrlen);
+	if (rc != EOK)
+		return ip_release_and_return(packet, rc);
+
+	// trim padding if present
+	if (!error &&
+	    (IP_TOTAL_LENGTH(header) < packet_get_data_length(packet))) {
+		rc = packet_trim(packet, 0,
+		    packet_get_data_length(packet) - IP_TOTAL_LENGTH(header));
+		if (rc != EOK)
+			return ip_release_and_return(packet, rc);
+	}
+
+	fibril_rwlock_read_lock(&ip_globals.protos_lock);
+
+	proto = ip_protos_find(&ip_globals.protos, header->protocol);
+	if (!proto) {
+		fibril_rwlock_read_unlock(&ip_globals.protos_lock);
+		phone = ip_prepare_icmp_and_get_phone(error, packet, header);
+		if (phone >= 0) {
+			// unreachable ICMP
+			icmp_destination_unreachable_msg(phone,
+			    ICMP_PROT_UNREACH, 0, packet);
+		}
+		return ENOENT;
+	}
+
+	if (proto->received_msg) {
+		service = proto->service;
+		received_msg = proto->received_msg;
+		fibril_rwlock_read_unlock(&ip_globals.protos_lock);
+		rc = received_msg(device_id, packet, service, error);
+	} else {
+		rc = tl_received_msg(proto->phone, device_id, packet,
+		    proto->service, error);
+		fibril_rwlock_read_unlock(&ip_globals.protos_lock);
+	}
+
+	return rc;
+}
+
+/** Processes the received packet.
+ *
+ * The packet is either passed to another module or released on error.
+ *
+ * The ICMP_PARAM_POINTER error notification may be sent if the checksum is
+ * invalid.
+ * The ICMP_EXC_TTL error notification may be sent if the TTL is less than two.
+ * The ICMP_HOST_UNREACH error notification may be sent if no route was found.
+ * The ICMP_HOST_UNREACH error notification may be sent if the packet is for
+ * another host and the routing is disabled.
+ *
+ * @param[in] device_id	The source device identifier.
+ * @param[in] packet	The received packet to be processed.
+ * @return		EOK on success.
+ * @return		EINVAL if the TTL is less than two.
+ * @return		EINVAL if the checksum is invalid.
+ * @return		EAFNOSUPPORT if the address family is not supported.
+ * @return		ENOENT if no route was found.
+ * @return		ENOENT if the packet is for another host and the routing
+ *			is disabled.
+ */
+static int ip_process_packet(device_id_t device_id, packet_t *packet)
+{
+	ip_header_t *header;
+	in_addr_t dest;
+	ip_route_t *route;
+	int phone;
+	struct sockaddr *addr;
+	struct sockaddr_in addr_in;
+	socklen_t addrlen;
+	int rc;
+	
+	header = (ip_header_t *) packet_get_data(packet);
+	if (!header)
+		return ip_release_and_return(packet, ENOMEM);
+
+	// checksum
+	if ((header->header_checksum) &&
+	    (IP_HEADER_CHECKSUM(header) != IP_CHECKSUM_ZERO)) {
+		phone = ip_prepare_icmp_and_get_phone(0, packet, header);
+		if (phone >= 0) {
+			// checksum error ICMP
+			icmp_parameter_problem_msg(phone, ICMP_PARAM_POINTER,
+			    ((size_t) ((void *) &header->header_checksum)) -
+			    ((size_t) ((void *) header)), packet);
+		}
+		return EINVAL;
+	}
+
+	if (header->ttl <= 1) {
+		phone = ip_prepare_icmp_and_get_phone(0, packet, header);
+		if (phone >= 0) {
+			// ttl exceeded ICMP
+			icmp_time_exceeded_msg(phone, ICMP_EXC_TTL, packet);
+		}
+		return EINVAL;
+	}
+	
+	// process ipopt and get destination
+	dest = ip_get_destination(header);
+
+	// set the addrination address
+	switch (header->version) {
+	case IPVERSION:
+		addrlen = sizeof(addr_in);
+		bzero(&addr_in, addrlen);
+		addr_in.sin_family = AF_INET;
+		memcpy(&addr_in.sin_addr.s_addr, &dest, sizeof(dest));
+		addr = (struct sockaddr *) &addr_in;
+		break;
+
+	default:
+		return ip_release_and_return(packet, EAFNOSUPPORT);
+	}
+
+	rc = packet_set_addr(packet, NULL, (uint8_t *) &addr, addrlen);
+	if (rc != EOK)
+		return rc;
+	
+	route = ip_find_route(dest);
+	if (!route) {
+		phone = ip_prepare_icmp_and_get_phone(0, packet, header);
+		if (phone >= 0) {
+			// unreachable ICMP
+			icmp_destination_unreachable_msg(phone,
+			    ICMP_HOST_UNREACH, 0, packet);
+		}
+		return ENOENT;
+	}
+
+	if (route->address.s_addr == dest.s_addr) {
+		// local delivery
+		return ip_deliver_local(device_id, packet, header, 0);
+	}
+
+	if (route->netif->routing) {
+		header->ttl--;
+		return ip_send_route(packet, route->netif, route, NULL, dest,
+		    0);
+	}
+
+	phone = ip_prepare_icmp_and_get_phone(0, packet, header);
+	if (phone >= 0) {
+		// unreachable ICMP if no routing
+		icmp_destination_unreachable_msg(phone, ICMP_HOST_UNREACH, 0,
+		    packet);
+	}
+	
+	return ENOENT;
+}
+
 /** Returns the device packet dimensions for sending.
  *
@@ -1366,7 +1504,6 @@
  * @return		EOK on success.
  */
-static int
-ip_packet_size_message(device_id_t device_id, size_t *addr_len, size_t *prefix,
-    size_t *content, size_t *suffix)
+static int ip_packet_size_message(device_id_t device_id, size_t *addr_len,
+    size_t *prefix, size_t *content, size_t *suffix)
 {
 	ip_netif_t *netif;
@@ -1418,231 +1555,126 @@
 }
 
-/** Returns the packet destination address from the IP header.
- *
- * @param[in] header	The packet IP header to be read.
- * @return		The packet destination address.
- */
-static in_addr_t ip_get_destination(ip_header_t *header)
-{
-	in_addr_t destination;
-
-	// TODO search set ipopt route?
-	destination.s_addr = header->destination_address;
-	return destination;
-}
-
-/** Delivers the packet to the local host.
- *
- * The packet is either passed to another module or released on error.
- * The ICMP_PROT_UNREACH error notification may be sent if the protocol is not
- * found.
- *
- * @param[in] device_id	The source device identifier.
- * @param[in] packet	The packet to be delivered.
- * @param[in] header	The first packet IP header. May be NULL.
- * @param[in] error	The packet error service.
+/** Updates the device content length according to the new MTU value.
+ *
+ * @param[in] device_id	The device identifier.
+ * @param[in] mtu	The new mtu value.
  * @return		EOK on success.
- * @return		ENOTSUP if the packet is a fragment.
- * @return		EAFNOSUPPORT if the address family is not supported.
- * @return		ENOENT if the target protocol is not found.
- * @return		Other error codes as defined for the packet_set_addr()
- *			function.
- * @return		Other error codes as defined for the packet_trim()
- *			function.
- * @return		Other error codes as defined for the protocol specific
- *			tl_received_msg() function.
+ * @return		ENOENT if device is not found.
+ */
+static int ip_mtu_changed_message(device_id_t device_id, size_t mtu)
+{
+	ip_netif_t *netif;
+
+	fibril_rwlock_write_lock(&ip_globals.netifs_lock);
+	netif = ip_netifs_find(&ip_globals.netifs, device_id);
+	if (!netif) {
+		fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
+		return ENOENT;
+	}
+	netif->packet_dimension.content = mtu;
+	fibril_rwlock_write_unlock(&ip_globals.netifs_lock);
+
+	printf("%s: Device %d changed MTU to %zu\n", NAME, device_id, mtu);
+
+	return EOK;
+}
+
+/** Process IPC messages from the registered device driver modules
+ *
+ * @param[in]     iid   Message identifier.
+ * @param[in,out] icall Message parameters.
+ *
+ */
+static void ip_receiver(ipc_callid_t iid, ipc_call_t *icall)
+{
+	packet_t *packet;
+	int rc;
+	
+	while (true) {
+		switch (IPC_GET_IMETHOD(*icall)) {
+		case NET_IL_DEVICE_STATE:
+			rc = ip_device_state_message(IPC_GET_DEVICE(*icall),
+			    IPC_GET_STATE(*icall));
+			ipc_answer_0(iid, (sysarg_t) rc);
+			break;
+		
+		case NET_IL_RECEIVED:
+			rc = packet_translate_remote(ip_globals.net_phone, &packet,
+			    IPC_GET_PACKET(*icall));
+			if (rc == EOK) {
+				do {
+					packet_t *next = pq_detach(packet);
+					ip_process_packet(IPC_GET_DEVICE(*icall), packet);
+					packet = next;
+				} while (packet);
+			}
+			
+			ipc_answer_0(iid, (sysarg_t) rc);
+			break;
+		
+		case NET_IL_MTU_CHANGED:
+			rc = ip_mtu_changed_message(IPC_GET_DEVICE(*icall),
+			    IPC_GET_MTU(*icall));
+			ipc_answer_0(iid, (sysarg_t) rc);
+			break;
+		
+		default:
+			ipc_answer_0(iid, (sysarg_t) ENOTSUP);
+		}
+		
+		iid = async_get_call(icall);
+	}
+}
+
+/** Registers the transport layer protocol.
+ *
+ * The traffic of this protocol will be supplied using either the receive
+ * function or IPC message.
+ *
+ * @param[in] protocol	The transport layer module protocol.
+ * @param[in] service	The transport layer module service.
+ * @param[in] phone	The transport layer module phone.
+ * @param[in] received_msg The receiving function.
+ * @return		EOK on success.
+ * @return		EINVAL if the protocol parameter and/or the service
+ *			parameter is zero.
+ * @return		EINVAL if the phone parameter is not a positive number
+ *			and the tl_receive_msg is NULL.
+ * @return		ENOMEM if there is not enough memory left.
  */
 static int
-ip_deliver_local(device_id_t device_id, packet_t *packet, ip_header_t *header,
-    services_t error)
+ip_register(int protocol, services_t service, int phone,
+    tl_received_msg_t received_msg)
 {
 	ip_proto_t *proto;
-	int phone;
-	services_t service;
-	tl_received_msg_t received_msg;
-	struct sockaddr *src;
-	struct sockaddr *dest;
-	struct sockaddr_in src_in;
-	struct sockaddr_in dest_in;
-	socklen_t addrlen;
-	int rc;
-
-	if ((header->flags & IPFLAG_MORE_FRAGMENTS) ||
-	    IP_FRAGMENT_OFFSET(header)) {
-		// TODO fragmented
-		return ENOTSUP;
-	}
-	
-	switch (header->version) {
-	case IPVERSION:
-		addrlen = sizeof(src_in);
-		bzero(&src_in, addrlen);
-		src_in.sin_family = AF_INET;
-		memcpy(&dest_in, &src_in, addrlen);
-		memcpy(&src_in.sin_addr.s_addr, &header->source_address,
-		    sizeof(header->source_address));
-		memcpy(&dest_in.sin_addr.s_addr, &header->destination_address,
-		    sizeof(header->destination_address));
-		src = (struct sockaddr *) &src_in;
-		dest = (struct sockaddr *) &dest_in;
-		break;
-
-	default:
-		return ip_release_and_return(packet, EAFNOSUPPORT);
-	}
-
-	rc = packet_set_addr(packet, (uint8_t *) src, (uint8_t *) dest,
-	    addrlen);
-	if (rc != EOK)
-		return ip_release_and_return(packet, rc);
-
-	// trim padding if present
-	if (!error &&
-	    (IP_TOTAL_LENGTH(header) < packet_get_data_length(packet))) {
-		rc = packet_trim(packet, 0,
-		    packet_get_data_length(packet) - IP_TOTAL_LENGTH(header));
-		if (rc != EOK)
-			return ip_release_and_return(packet, rc);
-	}
-
-	fibril_rwlock_read_lock(&ip_globals.protos_lock);
-
-	proto = ip_protos_find(&ip_globals.protos, header->protocol);
-	if (!proto) {
-		fibril_rwlock_read_unlock(&ip_globals.protos_lock);
-		phone = ip_prepare_icmp_and_get_phone(error, packet, header);
-		if (phone >= 0) {
-			// unreachable ICMP
-			icmp_destination_unreachable_msg(phone,
-			    ICMP_PROT_UNREACH, 0, packet);
-		}
-		return ENOENT;
-	}
-
-	if (proto->received_msg) {
-		service = proto->service;
-		received_msg = proto->received_msg;
-		fibril_rwlock_read_unlock(&ip_globals.protos_lock);
-		rc = received_msg(device_id, packet, service, error);
-	} else {
-		rc = tl_received_msg(proto->phone, device_id, packet,
-		    proto->service, error);
-		fibril_rwlock_read_unlock(&ip_globals.protos_lock);
-	}
-
-	return rc;
-}
-
-/** Processes the received packet.
- *
- * The packet is either passed to another module or released on error.
- *
- * The ICMP_PARAM_POINTER error notification may be sent if the checksum is
- * invalid.
- * The ICMP_EXC_TTL error notification may be sent if the TTL is less than two.
- * The ICMP_HOST_UNREACH error notification may be sent if no route was found.
- * The ICMP_HOST_UNREACH error notification may be sent if the packet is for
- * another host and the routing is disabled.
- *
- * @param[in] device_id	The source device identifier.
- * @param[in] packet	The received packet to be processed.
- * @return		EOK on success.
- * @return		EINVAL if the TTL is less than two.
- * @return		EINVAL if the checksum is invalid.
- * @return		EAFNOSUPPORT if the address family is not supported.
- * @return		ENOENT if no route was found.
- * @return		ENOENT if the packet is for another host and the routing
- *			is disabled.
- */
-static int
-ip_process_packet(device_id_t device_id, packet_t *packet)
-{
-	ip_header_t *header;
-	in_addr_t dest;
-	ip_route_t *route;
-	int phone;
-	struct sockaddr *addr;
-	struct sockaddr_in addr_in;
-	socklen_t addrlen;
-	int rc;
-	
-	header = (ip_header_t *) packet_get_data(packet);
-	if (!header)
-		return ip_release_and_return(packet, ENOMEM);
-
-	// checksum
-	if ((header->header_checksum) &&
-	    (IP_HEADER_CHECKSUM(header) != IP_CHECKSUM_ZERO)) {
-		phone = ip_prepare_icmp_and_get_phone(0, packet, header);
-		if (phone >= 0) {
-			// checksum error ICMP
-			icmp_parameter_problem_msg(phone, ICMP_PARAM_POINTER,
-			    ((size_t) ((void *) &header->header_checksum)) -
-			    ((size_t) ((void *) header)), packet);
-		}
+	int index;
+
+	if (!protocol || !service || ((phone < 0) && !received_msg))
 		return EINVAL;
-	}
-
-	if (header->ttl <= 1) {
-		phone = ip_prepare_icmp_and_get_phone(0, packet, header);
-		if (phone >= 0) {
-			// ttl exceeded ICMP
-			icmp_time_exceeded_msg(phone, ICMP_EXC_TTL, packet);
-		}
-		return EINVAL;
-	}
-	
-	// process ipopt and get destination
-	dest = ip_get_destination(header);
-
-	// set the addrination address
-	switch (header->version) {
-	case IPVERSION:
-		addrlen = sizeof(addr_in);
-		bzero(&addr_in, addrlen);
-		addr_in.sin_family = AF_INET;
-		memcpy(&addr_in.sin_addr.s_addr, &dest, sizeof(dest));
-		addr = (struct sockaddr *) &addr_in;
-		break;
-
-	default:
-		return ip_release_and_return(packet, EAFNOSUPPORT);
-	}
-
-	rc = packet_set_addr(packet, NULL, (uint8_t *) &addr, addrlen);
-	if (rc != EOK)
-		return rc;
-	
-	route = ip_find_route(dest);
-	if (!route) {
-		phone = ip_prepare_icmp_and_get_phone(0, packet, header);
-		if (phone >= 0) {
-			// unreachable ICMP
-			icmp_destination_unreachable_msg(phone,
-			    ICMP_HOST_UNREACH, 0, packet);
-		}
-		return ENOENT;
-	}
-
-	if (route->address.s_addr == dest.s_addr) {
-		// local delivery
-		return ip_deliver_local(device_id, packet, header, 0);
-	}
-
-	if (route->netif->routing) {
-		header->ttl--;
-		return ip_send_route(packet, route->netif, route, NULL, dest,
-		    0);
-	}
-
-	phone = ip_prepare_icmp_and_get_phone(0, packet, header);
-	if (phone >= 0) {
-		// unreachable ICMP if no routing
-		icmp_destination_unreachable_msg(phone, ICMP_HOST_UNREACH, 0,
-		    packet);
-	}
-	
-	return ENOENT;
-}
+
+	proto = (ip_proto_t *) malloc(sizeof(ip_protos_t));
+	if (!proto)
+		return ENOMEM;
+
+	proto->protocol = protocol;
+	proto->service = service;
+	proto->phone = phone;
+	proto->received_msg = received_msg;
+
+	fibril_rwlock_write_lock(&ip_globals.protos_lock);
+	index = ip_protos_add(&ip_globals.protos, proto->protocol, proto);
+	if (index < 0) {
+		fibril_rwlock_write_unlock(&ip_globals.protos_lock);
+		free(proto);
+		return index;
+	}
+	fibril_rwlock_write_unlock(&ip_globals.protos_lock);
+
+	printf("%s: Protocol registered (protocol: %d, phone: %d)\n",
+	    NAME, proto->protocol, proto->phone);
+
+	return EOK;
+}
+
 
 static int
@@ -1845,33 +1877,4 @@
 }
 
-/** Processes the received IP packet or the packet queue one by one.
- *
- * The packet is either passed to another module or released on error.
- *
- * @param[in] device_id	The source device identifier.
- * @param[in,out] packet The received packet.
- * @return		EOK on success and the packet is no longer needed.
- * @return		EINVAL if the packet is too small to carry the IP
- *			packet.
- * @return		EINVAL if the received address lengths differs from the
- *			registered values.
- * @return		ENOENT if the device is not found in the cache.
- * @return		ENOENT if the protocol for the device is not found in
- *			the cache.
- * @return		ENOMEM if there is not enough memory left.
- */
-static int ip_receive_message(device_id_t device_id, packet_t *packet)
-{
-	packet_t *next;
-
-	do {
-		next = pq_detach(packet);
-		ip_process_packet(device_id, packet);
-		packet = next;
-	} while (packet);
-
-	return EOK;
-}
-
 /** Processes the IP message.
  *
@@ -1885,19 +1888,18 @@
  *
  * @see ip_interface.h
- * @see il_interface.h
+ * @see il_remote.h
  * @see IS_NET_IP_MESSAGE()
  */
-int
-ip_message_standalone(ipc_callid_t callid, ipc_call_t *call, ipc_call_t *answer,
+int il_module_message(ipc_callid_t callid, ipc_call_t *call, ipc_call_t *answer,
     size_t *answer_count)
 {
 	packet_t *packet;
 	struct sockaddr *addr;
+	void *header;
+	size_t headerlen;
 	size_t addrlen;
 	size_t prefix;
 	size_t suffix;
 	size_t content;
-	void *header;
-	size_t headerlen;
 	device_id_t device_id;
 	int rc;
@@ -1912,26 +1914,7 @@
 		    IPC_GET_PHONE(*call), NULL);
 	
-	case NET_IL_DEVICE:
+	case NET_IP_DEVICE:
 		return ip_device_req_local(0, IPC_GET_DEVICE(*call),
 		    IPC_GET_SERVICE(*call));
-	
-	case NET_IL_SEND:
-		rc = packet_translate_remote(ip_globals.net_phone, &packet,
-		    IPC_GET_PACKET(*call));
-		if (rc != EOK)
-			return rc;
-		return ip_send_msg_local(0, IPC_GET_DEVICE(*call), packet, 0,
-		    IPC_GET_ERROR(*call));
-	
-	case NET_IL_DEVICE_STATE:
-		return ip_device_state_message(IPC_GET_DEVICE(*call),
-		    IPC_GET_STATE(*call));
-	
-	case NET_IL_RECEIVED:
-		rc = packet_translate_remote(ip_globals.net_phone, &packet,
-		    IPC_GET_PACKET(*call));
-		if (rc != EOK)
-			return rc;
-		return ip_receive_message(IPC_GET_DEVICE(*call), packet);
 	
 	case NET_IP_RECEIVED_ERROR:
@@ -1975,5 +1958,5 @@
 		return rc;
 	
-	case NET_IL_PACKET_SPACE:
+	case NET_IP_PACKET_SPACE:
 		rc = ip_packet_size_message(IPC_GET_DEVICE(*call), &addrlen,
 		    &prefix, &content, &suffix);
@@ -1988,7 +1971,12 @@
 		return EOK;
 	
-	case NET_IL_MTU_CHANGED:
-		return ip_mtu_changed_message(IPC_GET_DEVICE(*call),
-		    IPC_GET_MTU(*call));
+	case NET_IP_SEND:
+		rc = packet_translate_remote(ip_globals.net_phone, &packet,
+		    IPC_GET_PACKET(*call));
+		if (rc != EOK)
+			return rc;
+		
+		return ip_send_msg_local(0, IPC_GET_DEVICE(*call), packet, 0,
+		    IPC_GET_ERROR(*call));
 	}
 	
@@ -1996,50 +1984,8 @@
 }
 
-/** Default thread for new connections.
- *
- * @param[in] iid	The initial message identifier.
- * @param[in] icall	The initial message call structure.
- */
-static void il_client_connection(ipc_callid_t iid, ipc_call_t *icall)
-{
-	/*
-	 * Accept the connection
-	 *  - Answer the first IPC_M_CONNECT_ME_TO call.
-	 */
-	ipc_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 = il_module_message(callid, &call, &answer,
-		    &count);
-		
-		/*
-		 * End if told to either by the message or the processing
-		 * result.
-		 */
-		if ((IPC_GET_IMETHOD(call) == IPC_M_PHONE_HUNGUP) ||
-		    (res == EHANGUP)) {
-			return;
-		}
-		
-		/* Answer the message */
-		answer_call(callid, res, &answer, count);
-	}
-}
-
 int main(int argc, char *argv[])
 {
 	/* Start the module */
-	return il_module_start(il_client_connection);
+	return il_module_start(SERVICE_IP);
 }
 
Index: uspace/srv/net/il/ip/ip.h
===================================================================
--- uspace/srv/net/il/ip/ip.h	(revision 73ac2e9cfc27b4ece704510e8fe908610ae7a583)
+++ uspace/srv/net/il/ip/ip.h	(revision 797b704b28bced20e17a9eb959845c20363ce662)
@@ -138,6 +138,4 @@
 /** IP global data. */
 struct ip_globals {
-	/** Default client connection function for support modules. */
-	async_client_conn_t client_connection;
 	/** Default gateway. */
 	ip_route_t gateway;
Index: uspace/srv/net/il/ip/ip_module.c
===================================================================
--- uspace/srv/net/il/ip/ip_module.c	(revision 73ac2e9cfc27b4ece704510e8fe908610ae7a583)
+++ 	(revision )
@@ -1,94 +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 ip
- * @{
- */
-
-/** @file
- * IP standalone module implementation.
- * Contains skeleton module functions mapping.
- * The functions are used by the module skeleton as module specific entry
- * points.
- *
- * @see module.c
- */
-
-#include <async.h>
-#include <stdio.h>
-#include <ipc/ipc.h>
-#include <ipc/services.h>
-#include <errno.h>
-
-#include <net/modules.h>
-#include <net_interface.h>
-#include <net/packet.h>
-#include <il_local.h>
-
-#include "ip.h"
-#include "ip_module.h"
-
-/** IP module global data. */
-extern ip_globals_t ip_globals;
-
-int
-il_module_message(ipc_callid_t callid, ipc_call_t *call,
-    ipc_call_t *answer, size_t *count)
-{
-	return ip_message_standalone(callid, call, answer, count);
-}
-
-int il_module_start(async_client_conn_t client_connection)
-{
-	sysarg_t phonehash;
-	int rc;
-	
-	async_set_client_connection(client_connection);
-	ip_globals.net_phone = net_connect_module();
-
-	rc = pm_init();
-	if (rc != EOK)
-		return rc;
-	
-	rc = ip_initialize(client_connection);
-	if (rc != EOK)
-		goto out;
-	
-	rc = ipc_connect_to_me(PHONE_NS, SERVICE_IP, 0, 0, &phonehash);
-	if (rc != EOK)
-		goto out;
-	
-	async_manager();
-
-out:
-	pm_destroy();
-	return rc;
-}
-
-/** @}
- */
Index: uspace/srv/net/il/ip/ip_module.h
===================================================================
--- uspace/srv/net/il/ip/ip_module.h	(revision 73ac2e9cfc27b4ece704510e8fe908610ae7a583)
+++ 	(revision )
@@ -1,50 +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 ip
- * @{
- */
-
-/** @file
- * IP module functions.
- * The functions are used as IP module entry points.
- */
-
-#ifndef NET_IP_MODULE_H_
-#define NET_IP_MODULE_H_
-
-#include <ipc/ipc.h>
-
-extern int ip_initialize(async_client_conn_t);
-extern int ip_message_standalone(ipc_callid_t, ipc_call_t *, ipc_call_t *,
-    size_t *);
-
-#endif
-
-/** @}
- */
Index: uspace/srv/net/nil/eth/eth.c
===================================================================
--- uspace/srv/net/nil/eth/eth.c	(revision 73ac2e9cfc27b4ece704510e8fe908610ae7a583)
+++ uspace/srv/net/nil/eth/eth.c	(revision 797b704b28bced20e17a9eb959845c20363ce662)
@@ -57,5 +57,5 @@
 #include <netif_remote.h>
 #include <net_interface.h>
-#include <il_interface.h>
+#include <il_remote.h>
 #include <adt/measured_strings.h>
 #include <packet_client.h>
@@ -247,8 +247,8 @@
 			rc = packet_translate_remote(eth_globals.net_phone,
 			    &packet, IPC_GET_PACKET(*icall));
-			if (rc == EOK) {
+			if (rc == EOK)
 				rc = nil_received_msg_local(0,
 				    IPC_GET_DEVICE(*icall), packet, 0);
-			}
+			
 			ipc_answer_0(iid, (sysarg_t) rc);
 			break;
Index: uspace/srv/net/nil/nildummy/nildummy.c
===================================================================
--- uspace/srv/net/nil/nildummy/nildummy.c	(revision 73ac2e9cfc27b4ece704510e8fe908610ae7a583)
+++ uspace/srv/net/nil/nildummy/nildummy.c	(revision 797b704b28bced20e17a9eb959845c20363ce662)
@@ -48,5 +48,5 @@
 #include <net/modules.h>
 #include <net/device.h>
-#include <il_interface.h>
+#include <il_remote.h>
 #include <adt/measured_strings.h>
 #include <net/packet.h>
@@ -118,8 +118,8 @@
 			rc = packet_translate_remote(nildummy_globals.net_phone,
 			    &packet, IPC_GET_PACKET(*icall));
-			if (rc == EOK) {
+			if (rc == EOK)
 				rc = nil_received_msg_local(0,
 				    IPC_GET_DEVICE(*icall), packet, 0);
-			}
+			
 			ipc_answer_0(iid, (sysarg_t) rc);
 			break;
Index: uspace/srv/net/tl/icmp/icmp.c
===================================================================
--- uspace/srv/net/tl/icmp/icmp.c	(revision 73ac2e9cfc27b4ece704510e8fe908610ae7a583)
+++ uspace/srv/net/tl/icmp/icmp.c	(revision 797b704b28bced20e17a9eb959845c20363ce662)
@@ -68,5 +68,5 @@
 #include <icmp_client.h>
 #include <icmp_interface.h>
-#include <il_interface.h>
+#include <il_remote.h>
 #include <ip_client.h>
 #include <ip_interface.h>
