Index: libadt/generic/hash_table.c
===================================================================
--- libadt/generic/hash_table.c	(revision babe786005b9357a2f47ef2edf4e666b83142f27)
+++ libadt/generic/hash_table.c	(revision 043dcc27a5fffcd359e0accdf1a6122945f3aec9)
@@ -107,8 +107,4 @@
 	assert(chain < h->entries);
 	
-	/*
-	 * The hash table is not redundant.
-	 * Check if the keys are not in place already.
-	 */
 	for (cur = h->entry[chain].next; cur != &h->entry[chain]; cur = cur->next) {
 		if (h->op->compare(key, h->max_keys, cur)) {
Index: libipc/generic/ipc.c
===================================================================
--- libipc/generic/ipc.c	(revision babe786005b9357a2f47ef2edf4e666b83142f27)
+++ libipc/generic/ipc.c	(revision 043dcc27a5fffcd359e0accdf1a6122945f3aec9)
@@ -273,4 +273,9 @@
 }
 
+int ipc_forward_fast(ipc_callid_t callid, int phoneid, int method, ipcarg_t arg1)
+{
+	return __SYSCALL4(SYS_IPC_FORWARD_FAST, callid, phoneid, method, arg1);
+}
+
 /*
 int ipc_open_dgrconn(int pohoneid, size_t max_dgram)
Index: libipc/include/ipc.h
===================================================================
--- libipc/include/ipc.h	(revision babe786005b9357a2f47ef2edf4e666b83142f27)
+++ libipc/include/ipc.h	(revision 043dcc27a5fffcd359e0accdf1a6122945f3aec9)
@@ -38,5 +38,5 @@
 typedef struct {
 	ipcarg_t args[IPC_CALL_LEN];
-	ipcarg_t phoneid;
+	ipcarg_t in_phone_hash;
 } ipc_call_t ;
 typedef sysarg_t ipc_callid_t;
@@ -59,12 +59,13 @@
 
 #define ipc_call_async(phoneid,method,arg1,private, callback) (ipc_call_async_2(phoneid, method, arg1, 0, private, callback))
-void ipc_call_async_2(int phoneid, ipcarg_t method, ipcarg_t arg1,
+extern void ipc_call_async_2(int phoneid, ipcarg_t method, ipcarg_t arg1,
 		      ipcarg_t arg2, void *private,
 		      ipc_async_callback_t callback);
-int ipc_connect_to_me(int phoneid, int arg1, int arg2, ipcarg_t *phone);
-int ipc_connect_me_to(int phoneid, int arg1, int arg2);
-int ipc_hangup(int phoneid);
-int ipc_register_irq(int irq, irq_code_t *code);
-int ipc_unregister_irq(int irq);
+extern int ipc_connect_to_me(int phoneid, int arg1, int arg2, ipcarg_t *phone);
+extern int ipc_connect_me_to(int phoneid, int arg1, int arg2);
+extern int ipc_hangup(int phoneid);
+extern int ipc_register_irq(int irq, irq_code_t *code);
+extern int ipc_unregister_irq(int irq);
+extern int ipc_forward_fast(ipc_callid_t callid, int phoneid, int method, ipcarg_t arg1);
 
 #endif
Index: ns/ns.c
===================================================================
--- ns/ns.c	(revision babe786005b9357a2f47ef2edf4e666b83142f27)
+++ ns/ns.c	(revision 043dcc27a5fffcd359e0accdf1a6122945f3aec9)
@@ -46,7 +46,11 @@
 #define NS_HASH_TABLE_CHAINS	20
 
+static int register_service(ipcarg_t service, ipcarg_t phone, ipc_call_t *call);
+static int connect_to_service(ipcarg_t service, ipc_call_t *call, ipc_callid_t callid);
+
 /* Static functions implementing NS hash table operations. */
 static hash_index_t ns_hash(unsigned long *key);
 static int ns_compare(unsigned long *key, hash_count_t keys, link_t *item);
+static void ns_remove(link_t *item);
 
 /** Operations for NS hash table. */
@@ -54,5 +58,5 @@
 	.hash = ns_hash,
 	.compare = ns_compare,
-	.remove_callback = NULL
+	.remove_callback = ns_remove
 };
 
