Index: uspace/app/ping/ping.c
===================================================================
--- uspace/app/ping/ping.c	(revision e2b15486aeb1cc59be933d1e08b3299f89aebd7b)
+++ uspace/app/ping/ping.c	(revision 50c06df137e61ca4f6a5de9ada5a632686de0eed)
@@ -340,5 +340,5 @@
 	    config.dest_str, config.size, config.size);
 	
-	int icmp_phone = icmp_connect_module(SERVICE_ICMP, ICMP_CONNECT_TIMEOUT);
+	int icmp_phone = icmp_connect_module(ICMP_CONNECT_TIMEOUT);
 	if (icmp_phone < 0) {
 		fprintf(stderr, "%s: Unable to connect to ICMP service (%s)\n", NAME,
Index: uspace/lib/c/generic/net/icmp_common.c
===================================================================
--- uspace/lib/c/generic/net/icmp_common.c	(revision e2b15486aeb1cc59be933d1e08b3299f89aebd7b)
+++ uspace/lib/c/generic/net/icmp_common.c	(revision 50c06df137e61ca4f6a5de9ada5a632686de0eed)
@@ -27,5 +27,5 @@
  */
 
-/** @addtogroup libc 
+/** @addtogroup libc
  *  @{
  */
@@ -38,28 +38,21 @@
 #include <net/modules.h>
 #include <net/icmp_common.h>
-
 #include <ipc/services.h>
 #include <ipc/icmp.h>
-
 #include <sys/time.h>
 #include <async.h>
 
-/** Connects to the ICMP module.
+/** Connect to the ICMP module.
  *
- * @param service	The ICMP module service. Ignored parameter.
- * @param[in] timeout	The connection timeout in microseconds. No timeout if
- *			set to zero.
- * @return		The ICMP module phone on success.
- * @return		ETIMEOUT if the connection timeouted.
+ * @param[in] timeout Connection timeout in microseconds, zero
+ *                    for no timeout.
+ *
+ * @return ICMP module phone on success.
+ * @return ETIMEOUT if the connection timeouted.
+ *
  */
-int icmp_connect_module(services_t service, suseconds_t timeout)
+int icmp_connect_module(suseconds_t timeout)
 {
-	int phone;
-
-	phone = connect_to_service_timeout(SERVICE_ICMP, timeout);
-	if (phone >= 0)
-		async_req_0_0(phone, NET_ICMP_INIT);
-
-	return phone;
+	return connect_to_service_timeout(SERVICE_ICMP, timeout);
 }
 
Index: uspace/lib/c/include/adt/hash_table.h
===================================================================
--- uspace/lib/c/include/adt/hash_table.h	(revision e2b15486aeb1cc59be933d1e08b3299f89aebd7b)
+++ uspace/lib/c/include/adt/hash_table.h	(revision 50c06df137e61ca4f6a5de9ada5a632686de0eed)
@@ -41,41 +41,42 @@
 typedef unsigned long hash_count_t;
 typedef unsigned long hash_index_t;
-typedef struct hash_table hash_table_t;
-typedef struct hash_table_operations hash_table_operations_t;
+
+/** Set of operations for hash table. */
+typedef struct {
+	/** Hash function.
+	 *
+	 * @param key Array of keys needed to compute hash index.
+	 *            All keys must be passed.
+	 *
+	 * @return Index into hash table.
+	 *
+	 */
+	hash_index_t (*hash)(unsigned long key[]);
+	
+	/** Hash table item comparison function.
+	 *
+	 * @param key Array of keys that will be compared with item. It is
+	 *            not necessary to pass all keys.
+	 *
+	 * @return True if the keys match, false otherwise.
+	 *
+	 */
+	int (*compare)(unsigned long key[], hash_count_t keys, link_t *item);
+	
+	/** Hash table item removal callback.
+	 *
+	 * @param item Item that was removed from the hash table.
+	 *
+	 */
+	void (*remove_callback)(link_t *item);
+} hash_table_operations_t;
 
 /** Hash table structure. */
-struct hash_table {
+typedef struct {
 	link_t *entry;
 	hash_count_t entries;
 	hash_count_t max_keys;
 	hash_table_operations_t *op;
-};
-
-/** Set of operations for hash table. */
-struct hash_table_operations {
-	/** Hash function.
-	 *
-	 * @param key 	Array of keys needed to compute hash index. All keys
-	 *		must be passed.
-	 *
-	 * @return	Index into hash table.
-	 */
-	hash_index_t (* hash)(unsigned long key[]);
-	
-	/** Hash table item comparison function.
-	 *
-	 * @param key 	Array of keys that will be compared with item. It is
-	 *		not necessary to pass all keys.
-	 *
-	 * @return 	true if the keys match, false otherwise.
-	 */
-	int (*compare)(unsigned long key[], hash_count_t keys, link_t *item);
-
-	/** Hash table item removal callback.
-	 *
-	 * @param item 	Item that was removed from the hash table.
-	 */
-	void (*remove_callback)(link_t *item);
-};
+} hash_table_t;
 
 #define hash_table_get_instance(item, type, member) \
Index: uspace/lib/c/include/ipc/icmp.h
===================================================================
--- uspace/lib/c/include/ipc/icmp.h	(revision e2b15486aeb1cc59be933d1e08b3299f89aebd7b)
+++ uspace/lib/c/include/ipc/icmp.h	(revision 50c06df137e61ca4f6a5de9ada5a632686de0eed)
@@ -33,5 +33,5 @@
 /** @file
  * ICMP module messages.
- * @see icmp_interface.h
+ * @see icmp_remote.h
  */
 
@@ -48,9 +48,9 @@
 /** ICMP module messages. */
 typedef enum {
-	/** Sends echo request. @see icmp_echo() */
+	/** Send echo request. @see icmp_echo() */
 	NET_ICMP_ECHO = NET_ICMP_FIRST,
 	
 	/**
-	 * Sends destination unreachable error message.
+	 * Send destination unreachable error message.
 	 * @see icmp_destination_unreachable_msg()
 	 */
@@ -58,5 +58,5 @@
 	
 	/**
-	 * Sends source quench error message.
+	 * Send source quench error message.
 	 * @see icmp_source_quench_msg()
 	 */
@@ -64,5 +64,5 @@
 	
 	/**
-	 * Sends time exceeded error message.
+	 * Send time exceeded error message.
 	 * @see icmp_time_exceeded_msg()
 	 */
@@ -70,12 +70,9 @@
 	
 	/**
-	 * Sends parameter problem error message.
+	 * Send parameter problem error message.
 	 * @see icmp_parameter_problem_msg()
 	 */
-	NET_ICMP_PARAMETERPROB,
-	
-	/** Initializes new connection. */
-	NET_ICMP_INIT
-} icmp_messages;
+	NET_ICMP_PARAMETERPROB
+} icmp_messages_t;
 
 /** @name ICMP specific message parameters definitions */
Index: uspace/lib/c/include/net/icmp_common.h
===================================================================
--- uspace/lib/c/include/net/icmp_common.h	(revision e2b15486aeb1cc59be933d1e08b3299f89aebd7b)
+++ uspace/lib/c/include/net/icmp_common.h	(revision 50c06df137e61ca4f6a5de9ada5a632686de0eed)
@@ -41,8 +41,8 @@
 #include <sys/time.h>
 
-/** Default timeout for incoming connections in microseconds. */
-#define ICMP_CONNECT_TIMEOUT	(1 * 1000 * 1000)
+/** Default timeout for incoming connections in microseconds (1 sec). */
+#define ICMP_CONNECT_TIMEOUT  1000000
 
-extern int icmp_connect_module(services_t, suseconds_t);
+extern int icmp_connect_module(suseconds_t);
 
 #endif
Index: uspace/lib/net/include/icmp_header.h
===================================================================
--- uspace/lib/net/include/icmp_header.h	(revision e2b15486aeb1cc59be933d1e08b3299f89aebd7b)
+++ uspace/lib/net/include/icmp_header.h	(revision 50c06df137e61ca4f6a5de9ada5a632686de0eed)
@@ -45,26 +45,16 @@
 
 /** ICMP header size in bytes. */
-#define ICMP_HEADER_SIZE	sizeof(icmp_header_t)
-
-/** Type definition of the echo specific data.
- * @see icmp_echo
- */
-typedef struct icmp_echo icmp_echo_t;
+#define ICMP_HEADER_SIZE  sizeof(icmp_header_t)
 
 /** Echo specific data. */
-struct icmp_echo {
+typedef struct icmp_echo {
 	/** Message idintifier. */
 	icmp_param_t identifier;
 	/** Message sequence number. */
 	icmp_param_t sequence_number;
-} __attribute__ ((packed));
-
-/** Type definition of the internet control message header.
- * @see icmp_header
- */
-typedef struct icmp_header icmp_header_t;
+} __attribute__((packed)) icmp_echo_t;
 
 /** Internet control message header. */
-struct icmp_header {
+typedef struct icmp_header {
 	/** The type of the message. */
 	uint8_t type;
@@ -83,9 +73,9 @@
 	 */
 	uint16_t checksum;
-
+	
 	/** Message specific data. */
 	union {
 		/** Echo specific data. */
-		icmp_echo_t  echo;
+		icmp_echo_t echo;
 		/** Proposed gateway value. */
 		in_addr_t gateway;
@@ -107,5 +97,5 @@
 		} param;
 	} un;
-} __attribute__ ((packed));
+} __attribute__((packed)) icmp_header_t;
 
 #endif
