Index: kernel/generic/include/ipc/ipc.h
===================================================================
--- kernel/generic/include/ipc/ipc.h	(revision 98cb5e0d438f111dd28c92d57d12c9aa74bd2f98)
+++ kernel/generic/include/ipc/ipc.h	(revision 01c3bb491370247ba1459d7e381e27022f09fed4)
@@ -112,5 +112,5 @@
 } ipc_data_t;
 
-typedef struct {
+typedef struct call {
 	kobject_t *kobject;
 
Index: kernel/generic/include/ipc/ipcrsc.h
===================================================================
--- kernel/generic/include/ipc/ipcrsc.h	(revision 98cb5e0d438f111dd28c92d57d12c9aa74bd2f98)
+++ kernel/generic/include/ipc/ipcrsc.h	(revision 01c3bb491370247ba1459d7e381e27022f09fed4)
@@ -40,5 +40,4 @@
 #include <cap/cap.h>
 
-extern call_t *get_call(sysarg_t);
 extern cap_handle_t phone_alloc(task_t *);
 extern bool phone_connect(cap_handle_t, answerbox_t *);
Index: kernel/generic/src/ipc/ipcrsc.c
===================================================================
--- kernel/generic/src/ipc/ipcrsc.c	(revision 98cb5e0d438f111dd28c92d57d12c9aa74bd2f98)
+++ kernel/generic/src/ipc/ipcrsc.c	(revision 01c3bb491370247ba1459d7e381e27022f09fed4)
@@ -136,31 +136,4 @@
 #include <cap/cap.h>
 #include <mm/slab.h>
-
-/** Find call_t * in call table according to callid.
- *
- * @todo Some speedup (hash table?)
- *
- * @param callid Userspace hash of the call. Currently it is the call structure
- *               kernel address.
- *
- * @return NULL on not found, otherwise pointer to the call structure.
- *
- */
-call_t *get_call(sysarg_t callid)
-{
-	call_t *result = NULL;
-	
-	irq_spinlock_lock(&TASK->answerbox.lock, true);
-	
-	list_foreach(TASK->answerbox.dispatched_calls, ab_link, call_t, call) {
-		if ((sysarg_t) call == callid) {
-			result = call;
-			break;
-		}
-	}
-	
-	irq_spinlock_unlock(&TASK->answerbox.lock, true);
-	return result;
-}
 
 static bool phone_reclaim(kobject_t *kobj)
Index: kernel/generic/src/ipc/sysipc.c
===================================================================
--- kernel/generic/src/ipc/sysipc.c	(revision 98cb5e0d438f111dd28c92d57d12c9aa74bd2f98)
+++ kernel/generic/src/ipc/sysipc.c	(revision 01c3bb491370247ba1459d7e381e27022f09fed4)
@@ -53,4 +53,5 @@
 #include <print.h>
 #include <macros.h>
+#include <cap/cap.h>
 
 #define STRUCT_TO_USPACE(dst, src)  copy_to_uspace((dst), (src), sizeof(*(src)))
@@ -447,6 +448,6 @@
  * Common code for both the fast and the slow version.
  *
- * @param callid   Hash of the call to forward.
- * @param handle   Phone capability to use for forwarding.
+ * @param chandle  Call handle of the forwarded call.
+ * @param phandle  Phone handle to use for forwarding.
  * @param imethod  New interface and method to use for the forwarded call.
  * @param arg1     New value of the first argument for the forwarded call.
@@ -465,12 +466,14 @@
  *
  */
-static sysarg_t sys_ipc_forward_common(sysarg_t callid, sysarg_t handle,
+static sysarg_t sys_ipc_forward_common(sysarg_t chandle, sysarg_t phandle,
     sysarg_t imethod, sysarg_t arg1, sysarg_t arg2, sysarg_t arg3,
     sysarg_t arg4, sysarg_t arg5, unsigned int mode, bool slow)
 {
-	call_t *call = get_call(callid);
-	if (!call)
+	kobject_t *ckobj = cap_unpublish(TASK, chandle, KOBJECT_TYPE_CALL);
+	if (!ckobj)
 		return ENOENT;
 	
+	call_t *call = ckobj->call;
+
 	ipc_data_t old;
 	bool need_old = answer_need_old(call);
@@ -481,6 +484,6 @@
 	int rc;
 
-	kobject_t *kobj = kobject_get(TASK, handle, KOBJECT_TYPE_PHONE);
-	if (!kobj) {
+	kobject_t *pkobj = kobject_get(TASK, phandle, KOBJECT_TYPE_PHONE);
+	if (!pkobj) {
 		rc = ENOENT;
 		goto error;
@@ -528,5 +531,5 @@
 	}
 	
-	rc = ipc_forward(call, kobj->phone, &TASK->answerbox, mode);
+	rc = ipc_forward(call, pkobj->phone, &TASK->answerbox, mode);
 	if (rc != EOK) {
 		after_forward = true;
@@ -534,5 +537,7 @@
 	}
 
-	kobject_put(kobj);
+	cap_free(TASK, chandle);
+	kobject_put(ckobj);
+	kobject_put(pkobj);
 	return EOK;
 
@@ -545,6 +550,9 @@
 		ipc_answer(&TASK->answerbox, call);
 
-	if (kobj)
-		kobject_put(kobj);
+	/* Republish the capability so that the call does not get lost. */
+	cap_publish(TASK, chandle, ckobj);
+
+	if (pkobj)
+		kobject_put(pkobj);
 	return rc;
 }
@@ -559,6 +567,6 @@
  * arguments are not set and these values are ignored.
  *
- * @param callid   Hash of the call to forward.
- * @param handle   Phone handle to use for forwarding.
+ * @param chandle  Call handle of the call to forward.
+ * @param phandle  Phone handle to use for forwarding.
  * @param imethod  New interface and method to use for the forwarded call.
  * @param arg1     New value of the first argument for the forwarded call.
@@ -569,9 +577,9 @@
  *
  */
-sysarg_t sys_ipc_forward_fast(sysarg_t callid, sysarg_t handle,
+sysarg_t sys_ipc_forward_fast(sysarg_t chandle, sysarg_t phandle,
     sysarg_t imethod, sysarg_t arg1, sysarg_t arg2, unsigned int mode)
 {
-	return sys_ipc_forward_common(callid, handle, imethod, arg1, arg2, 0, 0,
-	    0, mode, false); 
+	return sys_ipc_forward_common(chandle, phandle, imethod, arg1, arg2, 0,
+	    0, 0, mode, false);
 }
 
@@ -585,13 +593,13 @@
  * and arg5, respectively, to ARG3, ARG4 and ARG5, respectively.
  *
- * @param callid  Hash of the call to forward.
- * @param handle  Phone handle to use for forwarding.
- * @param data    Userspace address of the new IPC data.
- * @param mode    Flags that specify mode of the forward operation.
+ * @param chandle  Call handle of the call to forward.
+ * @param phandle  Phone handle to use for forwarding.
+ * @param data     Userspace address of the new IPC data.
+ * @param mode     Flags that specify mode of the forward operation.
  *
  * @return 0 on succes, otherwise an error code.
  *
  */
-sysarg_t sys_ipc_forward_slow(sysarg_t callid, sysarg_t handle,
+sysarg_t sys_ipc_forward_slow(sysarg_t chandle, sysarg_t phandle,
     ipc_data_t *data, unsigned int mode)
 {
@@ -602,8 +610,8 @@
 		return (sysarg_t) rc;
 	
-	return sys_ipc_forward_common(callid, handle,
+	return sys_ipc_forward_common(chandle, phandle,
 	    IPC_GET_IMETHOD(newdata), IPC_GET_ARG1(newdata),
 	    IPC_GET_ARG2(newdata), IPC_GET_ARG3(newdata),
-	    IPC_GET_ARG4(newdata), IPC_GET_ARG5(newdata), mode, true); 
+	    IPC_GET_ARG4(newdata), IPC_GET_ARG5(newdata), mode, true);
 }
 
@@ -613,25 +621,23 @@
  * than the generic sys_ipc_answer().
  *
- * @param callid Hash of the call to be answered.
- * @param retval Return value of the answer.
- * @param arg1   Service-defined return value.
- * @param arg2   Service-defined return value.
- * @param arg3   Service-defined return value.
- * @param arg4   Service-defined return value.
+ * @param chandle  Call handle to be answered.
+ * @param retval   Return value of the answer.
+ * @param arg1     Service-defined return value.
+ * @param arg2     Service-defined return value.
+ * @param arg3     Service-defined return value.
+ * @param arg4     Service-defined return value.
  *
  * @return 0 on success, otherwise an error code.
  *
  */
-sysarg_t sys_ipc_answer_fast(sysarg_t callid, sysarg_t retval,
-    sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4)
-{
-	/* Do not answer notification callids */
-	if (callid & IPC_CALLID_NOTIFICATION)
-		return 0;
-	
-	call_t *call = get_call(callid);
-	if (!call)
+sysarg_t sys_ipc_answer_fast(sysarg_t chandle, sysarg_t retval, sysarg_t arg1,
+    sysarg_t arg2, sysarg_t arg3, sysarg_t arg4)
+{
+	kobject_t *kobj = cap_unpublish(TASK, chandle, KOBJECT_TYPE_CALL);
+	if (!kobj)
 		return ENOENT;
 	
+	call_t *call = kobj->call;
+
 	ipc_data_t saved_data;
 	bool saved;
@@ -657,4 +663,8 @@
 	
 	ipc_answer(&TASK->answerbox, call);
+
+	kobject_put(kobj);
+	cap_free(TASK, chandle);
+
 	return rc;
 }
@@ -662,20 +672,18 @@
 /** Answer an IPC call.
  *
- * @param callid Hash of the call to be answered.
- * @param data   Userspace address of call data with the answer.
+ * @param chandle Call handle to be answered.
+ * @param data    Userspace address of call data with the answer.
  *
  * @return 0 on success, otherwise an error code.
  *
  */
-sysarg_t sys_ipc_answer_slow(sysarg_t callid, ipc_data_t *data)
-{
-	/* Do not answer notification callids */
-	if (callid & IPC_CALLID_NOTIFICATION)
-		return 0;
-	
-	call_t *call = get_call(callid);
-	if (!call)
+sysarg_t sys_ipc_answer_slow(sysarg_t chandle, ipc_data_t *data)
+{
+	kobject_t *kobj = cap_unpublish(TASK, chandle, KOBJECT_TYPE_CALL);
+	if (!kobj)
 		return ENOENT;
 	
+	call_t *call = kobj->call;
+
 	ipc_data_t saved_data;
 	bool saved;
@@ -689,10 +697,19 @@
 	int rc = copy_from_uspace(&call->data.args, &data->args, 
 	    sizeof(call->data.args));
-	if (rc != 0)
+	if (rc != 0) {
+		/*
+		 * Republish the capability so that the call does not get lost.
+		 */
+		cap_publish(TASK, chandle, kobj);
 		return rc;
+	}
 	
 	rc = answer_preprocess(call, saved ? &saved_data : NULL);
 	
 	ipc_answer(&TASK->answerbox, call);
+
+	kobject_put(kobj);
+	cap_free(TASK, chandle);
+
 	return rc;
 }
@@ -727,5 +744,7 @@
  *                 for explanation.
  *
- * @return Hash of the call.
+ * @return Capability handle of the received request.
+ * @return CAP_NIL for answers, notifications and when there is no call.
+ * @return Negative error code on error.
  */
 sysarg_t sys_ipc_wait_for_call(ipc_data_t *calldata, uint32_t usec,
@@ -746,7 +765,9 @@
 	udebug_stoppable_end();
 #endif
-	
-	if (!call)
-		return 0;
+
+	if (!call) {
+		STRUCT_TO_USPACE(calldata, &(ipc_data_t){});
+		return CAP_NIL;
+	}
 	
 	if (call->flags & IPC_CALL_NOTIF) {
@@ -759,5 +780,5 @@
 		kobject_put(call->kobject);
 		
-		return (sysarg_t) call;
+		return CAP_NIL;
 	}
 	
@@ -775,5 +796,5 @@
 		kobject_put(call->kobject);
 		
-		return (sysarg_t) call;
+		return CAP_NIL;
 	}
 	
@@ -781,27 +802,45 @@
 		goto restart;
 	
-	/* Include phone address('id') of the caller in the request,
-	 * copy whole call->data, not only call->data.args */
-	if (STRUCT_TO_USPACE(calldata, &call->data)) {
-		/*
-		 * The callee will not receive this call and no one else has
-		 * a chance to answer it. Reply with the EPARTY error code.
-		 */
-		ipc_data_t saved_data;
-		bool saved;
-		
-		if (answer_need_old(call)) {
-			memcpy(&saved_data, &call->data, sizeof(call->data));
-			saved = true;
-		} else
-			saved = false;
-		
-		IPC_SET_RETVAL(call->data, EPARTY);
-		(void) answer_preprocess(call, saved ? &saved_data : NULL);
-		ipc_answer(&TASK->answerbox, call);
-		return 0;
-	}
-	
-	return (sysarg_t) call;
+	int rc;
+	cap_handle_t handle = cap_alloc(TASK);
+	if (handle < 0) {
+		rc = handle;
+		goto error;
+	}
+	
+	/*
+	 * Include phone hash of the caller in the request, copy the whole
+	 * call->data, not only call->data.args.
+	 */
+	rc = STRUCT_TO_USPACE(calldata, &call->data);
+	if (rc != EOK)
+		goto error;
+
+	kobject_add_ref(call->kobject);
+	cap_publish(TASK, handle, call->kobject);
+	return handle;
+
+error:
+	if (handle >= 0)
+		cap_free(TASK, handle);
+
+	/*
+	 * The callee will not receive this call and no one else has a chance to
+	 * answer it. Reply with the EPARTY error code.
+	 */
+	ipc_data_t saved_data;
+	bool saved;
+
+	if (answer_need_old(call)) {
+		memcpy(&saved_data, &call->data, sizeof(call->data));
+		saved = true;
+	} else
+		saved = false;
+
+	IPC_SET_RETVAL(call->data, EPARTY);
+	(void) answer_preprocess(call, saved ? &saved_data : NULL);
+	ipc_answer(&TASK->answerbox, call);
+
+	return rc;
 }
 