@@ -65,4 +69,5 @@
 	ipcarg_t service;		/**< Number of the service. */
 	ipcarg_t phone;			/**< Phone registered with the service. */
+	ipcarg_t in_phone_hash;		/**< Incoming phone hash. */
 } hashed_service_t;
 
@@ -101,5 +106,5 @@
 	printf("%s: Name service started.\n", NAME);
 	
-	if (!hash_table_create(&ns_hash_table, NS_HASH_TABLE_CHAINS, 1, &ns_hash_table_ops)) {
+	if (!hash_table_create(&ns_hash_table, NS_HASH_TABLE_CHAINS, 3, &ns_hash_table_ops)) {
 		printf("%s: cannot create hash table\n", NAME);
 		return ENOMEM;
@@ -111,5 +116,5 @@
 	while (1) {
 		callid = ipc_wait_for_call(&call, 0);
-		printf("NS: Call phone=%lX...", call.phoneid);
+		printf("NS: Call in_phone_hash=%lX...", call.in_phone_hash);
 		switch (IPC_GET_METHOD(call)) {
 		case IPC_M_AS_SEND:
@@ -131,33 +136,16 @@
 			retval = 0;
 			break;
-		case IPC_M_CONNECT_TO_ME:;
+		case IPC_M_CONNECT_TO_ME:
 			/*
-			 * Request for registration of a service.
+			 * Server requests service registration.
 			 */
-			ipcarg_t service;
-			ipcarg_t phone;
-			hashed_service_t *hs;
-			
-			service = IPC_GET_ARG1(call);
-			phone = IPC_GET_ARG3(call);
-			printf("Registering service %d on phone %d...", service, phone);
-			
-			hs = (hashed_service_t *) malloc(sizeof(hashed_service_t));
-			if (!hs) {
-				printf("Failed to register service %d.\n", service);
-			}
-			
-			link_initialize(&hs->link);
-			hs->service = service;
-			hs->phone = phone;
-			hash_table_insert(&ns_hash_table, (unsigned long *) &service, &hs->link);
-			
-			ping_phone = phone;
-			retval = 0;
+			retval = register_service(IPC_GET_ARG1(call), IPC_GET_ARG3(call), &call);
+			ping_phone = IPC_GET_ARG3(call);
 			break;
 		case IPC_M_CONNECT_ME_TO:
-			printf("Connectme(%P)to: %zd\n",
-			       IPC_GET_ARG3(call), IPC_GET_ARG1(call));
-			retval = 0;
+			/*
+			 * Client requests to be connected to a service.
+			 */
+			retval = connect_to_service(IPC_GET_ARG1(call), &call, callid);
 			break;
 		case NS_PING:
@@ -189,8 +177,68 @@
 }
 
+/** Register server.
+ *
+ * @param service Service to be registered.
+ * @param phone phone Phone to be used for connections to the service.
+ * @param call Pointer to call structure.
+ *
+ * @return Zero on success or a value from @ref errno.h.
+ */
+int register_service(ipcarg_t service, ipcarg_t phone, ipc_call_t *call)
+{
+	unsigned long keys[3] = { service, call->in_phone_hash, 0 };
+	hashed_service_t *hs;
+			
+	printf("Registering service %d on phone %d...", service, phone);
+
+	if (hash_table_find(&ns_hash_table, keys)) {
+		printf("Service %d already registered.\n", service);
+		return EEXISTS;
+	}
+			
+	hs = (hashed_service_t *) malloc(sizeof(hashed_service_t));
+	if (!hs) {
+		printf("Failed to register service %d.\n", service);
+		return ENOMEM;
+	}
+			
+	link_initialize(&hs->link);
+	hs->service = service;
+	hs->phone = phone;
+	hs->in_phone_hash = call->in_phone_hash;
+	hash_table_insert(&ns_hash_table, keys, &hs->link);
+			
+	return 0;
+}
+
+/** Connect client to service.
+ *
+ * @param service Service to be connected to.
+ * @param call Pointer to call structure.
+ * @param callid Call ID of the request.
+ *
+ * @return Zero on success or a value from @ref errno.h.
+ */
+int connect_to_service(ipcarg_t service, ipc_call_t *call, ipc_callid_t callid)
+{
+	unsigned long keys[3] = { service, 0, 0 };
+	link_t *hlp;
+	hashed_service_t *hs;
+			
+	hlp = hash_table_find(&ns_hash_table, keys);
+	if (!hlp) {
+		printf("Service %d noty registered.\n", service);
+		return ENOENT;
+	}
+	hs = hash_table_get_instance(hlp, hashed_service_t, link);
+	printf("Connecting in_phone_hash=%lX to service at phone %d...", call->in_phone_hash, hs->phone);
+	return ipc_forward_fast(callid, hs->phone, 0, 0);
+}
+
 /** Compute hash index into NS hash table.
  *
- * @param key Pointer to single key (i.e. service number).
- * @return Hash index corresponding to *key.
+ * @param key Pointer keys. However, only the first key (i.e. service number)
+ * 	      is used to compute the hash index.
+ * @return Hash index corresponding to key[0].
  */
 hash_index_t ns_hash(unsigned long *key)
@@ -202,19 +250,38 @@
 /** Compare a key with hashed item.
  *
- * @param key Single key pointer.
- * @param keys Must be 1.
+ * This compare function always ignores the third key.
+ * It exists only to make it possible to remove records
+ * originating from connection with key[1] in_phone_hash
+ * value. Note that this is close to being classified
+ * as a nasty hack.
+ *
+ * @param key Array of keys.
+ * @param keys Must be lesser or equal to 3.
  * @param item Pointer to a hash table item.
  * @return Non-zero if the key matches the item, zero otherwise.
  */
-int ns_compare(unsigned long *key, hash_count_t keys, link_t *item)
+int ns_compare(unsigned long key[], hash_count_t keys, link_t *item)
 {
 	hashed_service_t *hs;
 
 	assert(key);
-	assert(keys == 1);
+	assert(keys <= 3);
 	assert(item);
 	
 	hs = hash_table_get_instance(item, hashed_service_t, link);
 	
-	return *key == hs->service;
-}
+	if (keys == 2)
+		return key[1] == hs->in_phone_hash;
+	else
+		return key[0] == hs->service;
+}
+
+/** Perform actions after removal of item from the hash table.
+ *
+ * @param item Item that was removed from the hash table.
+ */
+void ns_remove(link_t *item)
+{
+	assert(item);
+	free(hash_table_get_instance(item, hashed_service_t, link));
+}
Index: pci/pci.c
===================================================================
--- pci/pci.c	(revision babe786005b9357a2f47ef2edf4e666b83142f27)
+++ pci/pci.c	(revision 043dcc27a5fffcd359e0accdf1a6122945f3aec9)
@@ -32,5 +32,5 @@
 
 	int ipc_res;
-	ipcarg_t ns_phone_addr;
+	ipcarg_t ns_in_phone_hash;
 
 	printf("%s: HelenOS PCI driver\n", NAME);
@@ -56,5 +56,5 @@
 
 	printf("%s: registering at naming service.\n", NAME);
-	if (ipc_connect_to_me(PHONE_NS, 40, 70, &ns_phone_addr) != 0) {
+	if (ipc_connect_to_me(PHONE_NS, 40, 70, &ns_in_phone_hash) != 0) {
 		printf("Failed to register %s at naming service.\n", NAME);
 		return -1;