Index: uspace/lib/net/include/icmp_interface.h
===================================================================
--- uspace/lib/net/include/icmp_interface.h	(revision e2b15486aeb1cc59be933d1e08b3299f89aebd7b)
+++ 	(revision )
@@ -1,63 +1,0 @@
-/*
- * Copyright (c) 2009 Lukas Mejdrech
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * - Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- * - Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- * - The name of the author may not be used to endorse or promote products
- *   derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/** @addtogroup libnet 
- *  @{
- */
-
-#ifndef LIBNET_ICMP_INTERFACE_H_
-#define LIBNET_ICMP_INTERFACE_H_
-
-#include <net/socket_codes.h>
-#include <sys/types.h>
-
-#include <net/device.h>
-#include <adt/measured_strings.h>
-#include <net/packet.h>
-#include <net/inet.h>
-#include <net/ip_codes.h>
-#include <net/icmp_codes.h>
-#include <net/icmp_common.h>
-
-/** @name ICMP module interface
- * This interface is used by other modules.
- */
-/*@{*/
-
-extern int icmp_destination_unreachable_msg(int, icmp_code_t, icmp_param_t,
-    packet_t *);
-extern int icmp_source_quench_msg(int, packet_t *);
-extern int icmp_time_exceeded_msg(int, icmp_code_t, packet_t *);
-extern int icmp_parameter_problem_msg(int, icmp_code_t, icmp_param_t, packet_t *);
-
-/*@}*/
-
-#endif
-
-/** @}
- */
Index: uspace/lib/net/include/icmp_remote.h
===================================================================
--- uspace/lib/net/include/icmp_remote.h	(revision 50c06df137e61ca4f6a5de9ada5a632686de0eed)
+++ uspace/lib/net/include/icmp_remote.h	(revision 50c06df137e61ca4f6a5de9ada5a632686de0eed)
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2009 Lukas Mejdrech
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup libnet
+ *  @{
+ */
+
+#ifndef LIBNET_ICMP_REMOTE_H_
+#define LIBNET_ICMP_REMOTE_H_
+
+#include <net/socket_codes.h>
+#include <sys/types.h>
+
+#include <net/device.h>
+#include <adt/measured_strings.h>
+#include <net/packet.h>
+#include <net/inet.h>
+#include <net/ip_codes.h>
+#include <net/icmp_codes.h>
+#include <net/icmp_common.h>
+
+/** @name ICMP module interface
+ * This interface is used by other modules.
+ */
+/*@{*/
+
+extern int icmp_destination_unreachable_msg(int, icmp_code_t, icmp_param_t,
+    packet_t *);
+extern int icmp_source_quench_msg(int, packet_t *);
+extern int icmp_time_exceeded_msg(int, icmp_code_t, packet_t *);
+extern int icmp_parameter_problem_msg(int, icmp_code_t, icmp_param_t,
+    packet_t *);
+
+/*@}*/
+
+#endif
+
+/** @}
+ */
Index: uspace/lib/net/include/tl_skel.h
===================================================================
--- uspace/lib/net/include/tl_skel.h	(revision e2b15486aeb1cc59be933d1e08b3299f89aebd7b)
+++ uspace/lib/net/include/tl_skel.h	(revision 50c06df137e61ca4f6a5de9ada5a632686de0eed)
@@ -61,4 +61,11 @@
 extern int tl_initialize(int net_phone);
 
+/** Per-connection module initialization.
+ *
+ * This has to be implemented in user code.
+ *
+ */
+extern void tl_connection(void);
+
 /** Process the transport layer module message.
  *
@@ -74,5 +81,5 @@
  *
  */
-extern int tl_module_message(ipc_callid_t, ipc_call_t *,
+extern int tl_message(ipc_callid_t, ipc_call_t *,
     ipc_call_t *, size_t *);
 
Index: uspace/lib/net/tl/icmp_remote.c
===================================================================
--- uspace/lib/net/tl/icmp_remote.c	(revision e2b15486aeb1cc59be933d1e08b3299f89aebd7b)
+++ uspace/lib/net/tl/icmp_remote.c	(revision 50c06df137e61ca4f6a5de9ada5a632686de0eed)
@@ -33,8 +33,8 @@
 /** @file
  * ICMP interface implementation for remote modules.
- * @see icmp_interface.h
+ * @see icmp_remote.h
  */
 
-#include <icmp_interface.h>
+#include <icmp_remote.h>
 #include <net/modules.h>
 #include <packet_client.h>
Index: uspace/lib/net/tl/tl_common.c
===================================================================
--- uspace/lib/net/tl/tl_common.c	(revision e2b15486aeb1cc59be933d1e08b3299f89aebd7b)
+++ uspace/lib/net/tl/tl_common.c	(revision 50c06df137e61ca4f6a5de9ada5a632686de0eed)
@@ -27,5 +27,5 @@
  */
 
-/** @addtogroup libnet 
+/** @addtogroup libnet
  * @{
  */
@@ -39,5 +39,5 @@
 #include <packet_client.h>
 #include <packet_remote.h>
-#include <icmp_interface.h>
+#include <icmp_remote.h>
 #include <ip_remote.h>
 #include <ip_interface.h>
Index: uspace/lib/net/tl/tl_skel.c
===================================================================
--- uspace/lib/net/tl/tl_skel.c	(revision e2b15486aeb1cc59be933d1e08b3299f89aebd7b)
+++ uspace/lib/net/tl/tl_skel.c	(revision 50c06df137e61ca4f6a5de9ada5a632686de0eed)
@@ -56,4 +56,7 @@
 	ipc_answer_0(iid, EOK);
 	
+	/* Per-connection initialization */
+	tl_connection();
+	
 	while (true) {
 		ipc_call_t answer;
@@ -68,6 +71,5 @@
 		
 		/* Process the message */
-		int res = tl_module_message(callid, &call, &answer,
-		    &count);
+		int res = tl_message(callid, &call, &answer, &count);
 		
 		/*
Index: uspace/lib/usb/src/recognise.c
===================================================================
--- uspace/lib/usb/src/recognise.c	(revision e2b15486aeb1cc59be933d1e08b3299f89aebd7b)
+++ uspace/lib/usb/src/recognise.c	(revision 50c06df137e61ca4f6a5de9ada5a632686de0eed)
@@ -203,4 +203,8 @@
 		uint8_t cur_descr_len = current_descriptor[0];
 		uint8_t cur_descr_type = current_descriptor[1];
+
+		if (cur_descr_len == 0) {
+			return ENOENT;
+		}
 		
 		position += cur_descr_len;
Index: uspace/srv/net/il/ip/ip.c
===================================================================
--- uspace/srv/net/il/ip/ip.c	(revision e2b15486aeb1cc59be933d1e08b3299f89aebd7b)
+++ uspace/srv/net/il/ip/ip.c	(revision 50c06df137e61ca4f6a5de9ada5a632686de0eed)
@@ -67,5 +67,5 @@
 #include <net_checksum.h>
 #include <icmp_client.h>
-#include <icmp_interface.h>
+#include <icmp_remote.h>
 #include <ip_client.h>
 #include <ip_interface.h>
Index: uspace/srv/net/tl/icmp/icmp.c
===================================================================
--- uspace/srv/net/tl/icmp/icmp.c	(revision e2b15486aeb1cc59be933d1e08b3299f89aebd7b)
+++ uspace/srv/net/tl/icmp/icmp.c	(revision 50c06df137e61ca4f6a5de9ada5a632686de0eed)
@@ -33,5 +33,4 @@
 /** @file
  * ICMP module implementation.
- * @see icmp.h
  */
 
@@ -51,4 +50,5 @@
 #include <byteorder.h>
 #include <errno.h>
+#include <adt/hash_table.h>
 
 #include <net/socket_codes.h>
@@ -64,5 +64,5 @@
 #include <net_checksum.h>
 #include <icmp_client.h>
-#include <icmp_interface.h>
+#include <icmp_remote.h>
 #include <il_remote.h>
 #include <ip_client.h>
@@ -73,31 +73,26 @@
 #include <icmp_header.h>
 
-#include "icmp.h"
-
-/** ICMP module name. */
+/** ICMP module name */
 #define NAME  "icmp"
 
-/** Default ICMP error reporting. */
-#define NET_DEFAULT_ICMP_ERROR_REPORTING	true
-
-/** Default ICMP echo replying. */
-#define NET_DEFAULT_ICMP_ECHO_REPLYING		true
-
-/** Original datagram length in bytes transfered to the error notification
- * message.
- */
-#define ICMP_KEEP_LENGTH	8
-
-/** Free identifier numbers pool start. */
-#define ICMP_FREE_IDS_START	1
-
-/** Free identifier numbers pool end. */
-#define ICMP_FREE_IDS_END	UINT16_MAX
-
-/** Computes the ICMP datagram checksum.
- *
- * @param[in,out] header The ICMP datagram header.
- * @param[in] length	The total datagram length.
- * @return		The computed checksum.
+/** Number of replies hash table keys */
+#define REPLY_KEYS  2
+
+/** Number of replies hash table buckets */
+#define REPLY_BUCKETS  1024
+
+/**
+ * Original datagram length in bytes transfered to the error
+ * notification message.
+ */
+#define ICMP_KEEP_LENGTH  8
+
+/** Compute the ICMP datagram checksum.
+ *
+ * @param[in,out] header ICMP datagram header.
+ * @param[in]     length Total datagram length.
+ *
+ * @return Computed checksum.
+ *
  */
 #define ICMP_CHECKSUM(header, length) \
@@ -105,181 +100,222 @@
 
 /** An echo request datagrams pattern. */
-#define ICMP_ECHO_TEXT		"Hello from HelenOS."
-
-/** Computes an ICMP reply data key.
- *
- * @param[in] id	The message identifier.
- * @param[in] sequence	The message sequence number.
- * @return		The computed ICMP reply data key.
- */
-#define ICMP_GET_REPLY_KEY(id, sequence) \
-	(((id) << 16) | (sequence & 0xFFFF))
-
-
-/** ICMP global data. */
-icmp_globals_t	icmp_globals;
-
-INT_MAP_IMPLEMENT(icmp_replies, icmp_reply_t);
-INT_MAP_IMPLEMENT(icmp_echo_data, icmp_echo_t);
-
-/** Releases the packet and returns the result.
- *
- * @param[in] packet	The packet queue to be released.
- * @param[in] result	The result to be returned.
- * @return		The result parameter.
- */
-static int icmp_release_and_return(packet_t *packet, int result)
-{
-	pq_release_remote(icmp_globals.net_phone, packet_get_id(packet));
-	return result;
-}
-
-/** Sends the ICMP message.
- *
- * Sets the message type and code and computes the checksum.
+#define ICMP_ECHO_TEXT  "ICMP hello from HelenOS."
+
+/** ICMP reply data. */
+typedef struct {
+	/** Hash table link */
+	link_t link;
+	
+	/** Reply identification and sequence */
+	icmp_param_t id;
+	icmp_param_t sequence;
+	
+	/** Reply signaling */
+	fibril_condvar_t condvar;
+	
+	/** Reply result */
+	int result;
+} icmp_reply_t;
+
+/** Global data */
+static int phone_net = -1;
+static int phone_ip = -1;
+static bool error_reporting = true;
+static bool echo_replying = true;
+static packet_dimension_t icmp_dimension;
+
+/** ICMP client identification counter */
+static atomic_t icmp_client;
+
+/** ICMP identifier and sequence number (client-specific) */
+static fibril_local icmp_param_t icmp_id;
+static fibril_local icmp_param_t icmp_seq;
+
+/** Reply hash table */
+static fibril_mutex_t reply_lock;
+static hash_table_t replies;
+
+static hash_index_t replies_hash(unsigned long key[])
+{
+	/*
+	 * ICMP identifier and sequence numbers
+	 * are 16-bit values.
+	 */
+	hash_index_t index = ((key[0] & 0xffff) << 16) | (key[1] & 0xffff);
+	return (index % REPLY_BUCKETS);
+}
+
+static int replies_compare(unsigned long key[], hash_count_t keys, link_t *item)
+{
+	icmp_reply_t *reply =
+	    hash_table_get_instance(item, icmp_reply_t, link);
+	
+	if (keys == 1)
+		return (reply->id == key[0]);
+	else
+		return ((reply->id == key[0]) && (reply->sequence == key[1]));
+}
+
+static void replies_remove_callback(link_t *item)
+{
+}
+
+static hash_table_operations_t reply_ops = {
+	.hash = replies_hash,
+	.compare = replies_compare,
+	.remove_callback = replies_remove_callback
+};
+
+/** Release the packet and return the result.
+ *
+ * @param[in] packet Packet queue to be released.
+ *
+ */
+static void icmp_release(packet_t *packet)
+{
+	pq_release_remote(phone_net, packet_get_id(packet));
+}
+
+/** Send the ICMP message.
+ *
+ * Set the message type and code and compute the checksum.
  * Error messages are sent only if allowed in the configuration.
- * Releases the packet on errors.
- *
- * @param[in] type	The message type.
- * @param[in] code	The message code.
- * @param[in] packet	The message packet to be sent.
- * @param[in] header	The ICMP header.
- * @param[in] error	The error service to be announced. Should be
- *			SERVICE_ICMP or zero.
- * @param[in] ttl	The time to live.
- * @param[in] tos	The type of service.
- * @param[in] dont_fragment The value indicating whether the datagram must not
- *			be fragmented. Is used as a MTU discovery.
- * @return		EOK on success.
- * @return		EPERM if the error message is not allowed.
- */
-static int icmp_send_packet(icmp_type_t type, icmp_code_t code, packet_t *packet,
-    icmp_header_t *header, services_t error, ip_ttl_t ttl, ip_tos_t tos,
-    int dont_fragment)
-{
-	int rc;
-
+ * Release the packet on errors.
+ *
+ * @param[in] type          Message type.
+ * @param[in] code          Message code.
+ * @param[in] packet        Message packet to be sent.
+ * @param[in] header        ICMP header.
+ * @param[in] error         Error service to be announced. Should be
+ *                          SERVICE_ICMP or zero.
+ * @param[in] ttl           Time to live.
+ * @param[in] tos           Type of service.
+ * @param[in] dont_fragment Disable fragmentation.
+ *
+ * @return EOK on success.
+ * @return EPERM if the error message is not allowed.
+ *
+ */
+static int icmp_send_packet(icmp_type_t type, icmp_code_t code,
+    packet_t *packet, icmp_header_t *header, services_t error, ip_ttl_t ttl,
+    ip_tos_t tos, bool dont_fragment)
+{
 	/* Do not send an error if disabled */
-	if (error && !icmp_globals.error_reporting)
-		return icmp_release_and_return(packet, EPERM);
-
+	if ((error) && (!error_reporting)) {
+		icmp_release(packet);
+		return EPERM;
+	}
+	
 	header->type = type;
 	header->code = code;
+	
+	/*
+	 * The checksum needs to be calculated
+	 * with a virtual checksum field set to
+	 * zero.
+	 */
 	header->checksum = 0;
 	header->checksum = ICMP_CHECKSUM(header,
 	    packet_get_data_length(packet));
 	
-	rc = ip_client_prepare_packet(packet, IPPROTO_ICMP, ttl, tos,
+	int rc = ip_client_prepare_packet(packet, IPPROTO_ICMP, ttl, tos,
 	    dont_fragment, 0);
-	if (rc != EOK)
-		return icmp_release_and_return(packet, rc);
-
-	return ip_send_msg(icmp_globals.ip_phone, -1, packet, SERVICE_ICMP,
-	    error);
-}
-
-/** Prepares the ICMP error packet.
- *
- * Truncates the original packet if longer than ICMP_KEEP_LENGTH bytes.
- * Prefixes and returns the ICMP header.
- *
- * @param[in,out] packet The original packet.
+	if (rc != EOK) {
+		icmp_release(packet);
+		return rc;
+	}
+	
+	return ip_send_msg(phone_ip, -1, packet, SERVICE_ICMP, error);
+}
+
+/** Prepare the ICMP error packet.
+ *
+ * Truncate the original packet if longer than ICMP_KEEP_LENGTH bytes.
+ * Prefix and return the ICMP header.
+ *
+ * @param[in,out] packet Original packet.
+ *
  * @return The prefixed ICMP header.
  * @return NULL on errors.
+ *
  */
 static icmp_header_t *icmp_prepare_packet(packet_t *packet)
 {
-	icmp_header_t *header;
-	size_t header_length;
-	size_t total_length;
-
-	total_length = packet_get_data_length(packet);
+	size_t total_length = packet_get_data_length(packet);
 	if (total_length <= 0)
 		return NULL;
-
-	header_length = ip_client_header_length(packet);
+	
+	size_t header_length = ip_client_header_length(packet);
 	if (header_length <= 0)
 		return NULL;
-
+	
 	/* Truncate if longer than 64 bits (without the IP header) */
 	if ((total_length > header_length + ICMP_KEEP_LENGTH) &&
 	    (packet_trim(packet, 0,
-	    total_length - header_length - ICMP_KEEP_LENGTH) != EOK)) {
+	    total_length - header_length - ICMP_KEEP_LENGTH) != EOK))
 		return NULL;
-	}
-
-	header = PACKET_PREFIX(packet, icmp_header_t);
+	
+	icmp_header_t *header = PACKET_PREFIX(packet, icmp_header_t);
 	if (!header)
 		return NULL;
-
+	
 	bzero(header, sizeof(*header));
 	return header;
 }
 
-/** Requests an echo message.
- *
- * Sends a packet with specified parameters to the target host and waits for
- * the reply upto the given timeout.
- * Blocks the caller until the reply or the timeout occurs.
- *
- * @param[in] id	The message identifier.
- * @param[in] sequence	The message sequence parameter.
- * @param[in] size	The message data length in bytes.
- * @param[in] timeout	The timeout in miliseconds.
- * @param[in] ttl	The time to live.
- * @param[in] tos	The type of service.
- * @param[in] dont_fragment The value indicating whether the datagram must not
- *			be fragmented. Is used as a MTU discovery.
- * @param[in] addr	The target host address.
- * @param[in] addrlen	The torget host address length.
- * @return		ICMP_ECHO on success.
- * @return		ETIMEOUT if the reply has not arrived before the
- *			timeout.
- * @return		ICMP type of the received error notification.
- * @return		EINVAL if the addrlen parameter is less or equal to
- *			zero.
- * @return		ENOMEM if there is not enough memory left.
- * @return		EPARTY if there was an internal error.
+/** Request an echo message.
+ *
+ * Send a packet with specified parameters to the target host
+ * and wait for the reply upto the given timeout.
+ * Block the caller until the reply or the timeout occurs.
+ *
+ * @param[in] id            Message identifier.
+ * @param[in] sequence      Message sequence parameter.
+ * @param[in] size          Message data length in bytes.
+ * @param[in] timeout       Timeout in miliseconds.
+ * @param[in] ttl           Time to live.
+ * @param[in] tos           Type of service.
+ * @param[in] dont_fragment Disable fragmentation.
+ * @param[in] addr          Target host address.
+ * @param[in] addrlen       Torget host address length.
+ *
+ * @return ICMP_ECHO on success.
+ * @return ETIMEOUT if the reply has not arrived before the
+ *         timeout.
+ * @return ICMP type of the received error notification.
+ * @return EINVAL if the addrlen parameter is less or equal to
+ *         zero.
+ * @return ENOMEM if there is not enough memory left.
+ *
  */
 static int icmp_echo(icmp_param_t id, icmp_param_t sequence, size_t size,
-    mseconds_t timeout, ip_ttl_t ttl, ip_tos_t tos, int dont_fragment,
-    const struct sockaddr * addr, socklen_t addrlen)
-{
-	icmp_header_t *header;
-	packet_t *packet;
-	size_t length;
-	uint8_t *data;
-	icmp_reply_t *reply;
-	int reply_key;
-	int index;
-	int rc;
-
+    mseconds_t timeout, ip_ttl_t ttl, ip_tos_t tos, bool dont_fragment,
+    const struct sockaddr *addr, socklen_t addrlen)
+{
 	if (addrlen <= 0)
 		return EINVAL;
-
-	length = (size_t) addrlen;
-	/* TODO do not ask all the time */
-	rc = ip_packet_size_req(icmp_globals.ip_phone, -1,
-	    &icmp_globals.packet_dimension);
-	if (rc != EOK)
-		return rc;
-
-	packet = packet_get_4_remote(icmp_globals.net_phone, size,
-	    icmp_globals.packet_dimension.addr_len,
-	    ICMP_HEADER_SIZE + icmp_globals.packet_dimension.prefix,
-	    icmp_globals.packet_dimension.suffix);
+	
+	size_t length = (size_t) addrlen;
+	
+	packet_t *packet = packet_get_4_remote(phone_net, size,
+	    icmp_dimension.addr_len, ICMP_HEADER_SIZE + icmp_dimension.prefix,
+	    icmp_dimension.suffix);
 	if (!packet)
 		return ENOMEM;
-
+	
 	/* Prepare the requesting packet, set the destination address. */
-	rc = packet_set_addr(packet, NULL, (const uint8_t *) addr, length);
-	if (rc != EOK)
-		return icmp_release_and_return(packet, rc);
-
+	int rc = packet_set_addr(packet, NULL, (const uint8_t *) addr, length);
+	if (rc != EOK) {
+		icmp_release(packet);
+		return rc;
+	}
+	
 	/* Allocate space in the packet */
-	data = (uint8_t *) packet_suffix(packet, size);
-	if (!data)
-		return icmp_release_and_return(packet, ENOMEM);
-
+	uint8_t *data = (uint8_t *) packet_suffix(packet, size);
+	if (!data) {
+		icmp_release(packet);
+		return ENOMEM;
+	}
+	
 	/* Fill the data */
 	length = 0;
@@ -289,166 +325,164 @@
 	}
 	memcpy(data + length, ICMP_ECHO_TEXT, size - length);
-
+	
 	/* Prefix the header */
-	header = PACKET_PREFIX(packet, icmp_header_t);
-	if (!header)
-		return icmp_release_and_return(packet, ENOMEM);
-
-	bzero(header, sizeof(*header));
+	icmp_header_t *header = PACKET_PREFIX(packet, icmp_header_t);
+	if (!header) {
+		icmp_release(packet);
+		return ENOMEM;
+	}
+	
+	bzero(header, sizeof(icmp_header_t));
 	header->un.echo.identifier = id;
 	header->un.echo.sequence_number = sequence;
-
+	
 	/* Prepare the reply structure */
-	reply = malloc(sizeof(*reply));
-	if (!reply)
-		return icmp_release_and_return(packet, ENOMEM);
-
-	fibril_mutex_initialize(&reply->mutex);
-	fibril_mutex_lock(&reply->mutex);
+	icmp_reply_t *reply = malloc(sizeof(icmp_reply_t));
+	if (!reply) {
+		icmp_release(packet);
+		return ENOMEM;
+	}
+	
+	reply->id = id;
+	reply->sequence = sequence;
 	fibril_condvar_initialize(&reply->condvar);
-	reply_key = ICMP_GET_REPLY_KEY(header->un.echo.identifier,
-	    header->un.echo.sequence_number);
-	index = icmp_replies_add(&icmp_globals.replies, reply_key, reply);
-	if (index < 0) {
-		free(reply);
-		return icmp_release_and_return(packet, index);
-	}
-
-	/* Unlock the globals so that we can wait for the reply */
-	fibril_rwlock_write_unlock(&icmp_globals.lock);
-
+	
+	/* Add the reply to the replies hash table */
+	fibril_mutex_lock(&reply_lock);
+	
+	unsigned long key[REPLY_KEYS] = {id, sequence};
+	hash_table_insert(&replies, key, &reply->link);
+	
 	/* Send the request */
 	icmp_send_packet(ICMP_ECHO, 0, packet, header, 0, ttl, tos,
 	    dont_fragment);
-
+	
 	/* Wait for the reply. Timeout in microseconds. */
-	rc = fibril_condvar_wait_timeout(&reply->condvar, &reply->mutex,
+	rc = fibril_condvar_wait_timeout(&reply->condvar, &reply_lock,
 	    timeout * 1000);
 	if (rc == EOK)
 		rc = reply->result;
-
-	/* Drop the reply mutex before locking the globals again */
-	fibril_mutex_unlock(&reply->mutex);
-	fibril_rwlock_write_lock(&icmp_globals.lock);
-
-	/* Destroy the reply structure */
-	icmp_replies_exclude_index(&icmp_globals.replies, index);
-
+	
+	/* Remove the reply from the replies hash table */
+	hash_table_remove(&replies, key, REPLY_KEYS);
+	
+	fibril_mutex_unlock(&reply_lock);
+	
+	free(reply);
+	
 	return rc;
 }
 
-static int icmp_destination_unreachable_msg_local(int icmp_phone,
-    icmp_code_t code, icmp_param_t mtu, packet_t *packet)
-{
-	icmp_header_t *header;
-
-	header = icmp_prepare_packet(packet);
-	if (!header)
-		return icmp_release_and_return(packet, ENOMEM);
-
+static int icmp_destination_unreachable(icmp_code_t code, icmp_param_t mtu,
+    packet_t *packet)
+{
+	icmp_header_t *header = icmp_prepare_packet(packet);
+	if (!header) {
+		icmp_release(packet);
+		return ENOMEM;
+	}
+	
 	if (mtu)
 		header->un.frag.mtu = mtu;
-
+	
 	return icmp_send_packet(ICMP_DEST_UNREACH, code, packet, header,
-	    SERVICE_ICMP, 0, 0, 0);
-}
-
-static int icmp_source_quench_msg_local(int icmp_phone, packet_t *packet)
-{
-	icmp_header_t *header;
-
-	header = icmp_prepare_packet(packet);
-	if (!header)
-		return icmp_release_and_return(packet, ENOMEM);
-
+	    SERVICE_ICMP, 0, 0, false);
+}
+
+static int icmp_source_quench(packet_t *packet)
+{
+	icmp_header_t *header = icmp_prepare_packet(packet);
+	if (!header) {
+		icmp_release(packet);
+		return ENOMEM;
+	}
+	
 	return icmp_send_packet(ICMP_SOURCE_QUENCH, 0, packet, header,
-	    SERVICE_ICMP, 0, 0, 0);
-}
-
-static int icmp_time_exceeded_msg_local(int icmp_phone, icmp_code_t code,
+	    SERVICE_ICMP, 0, 0, false);
+}
+
+static int icmp_time_exceeded(icmp_code_t code, packet_t *packet)
+{
+	icmp_header_t *header = icmp_prepare_packet(packet);
+	if (!header) {
+		icmp_release(packet);
+		return ENOMEM;
+	}
+	
+	return icmp_send_packet(ICMP_TIME_EXCEEDED, code, packet, header,
+	    SERVICE_ICMP, 0, 0, false);
+}
+
+static int icmp_parameter_problem(icmp_code_t code, icmp_param_t pointer,
     packet_t *packet)
 {
-	icmp_header_t *header;
-
-	header = icmp_prepare_packet(packet);
-	if (!header)
-		return icmp_release_and_return(packet, ENOMEM);
-
-	return icmp_send_packet(ICMP_TIME_EXCEEDED, code, packet, header,
-	    SERVICE_ICMP, 0, 0, 0);
-}
-
-static int icmp_parameter_problem_msg_local(int icmp_phone, icmp_code_t code,
-    icmp_param_t pointer, packet_t *packet)
-{
-	icmp_header_t *header;
-
-	header = icmp_prepare_packet(packet);
-	if (!header)
-		return icmp_release_and_return(packet, ENOMEM);
-
+	icmp_header_t *header = icmp_prepare_packet(packet);
+	if (!header) {
+		icmp_release(packet);
+		return ENOMEM;
+	}
+	
 	header->un.param.pointer = pointer;
 	return icmp_send_packet(ICMP_PARAMETERPROB, code, packet, header,
-	    SERVICE_ICMP, 0, 0, 0);
-}
-
-/** Tries to set the pending reply result as the received message type.
+	    SERVICE_ICMP, 0, 0, false);
+}
+
+/** Try to set the pending reply result as the received message type.
  *
  * If the reply data is not present, the reply timed out and the other fibril
- * is already awake.
- * Releases the packet.
- *
- * @param[in] packet	The received reply message.
- * @param[in] header	The ICMP message header.
- * @param[in] type	The received reply message type.
- * @param[in] code	The received reply message code.
- */
-static void  icmp_process_echo_reply(packet_t *packet, icmp_header_t *header,
+ * is already awake. The packet is released.
+ *
+ * @param[in] packet The received reply message.
+ * @param[in] header The ICMP message header.
+ * @param[in] type   The received reply message type.
+ * @param[in] code   The received reply message code.
+ *
+ */
+static void icmp_process_echo_reply(packet_t *packet, icmp_header_t *header,
     icmp_type_t type, icmp_code_t code)
 {
-	int reply_key;
-	icmp_reply_t *reply;
-
-	/* Compute the reply key */
-	reply_key = ICMP_GET_REPLY_KEY(header->un.echo.identifier,
-	    header->un.echo.sequence_number);
-	pq_release_remote(icmp_globals.net_phone, packet_get_id(packet));
-
+	unsigned long key[REPLY_KEYS] =
+	    {header->un.echo.identifier, header->un.echo.sequence_number};
+	
+	/* The packet is no longer needed */
+	icmp_release(packet);
+	
 	/* Find the pending reply */
-	fibril_rwlock_write_lock(&icmp_globals.lock);
-	reply = icmp_replies_find(&icmp_globals.replies, reply_key);
-	if (reply) {
+	fibril_mutex_lock(&reply_lock);
+	
+	link_t *link = hash_table_find(&replies, key);
+	if (link != NULL) {
+		icmp_reply_t *reply =
+		   hash_table_get_instance(link, icmp_reply_t, link);
+		
 		reply->result = type;
 		fibril_condvar_signal(&reply->condvar);
 	}
-	fibril_rwlock_write_unlock(&icmp_globals.lock);
-}
-
-/** Processes the received ICMP packet.
- *
- * Notifies the destination socket application.
- *
- * @param[in,out] packet The received packet.
- * @param[in] error	The packet error reporting service. Prefixes the
- *			received packet.
- * @return		EOK on success.
- * @return		EINVAL if the packet is not valid.
- * @return		EINVAL if the stored packet address is not the an_addr_t.
- * @return		EINVAL if the packet does not contain any data.
- * @return		NO_DATA if the packet content is shorter than the user
- *			datagram header.
- * @return		ENOMEM if there is not enough memory left.
- * @return		EADDRNOTAVAIL if the destination socket does not exist.
- * @return		Other error codes as defined for the
- *			ip_client_process_packet() function.
+	
+	fibril_mutex_unlock(&reply_lock);
+}
+
+/** Process the received ICMP packet.
+ *
+ * Notify the destination socket application.
+ *
+ * @param[in,out] packet Received packet.
+ * @param[in]     error  Packet error reporting service to prefix
+ *                       the received packet.
+ *
+ * @return EOK on success.
+ * @return EINVAL if the packet is not valid.
+ * @return EINVAL if the stored packet address is not the an_addr_t.
+ * @return EINVAL if the packet does not contain any data.
+ * @return NO_DATA if the packet content is shorter than the user
+ *         datagram header.
+ * @return ENOMEM if there is not enough memory left.
+ * @return EADDRNOTAVAIL if the destination socket does not exist.
+ * @return Other error codes as defined for the
+ *         ip_client_process_packet() function.
+ *
  */
 static int icmp_process_packet(packet_t *packet, services_t error)
 {
-	size_t length;
-	uint8_t *src;
-	int addrlen;
-	int result;
-	void *data;
-	icmp_header_t *header;
 	icmp_type_t type;
 	icmp_code_t code;
@@ -460,38 +494,38 @@
 	case SERVICE_ICMP:
 		/* Process error */
-		result = icmp_client_process_packet(packet, &type, &code, NULL,
-		    NULL);
-		if (result < 0)
-			return result;
-		length = (size_t) result;
+		rc = icmp_client_process_packet(packet, &type, &code, NULL, NULL);
+		if (rc < 0)
+			return rc;
+		
 		/* Remove the error header */
-		rc = packet_trim(packet, length, 0);
+		rc = packet_trim(packet, (size_t) rc, 0);
 		if (rc != EOK)
 			return rc;
+		
 		break;
 	default:
 		return ENOTSUP;
 	}
-
+	
 	/* Get rid of the IP header */
-	length = ip_client_header_length(packet);
+	size_t length = ip_client_header_length(packet);
 	rc = packet_trim(packet, length, 0);
 	if (rc != EOK)
 		return rc;
-
+	
 	length = packet_get_data_length(packet);
 	if (length <= 0)
 		return EINVAL;
-
+	
 	if (length < ICMP_HEADER_SIZE)
 		return EINVAL;
-
-	data = packet_get_data(packet);
+	
+	void *data = packet_get_data(packet);
 	if (!data)
 		return EINVAL;
-
+	
 	/* Get ICMP header */
-	header = (icmp_header_t *) data;
-
+	icmp_header_t *header = (icmp_header_t *) data;
+	
 	if (header->checksum) {
 		while (ICMP_CHECKSUM(header, length) != IP_CHECKSUM_ZERO) {
@@ -507,8 +541,9 @@
 				}
 			}
+			
 			return EINVAL;
 		}
 	}
-
+	
 	switch (header->type) {
 	case ICMP_ECHOREPLY:
@@ -517,7 +552,7 @@
 		else
 			icmp_process_echo_reply(packet, header, ICMP_ECHO, 0);
-
+		
 		return EOK;
-
+	
 	case ICMP_ECHO:
 		if (error) {
@@ -527,9 +562,10 @@
 		
 		/* Do not send a reply if disabled */
-		if (icmp_globals.echo_replying) {
-			addrlen = packet_get_addr(packet, &src, NULL);
-
+		if (echo_replying) {
+			uint8_t *src;
+			int addrlen = packet_get_addr(packet, &src, NULL);
+			
 			/*
-			 * Set both addresses to the source one (avoids the
+			 * Set both addresses to the source one (avoid the
 			 * source address deletion before setting the
 			 * destination one).
@@ -542,10 +578,10 @@
 				return EOK;
 			}
-
+			
 			return EINVAL;
 		}
-
+		
 		return EPERM;
-
+	
 	case ICMP_DEST_UNREACH:
 	case ICMP_SOURCE_QUENCH:
@@ -560,8 +596,8 @@
 	case ICMP_SKIP:
 	case ICMP_PHOTURIS:
-		ip_received_error_msg(icmp_globals.ip_phone, -1, packet,
+		ip_received_error_msg(phone_ip, -1, packet,
 		    SERVICE_IP, SERVICE_ICMP);
 		return EOK;
-
+	
 	default:
 		return ENOTSUP;
@@ -569,30 +605,4 @@
 }
 
-/** Processes the received ICMP packet.
- *
- * Is used as an entry point from the underlying IP module.
- * Releases the packet on error.
- *
- * @param device_id	The device identifier. Ignored parameter.
- * @param[in,out] packet The received packet.
- * @param receiver	The target service. Ignored parameter.
- * @param[in] error	The packet error reporting service. Prefixes the
- *			received packet.
- * @return		EOK on success.
- * @return		Other error codes as defined for the
- *			icmp_process_packet() function.
- */
-static int icmp_received_msg_local(device_id_t device_id, packet_t *packet,
-    services_t receiver, services_t error)
-{
-	int rc;
-
-	rc = icmp_process_packet(packet, error);
-	if (rc != EOK)
-		return icmp_release_and_return(packet, rc);
-
-	return EOK;
-}
-
 /** Process IPC messages from the IP module
  *
@@ -603,18 +613,24 @@
 static void icmp_receiver(ipc_callid_t iid, ipc_call_t *icall)
 {
+	bool loop = true;
 	packet_t *packet;
 	int rc;
 	
-	while (true) {
+	while (loop) {
 		switch (IPC_GET_IMETHOD(*icall)) {
 		case NET_TL_RECEIVED:
-			rc = packet_translate_remote(icmp_globals.net_phone, &packet,
+			rc = packet_translate_remote(phone_net, &packet,
 			    IPC_GET_PACKET(*icall));
-			if (rc == EOK)
-				rc = icmp_received_msg_local(IPC_GET_DEVICE(*icall), packet,
-				    SERVICE_ICMP, IPC_GET_ERROR(*icall));
+			if (rc == EOK) {
+				rc = icmp_process_packet(packet, IPC_GET_ERROR(*icall));
+				if (rc != EOK)
+					icmp_release(packet);
+			}
 			
 			ipc_answer_0(iid, (sysarg_t) rc);
 			break;
+		case IPC_M_PHONE_HUNGUP:
+			loop = false;
+			continue;
 		default:
 			ipc_answer_0(iid, (sysarg_t) ENOTSUP);
@@ -649,288 +665,135 @@
 	uint8_t *data;
 	
-	fibril_rwlock_initialize(&icmp_globals.lock);
-	fibril_rwlock_write_lock(&icmp_globals.lock);
-	icmp_replies_initialize(&icmp_globals.replies);
-	icmp_echo_data_initialize(&icmp_globals.echo_data);
-	
-	icmp_globals.net_phone = net_phone;
-	
-	icmp_globals.ip_phone = ip_bind_service(SERVICE_IP, IPPROTO_ICMP,
-	    SERVICE_ICMP, icmp_receiver);
-	if (icmp_globals.ip_phone < 0) {
-		fibril_rwlock_write_unlock(&icmp_globals.lock);
-		return icmp_globals.ip_phone;
-	}
-	
-	int rc = ip_packet_size_req(icmp_globals.ip_phone, -1,
-	    &icmp_globals.packet_dimension);
-	if (rc != EOK) {
-		fibril_rwlock_write_unlock(&icmp_globals.lock);
+	if (!hash_table_create(&replies, REPLY_BUCKETS, REPLY_KEYS, &reply_ops))
+		return ENOMEM;
+	
+	fibril_mutex_initialize(&reply_lock);
+	atomic_set(&icmp_client, 0);
+	
+	phone_net = net_phone;
+	phone_ip = ip_bind_service(SERVICE_IP, IPPROTO_ICMP, SERVICE_ICMP,
+	    icmp_receiver);
+	if (phone_ip < 0)
+		return phone_ip;
+	
+	int rc = ip_packet_size_req(phone_ip, -1, &icmp_dimension);
+	if (rc != EOK)
 		return rc;
-	}
-	
-	icmp_globals.packet_dimension.prefix += ICMP_HEADER_SIZE;
-	icmp_globals.packet_dimension.content -= ICMP_HEADER_SIZE;
-	
-	icmp_globals.error_reporting = NET_DEFAULT_ICMP_ERROR_REPORTING;
-	icmp_globals.echo_replying = NET_DEFAULT_ICMP_ECHO_REPLYING;
+	
+	icmp_dimension.prefix += ICMP_HEADER_SIZE;
+	icmp_dimension.content -= ICMP_HEADER_SIZE;
 	
 	/* Get configuration */
 	configuration = &names[0];
-	rc = net_get_conf_req(icmp_globals.net_phone, &configuration, count,
-	    &data);
-	if (rc != EOK) {
-		fibril_rwlock_write_unlock(&icmp_globals.lock);
+	rc = net_get_conf_req(phone_net, &configuration, count, &data);
+	if (rc != EOK)
 		return rc;
-	}
 	
 	if (configuration) {
-		if (configuration[0].value) {
-			icmp_globals.error_reporting =
-			    (configuration[0].value[0] == 'y');
-		}
-		if (configuration[1].value) {
-			icmp_globals.echo_replying =
-			    (configuration[1].value[0] == 'y');
-		}
+		if (configuration[0].value)
+			error_reporting = (configuration[0].value[0] == 'y');
+		
+		if (configuration[1].value)
+			echo_replying = (configuration[1].value[0] == 'y');
+		
 		net_free_settings(configuration, data);
 	}
 	
-	fibril_rwlock_write_unlock(&icmp_globals.lock);
 	return EOK;
 }
 
-/** Processes the generic client messages.
- *
- * @param[in] call	The message parameters.
- * @return		EOK on success.
- * @return		ENOTSUP if the message is not known.
- * @return		Other error codes as defined for the packet_translate()
- *			function.
- * @return		Other error codes as defined for the
- *			icmp_destination_unreachable_msg_local() function.
- * @return		Other error codes as defined for the
- *			icmp_source_quench_msg_local() function.
- * @return		Other error codes as defined for the
- *			icmp_time_exceeded_msg_local() function.
- * @return		Other error codes as defined for the
- *			icmp_parameter_problem_msg_local() function.
- *
- * @see icmp_interface.h
- */
-static int icmp_process_message(ipc_call_t *call)
-{
+/** Per-connection initialization
+ *
+ * Initialize client-specific global variables.
+ *
+ */
+void tl_connection(void)
+{
+	icmp_id = (icmp_param_t) atomic_postinc(&icmp_client);
+	icmp_seq = 1;
+}
+
+/** Process the ICMP message.
+ *
+ * @param[in]  callid Message identifier.
+ * @param[in]  call   Message parameters.
+ * @param[out] answer Answer.
+ * @param[out] count  Number of arguments of the answer.
+ *
+ * @return EOK on success.
+ * @return ENOTSUP if the message is not known.
+ * @return Other error codes as defined for the packet_translate()
+ *         function.
+ * @return Other error codes as defined for the
+ *         icmp_destination_unreachable() function.
+ * @return Other error codes as defined for the
+ *         icmp_source_quench() function.
+ * @return Other error codes as defined for the
+ *         icmp_time_exceeded() function.
+ * @return Other error codes as defined for the
+ *         icmp_parameter_problem() function.
+ *
+ * @see icmp_remote.h
+ * @see IS_NET_ICMP_MESSAGE()
+ *
+ */
+int tl_message(ipc_callid_t callid, ipc_call_t *call,
+    ipc_call_t *answer, size_t *count)
+{
+	struct sockaddr *addr;
+	size_t size;
 	packet_t *packet;
 	int rc;
-
+	
+	*count = 0;
+	
 	switch (IPC_GET_IMETHOD(*call)) {
+	case NET_ICMP_ECHO:
+		rc = async_data_write_accept((void **) &addr, false, 0, 0, 0, &size);
+		if (rc != EOK)
+			return rc;
+		
+		rc = icmp_echo(icmp_id, icmp_seq, ICMP_GET_SIZE(*call),	
+		    ICMP_GET_TIMEOUT(*call), ICMP_GET_TTL(*call),
+		    ICMP_GET_TOS(*call), ICMP_GET_DONT_FRAGMENT(*call),
+		    addr, (socklen_t) size);
+		
+		free(addr);
+		icmp_seq++;
+		return rc;
+	
 	case NET_ICMP_DEST_UNREACH:
-		rc = packet_translate_remote(icmp_globals.net_phone, &packet,
+		rc = packet_translate_remote(phone_net, &packet,
 		    IPC_GET_PACKET(*call));
 		if (rc != EOK)
 			return rc;
-		return icmp_destination_unreachable_msg_local(0,
-		    ICMP_GET_CODE(*call), ICMP_GET_MTU(*call), packet);
+		
+		return icmp_destination_unreachable(ICMP_GET_CODE(*call),
+		    ICMP_GET_MTU(*call), packet);
+	
 	case NET_ICMP_SOURCE_QUENCH:
-		rc = packet_translate_remote(icmp_globals.net_phone, &packet,
+		rc = packet_translate_remote(phone_net, &packet,
 		    IPC_GET_PACKET(*call));
 		if (rc != EOK)
 			return rc;
-		return icmp_source_quench_msg_local(0, packet);
+		
+		return icmp_source_quench(packet);
+	
 	case NET_ICMP_TIME_EXCEEDED:
-		rc = packet_translate_remote(icmp_globals.net_phone, &packet,
+		rc = packet_translate_remote(phone_net, &packet,
 		    IPC_GET_PACKET(*call));
 		if (rc != EOK)
 			return rc;
-		return icmp_time_exceeded_msg_local(0, ICMP_GET_CODE(*call),
-		    packet);
+		
+		return icmp_time_exceeded(ICMP_GET_CODE(*call), packet);
+	
 	case NET_ICMP_PARAMETERPROB:
-		rc = packet_translate_remote(icmp_globals.net_phone, &packet,
+		rc = packet_translate_remote(phone_net, &packet,
 		    IPC_GET_PACKET(*call));
 		if (rc != EOK)
 			return rc;
-		return icmp_parameter_problem_msg_local(0, ICMP_GET_CODE(*call),
+		
+		return icmp_parameter_problem(ICMP_GET_CODE(*call),
 		    ICMP_GET_POINTER(*call), packet);
-	default:
-		return ENOTSUP;
-	}
-}
-
-/** Assigns a new identifier for the connection.
- *
- * Fills the echo data parameter with the assigned values.
- *
- * @param[in,out] echo_data The echo data to be bound.
- * @return		Index of the inserted echo data.
- * @return		EBADMEM if the echo_data parameter is NULL.
- * @return		ENOTCONN if no free identifier have been found.
- */
-static int icmp_bind_free_id(icmp_echo_t *echo_data)
-{
-	icmp_param_t index;
-
-	if (!echo_data)
-		return EBADMEM;
-
-	/* From the last used one */
-	index = icmp_globals.last_used_id;
-	do {
-		index++;
-		/* til the range end */
-		if (index >= ICMP_FREE_IDS_END) {
-			/* start from the range beginning */
-			index = ICMP_FREE_IDS_START - 1;
-			do {
-				index++;
-				/* til the last used one */
-				if (index >= icmp_globals.last_used_id) {
-					/* none found */
-					return ENOTCONN;
-				}
-			} while(icmp_echo_data_find(&icmp_globals.echo_data,
-			    index) != NULL);
-
-			/* Found, break immediately */
-			break;
-		}
-	} while (icmp_echo_data_find(&icmp_globals.echo_data, index) != NULL);
-
-	echo_data->identifier = index;
-	echo_data->sequence_number = 0;
-
-	return icmp_echo_data_add(&icmp_globals.echo_data, index, echo_data);
-}
-
-/** Processes the client messages.
- *
- * Remembers the assigned identifier and sequence numbers.
- * Runs until the client module disconnects.
- *
- * @param[in] callid	The message identifier.
- * @param[in] call	The message parameters.
- * @return EOK.
- *
- * @see icmp_interface.h
- * @see icmp_api.h
- */
-static int icmp_process_client_messages(ipc_callid_t callid, ipc_call_t call)
-{
-	bool keep_on_going = true;
-	ipc_call_t answer;
-	size_t answer_count;
-	size_t length;
-	struct sockaddr *addr;
-	ipc_callid_t data_callid;
-	icmp_echo_t *echo_data;
-	int rc = EOK;
-
-	/*
-	 * Accept the connection
-	 *  - Answer the first NET_ICMP_INIT call.
-	 */
-	answer_count = 0;
-
-	echo_data = (icmp_echo_t *) malloc(sizeof(*echo_data));
-	if (!echo_data)
-		return ENOMEM;
-
-	/* Assign a new identifier */
-	fibril_rwlock_write_lock(&icmp_globals.lock);
-	rc = icmp_bind_free_id(echo_data);
-	fibril_rwlock_write_unlock(&icmp_globals.lock);
-	if (rc < 0) {
-		free(echo_data);
-		return rc;
-	}
-
-	while (keep_on_going) {
-		/* Answer the call */
-		answer_call(callid, rc, &answer, answer_count);
-
-		/* Refresh data */
-		refresh_answer(&answer, &answer_count);
-
-		/* Get the next call */
-		callid = async_get_call(&call);
-
-		/* Process the call */
-		switch (IPC_GET_IMETHOD(call)) {
-		case IPC_M_PHONE_HUNGUP:
-			keep_on_going = false;
-			rc = EHANGUP;
-			break;
-		
-		case NET_ICMP_ECHO:
-			if (!async_data_write_receive(&data_callid, &length)) {
-				rc = EINVAL;
-				break;
-			}
-			
-			addr = malloc(length);
-			if (!addr) {
-				rc = ENOMEM;
-				break;
-			}
-			
-			rc = async_data_write_finalize(data_callid, addr,
-			    length);
-			if (rc != EOK) {
-				free(addr);
-				break;
-			}
-
-			fibril_rwlock_write_lock(&icmp_globals.lock);
-			rc = icmp_echo(echo_data->identifier,
-			    echo_data->sequence_number, ICMP_GET_SIZE(call),
-			    ICMP_GET_TIMEOUT(call), ICMP_GET_TTL(call),
-			    ICMP_GET_TOS(call), ICMP_GET_DONT_FRAGMENT(call),
-			    addr, (socklen_t) length);
-			fibril_rwlock_write_unlock(&icmp_globals.lock);
-
-			free(addr);
-
-			if (echo_data->sequence_number < UINT16_MAX)
-				echo_data->sequence_number++;
-			else
-				echo_data->sequence_number = 0;
-
-			break;
-
-		default:
-			rc = icmp_process_message(&call);
-		}
-
-	}
-
-	/* Release the identifier */
-	fibril_rwlock_write_lock(&icmp_globals.lock);
-	icmp_echo_data_exclude(&icmp_globals.echo_data, echo_data->identifier);
-	fibril_rwlock_write_unlock(&icmp_globals.lock);
-
-	return rc;
-}
-
-/** Processes the ICMP message.
- *
- * @param[in] callid	The message identifier.
- * @param[in] call	The message parameters.
- * @param[out] answer	The message answer parameters.
- * @param[out] answer_count The last parameter for the actual answer in the
- *			answer parameter.
- * @return		EOK on success.
- * @return		ENOTSUP if the message is not known.
- *
- * @see icmp_interface.h
- * @see IS_NET_ICMP_MESSAGE()
- */
-int tl_module_message	(ipc_callid_t callid, ipc_call_t *call,
-    ipc_call_t *answer, size_t *answer_count)
-{
-	*answer_count = 0;
-	switch (IPC_GET_IMETHOD(*call)) {
-	case NET_ICMP_INIT:
-		return icmp_process_client_messages(callid, *call);
-	default:
-		return icmp_process_message(call);
 	}
 	
Index: uspace/srv/net/tl/icmp/icmp.h
===================================================================
--- uspace/srv/net/tl/icmp/icmp.h	(revision e2b15486aeb1cc59be933d1e08b3299f89aebd7b)
+++ 	(revision )
@@ -1,108 +1,0 @@
-/*
- * Copyright (c) 2008 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 icmp
- * @{
- */
-
-/** @file
- * ICMP module.
- */
-
-#ifndef NET_ICMP_H_
-#define NET_ICMP_H_
-
-#include <fibril_synch.h>
-
-#include <net/icmp_codes.h>
-#include <net/packet.h>
-#include <adt/int_map.h>
-#include <icmp_header.h>
-
-/** Type definition of the ICMP reply data.
- * @see icmp_reply
- */
-typedef struct icmp_reply icmp_reply_t;
-
-/** Type definition of the ICMP global data.
- * @see icmp_globals
- */
-typedef struct icmp_globals icmp_globals_t;
-
-/** Pending replies map.
- *
- * Maps message identifiers to the pending replies.
- * Sending fibril waits for its associated reply event.
- * Receiving fibril sets the associated reply with the return value and signals
- * the event.
- */
-INT_MAP_DECLARE(icmp_replies, icmp_reply_t);
-
-/** Echo specific data map.
- *
- * The identifier is used in the future semi-remote calls instead of the ICMP
- * phone.
- */
-INT_MAP_DECLARE(icmp_echo_data, icmp_echo_t);
-
-/** ICMP reply data. */
-struct icmp_reply {
-	/** Reply result. */
-	int result;
-	/** Safety lock. */
-	fibril_mutex_t mutex;
-	/** Received or timeouted reply signaling. */
-	fibril_condvar_t condvar;
-};
-
-/** ICMP global data. */
-struct icmp_globals {
-	/** IP module phone. */
-	int ip_phone;
-	/** Packet dimension. */
-	packet_dimension_t packet_dimension;
-	/** Networking module phone. */
-	int net_phone;
-	/** Indicates whether ICMP error reporting is enabled. */
-	int error_reporting;
-	/** Indicates whether ICMP echo replying (ping) is enabled. */
-	int echo_replying;
-	/** The last used identifier number. */
-	icmp_param_t last_used_id;
-	/** The budled modules assigned echo specific data. */
-	icmp_echo_data_t echo_data;
-	/** Echo timeout locks. */
-	icmp_replies_t replies;
-	/** Safety lock. */
-	fibril_rwlock_t lock;
-};
-
-#endif
-
-/** @}
- */
Index: uspace/srv/net/tl/tcp/tcp.c
===================================================================
--- uspace/srv/net/tl/tcp/tcp.c	(revision e2b15486aeb1cc59be933d1e08b3299f89aebd7b)
+++ uspace/srv/net/tl/tcp/tcp.c	(revision 50c06df137e61ca4f6a5de9ada5a632686de0eed)
@@ -64,5 +64,5 @@
 #include <ip_interface.h>
 #include <icmp_client.h>
-#include <icmp_interface.h>
+#include <icmp_remote.h>
 #include <net_interface.h>
 #include <socket_core.h>
@@ -1204,4 +1204,11 @@
 }
 
+/** Per-connection initialization
+ *
+ */
+void tl_connection(void)
+{
+}
+
 /** Processes the TCP message.
  *
@@ -1217,5 +1224,5 @@
  * @see IS_NET_TCP_MESSAGE()
  */
-int tl_module_message(ipc_callid_t callid, ipc_call_t *call,
+int tl_message(ipc_callid_t callid, ipc_call_t *call,
     ipc_call_t *answer, size_t *answer_count)
 {
@@ -2472,6 +2479,5 @@
 	tcp_globals.net_phone = net_phone;
 	
-	tcp_globals.icmp_phone = icmp_connect_module(SERVICE_ICMP,
-	    ICMP_CONNECT_TIMEOUT);
+	tcp_globals.icmp_phone = icmp_connect_module(ICMP_CONNECT_TIMEOUT);
 	tcp_globals.ip_phone = ip_bind_service(SERVICE_IP, IPPROTO_TCP,
 	    SERVICE_TCP, tcp_receiver);
Index: uspace/srv/net/tl/udp/udp.c
===================================================================
--- uspace/srv/net/tl/udp/udp.c	(revision e2b15486aeb1cc59be933d1e08b3299f89aebd7b)
+++ uspace/srv/net/tl/udp/udp.c	(revision 50c06df137e61ca4f6a5de9ada5a632686de0eed)
@@ -61,5 +61,5 @@
 #include <ip_interface.h>
 #include <icmp_client.h>
-#include <icmp_interface.h>
+#include <icmp_remote.h>
 #include <net_interface.h>
 #include <socket_core.h>
@@ -393,6 +393,5 @@
 	udp_globals.net_phone = net_phone;
 	
-	udp_globals.icmp_phone = icmp_connect_module(SERVICE_ICMP,
-	    ICMP_CONNECT_TIMEOUT);
+	udp_globals.icmp_phone = icmp_connect_module(ICMP_CONNECT_TIMEOUT);
 	
 	udp_globals.ip_phone = ip_bind_service(SERVICE_IP, IPPROTO_UDP,
@@ -878,4 +877,11 @@
 }
 
+/** Per-connection initialization
+ *
+ */
+void tl_connection(void)
+{
+}
+
 /** Processes the UDP message.
  *
@@ -891,5 +897,5 @@
  * @see IS_NET_UDP_MESSAGE()
  */
-int tl_module_message(ipc_callid_t callid, ipc_call_t *call,
+int tl_message(ipc_callid_t callid, ipc_call_t *call,
     ipc_call_t *answer, size_t *answer_count)
 {
