Index: generic/src/ipc/ipc.c
===================================================================
--- generic/src/ipc/ipc.c	(revision 9f222130bdbe659719771a8bd4c6c15f3d4afd38)
+++ generic/src/ipc/ipc.c	(revision d2ab461b1422bde30deed4d303ce1d7c83e434e8)
@@ -146,5 +146,4 @@
 	answerbox_t *callerbox = call->callerbox;
 
-	call->flags &= ~IPC_CALL_DISPATCHED;
 	call->flags |= IPC_CALL_ANSWERED;
 
@@ -167,4 +166,21 @@
 	spinlock_unlock(&box->lock);
 	/* Send back answer */
+	_ipc_answer_free_call(call);
+}
+
+/** Simulate sending back a message
+ *
+ * Most errors are better handled by forming a normal backward
+ * message and sending it as a normal answer.
+ */
+void ipc_backsend_err(phone_t *phone, call_t *call, __native err)
+{
+	call->data.phone = phone;
+	atomic_inc(&phone->active_calls);
+	if (phone->busy == IPC_BUSY_CONNECTED)
+		IPC_SET_RETVAL(call->data, EHANGUP);
+	else
+		IPC_SET_RETVAL(call->data, ENOENT);
+
 	_ipc_answer_free_call(call);
 }
@@ -201,14 +217,12 @@
 		if (call->flags & IPC_CALL_FORWARDED) {
 			IPC_SET_RETVAL(call->data, EFORWARD);
-		} else { /* Simulate sending a message */
-			call->data.phone = phone;
-			atomic_inc(&phone->active_calls);
+			_ipc_answer_free_call(call);
+		} else { /* Simulate sending back a message */
 			if (phone->busy == IPC_BUSY_CONNECTED)
-				IPC_SET_RETVAL(call->data, EHANGUP);
+				ipc_backsend_err(phone, call, EHANGUP);
 			else
-				IPC_SET_RETVAL(call->data, ENOENT);
+				ipc_backsend_err(phone, call, ENOENT);
 		}
 
-		_ipc_answer_free_call(call);
 		return ENOENT;
 	}
@@ -308,5 +322,4 @@
 		/* Append request to dispatch queue */
 		list_append(&request->list, &box->dispatched_calls);
-		request->flags |= IPC_CALL_DISPATCHED;
 	} else {
 		printf("WARNING: Spurious IPC wakeup.\n");
Index: generic/src/ipc/ipcrsc.c
===================================================================
--- generic/src/ipc/ipcrsc.c	(revision 9f222130bdbe659719771a8bd4c6c15f3d4afd38)
+++ generic/src/ipc/ipcrsc.c	(revision d2ab461b1422bde30deed4d303ce1d7c83e434e8)
@@ -63,4 +63,20 @@
  * Destroying is less frequent, this approach is taken.
  *
+ * Phone call
+ *
+ * *** Connect_me_to ***
+ * The caller sends IPC_M_CONNECT_ME_TO to an answerbox. The server
+ * receives 'phoneid' of the connecting phone as an ARG3. If it answers
+ * with RETVAL=0, the phonecall is accepted, otherwise it is refused.
+ *
+ * *** Connect_to_me ***
+ * The caller sends IPC_M_CONNECT_TO_ME, with special 
+ * The server receives an automatically
+ * opened phoneid. If it accepts (RETVAL=0), it can use the phoneid
+ * immediately. 
+ * Possible race condition can arise, when the client receives messages
+ * from new connection before getting response for connect_to_me message.
+ * Userspace should implement handshake protocol that would control it.
+ *
  * Phone hangup
  * 
@@ -101,5 +117,5 @@
  *    appropriate error code (EHANGUP, EFORWARD).
  *
- * 4) Wait for all async answers to arrive.
+ * 4) Wait for all async answers to arrive and dispose of them.
  * 
  */
@@ -143,5 +159,14 @@
 }
 
-/** Disconnect phone a free the slot
+static void phone_deallocp(phone_t *phone)
+{
+	ASSERT(phone->busy == IPC_BUSY_CONNECTING);
+	ASSERT(! phone->callee);
+	
+	/* atomic operation */
+	phone->busy = IPC_BUSY_FREE;
+}
+
+/** Free slot from a disconnected phone
  *
  * All already sent messages will be correctly processed
@@ -149,11 +174,5 @@
 void phone_dealloc(int phoneid)
 {
-	spinlock_lock(&TASK->lock);
-
-	ASSERT(TASK->phones[phoneid].busy == IPC_BUSY_CONNECTING);
-	ASSERT(! TASK->phones[phoneid].callee);
-
-	TASK->phones[phoneid].busy = IPC_BUSY_FREE;
-	spinlock_unlock(&TASK->lock);
+	phone_deallocp(&TASK->phones[phoneid]);
 }
 
Index: generic/src/ipc/sysipc.c
===================================================================
--- generic/src/ipc/sysipc.c	(revision 9f222130bdbe659719771a8bd4c6c15f3d4afd38)
+++ generic/src/ipc/sysipc.c	(revision d2ab461b1422bde30deed4d303ce1d7c83e434e8)
@@ -48,5 +48,5 @@
 }
 
-#define STRUCT_TO_USPACE(dst,src) copy_to_uspace(dst,src,sizeof(*src))
+#define STRUCT_TO_USPACE(dst,src) copy_to_uspace(dst,src,sizeof(*(src)))
 
 /** Return true if the method is a system method */
@@ -106,6 +106,8 @@
 			phone_dealloc(phoneid);
 		} else {
-				/* The connection was accepted */
+			/* The connection was accepted */
 			phone_connect(phoneid,&answer->sender->answerbox);
+			/* Set 'phone identification' as arg3 of response */
+			IPC_SET_ARG3(answer->data, (__native)&TASK->phones[phoneid]);
 		}
 	} else if (IPC_GET_METHOD(*olddata) == IPC_M_CONNECT_ME_TO) {
@@ -118,4 +120,28 @@
 }
 
+/** Called before the request is sent
+ *
+ * @return 0 - no error, -1 - report error to user
+ */
+static int request_preprocess(call_t *call)
+{
+	int newphid;
+
+	switch (IPC_GET_METHOD(call->data)) {
+	case IPC_M_CONNECT_ME_TO:
+		newphid = phone_alloc();
+		if (newphid < 0)
+			return ELIMIT;
+		/* Set arg3 for server */
+		IPC_SET_ARG3(call->data, (__native)&TASK->phones[newphid]);
+		call->flags |= IPC_CALL_CONN_ME_TO;
+		call->private = newphid;
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
 /****************************************************/
 /* Functions called to process received call/answer 
@@ -124,10 +150,16 @@
 
 /** Do basic kernel processing of received call answer */
-static int process_answer(answerbox_t *box,call_t *call)
+static void process_answer(call_t *call)
 {
 	if (IPC_GET_RETVAL(call->data) == EHANGUP && \
 	    call->flags & IPC_CALL_FORWARDED)
 		IPC_SET_RETVAL(call->data, EFORWARD);
-	return 0;
+
+	if (call->flags & IPC_CALL_CONN_ME_TO) {
+		if (IPC_GET_RETVAL(call->data))
+			phone_dealloc(call->private);
+		else
+			IPC_SET_ARG3(call->data, call->private);
+	}
 }
 
@@ -162,7 +194,5 @@
 	call_t call;
 	phone_t *phone;
-
-	if (is_system_method(method))
-		return EPERM;
+	int res;
 
 	GET_CHECK_PHONE(phone, phoneid, return ENOENT);
@@ -171,7 +201,10 @@
 	IPC_SET_METHOD(call.data, method);
 	IPC_SET_ARG1(call.data, arg1);
-	
-	ipc_call_sync(phone, &call);
-
+
+	if (!(res=request_preprocess(&call))) {
+		ipc_call_sync(phone, &call);
+		process_answer(&call);
+	} else 
+		IPC_SET_RETVAL(call.data, res);
 	STRUCT_TO_USPACE(&data->args, &call.data.args);
 
@@ -185,14 +218,16 @@
 	call_t call;
 	phone_t *phone;
+	int res;
 
 	ipc_call_static_init(&call);
 	copy_from_uspace(&call.data.args, &question->args, sizeof(call.data.args));
 
-	if (is_system_method(IPC_GET_METHOD(call.data)))
-		return EPERM;
-	
 	GET_CHECK_PHONE(phone, phoneid, return ENOENT);
 
-	ipc_call_sync(phone, &call);
+	if (!(res=request_preprocess(&call))) {
+		ipc_call_sync(phone, &call);
+		process_answer(&call);
+	} else 
+		IPC_SET_RETVAL(call.data, res);
 
 	STRUCT_TO_USPACE(&reply->args, &call.data.args);
@@ -224,12 +259,10 @@
 	call_t *call;
 	phone_t *phone;
-
-	if (is_system_method(method))
-		return IPC_CALLRET_FATAL;
+	int res;
 
 	if (check_call_limit())
 		return IPC_CALLRET_TEMPORARY;
 
-	GET_CHECK_PHONE(phone, phoneid, return ENOENT);
+	GET_CHECK_PHONE(phone, phoneid, return IPC_CALLRET_FATAL);
 
 	call = ipc_call_alloc();
@@ -238,5 +271,8 @@
 	IPC_SET_ARG2(call->data, arg2);
 
-	ipc_call(phone, call);
+	if (!(res=request_preprocess(call)))
+		ipc_call(phone, call);
+	else
+		ipc_backsend_err(phone, call, res);
 
 	return (__native) call;
@@ -251,19 +287,17 @@
 	call_t *call;
 	phone_t *phone;
+	int res;
 
 	if (check_call_limit())
 		return IPC_CALLRET_TEMPORARY;
 
-	GET_CHECK_PHONE(phone, phoneid, return ENOENT);
+	GET_CHECK_PHONE(phone, phoneid, return IPC_CALLRET_FATAL);
 
 	call = ipc_call_alloc();
 	copy_from_uspace(&call->data.args, &data->args, sizeof(call->data.args));
-
-	if (is_system_method(IPC_GET_METHOD(call->data))) {
-		ipc_call_free(call);
-		return EPERM;
-	}
-	
-	ipc_call(phone, call);
+	if (!(res=request_preprocess(call)))
+		ipc_call(phone, call);
+	else
+		ipc_backsend_err(phone, call, res);
 
 	return (__native) call;
@@ -305,4 +339,7 @@
 	 */
 	if (is_system_method(IPC_GET_METHOD(call->data))) {
+		if (IPC_GET_METHOD(call->data) == IPC_M_CONNECT_TO_ME)
+			phone_dealloc(IPC_GET_ARG3(call->data));
+
 		IPC_SET_ARG1(call->data, method);
 		IPC_SET_ARG2(call->data, arg1);
@@ -366,65 +403,5 @@
 }
 
-/** Ask the other side of connection to do 'callback' connection
- *
- * @return 0 if no error, error otherwise 
- */
-__native sys_ipc_connect_to_me(__native phoneid, __native arg1,
-			       __native arg2, task_id_t *taskid)
-{
-	call_t call;
-	phone_t *phone;
-
-	ipc_call_static_init(&call);
-	IPC_SET_METHOD(call.data, IPC_M_CONNECT_TO_ME);
-	IPC_SET_ARG1(call.data, arg1);
-	IPC_SET_ARG2(call.data, arg2);
-	
-	GET_CHECK_PHONE(phone, phoneid, return ENOENT);
-
-	ipc_call_sync(phone, &call);
-
-	if (!IPC_GET_RETVAL(call.data) && taskid)
-		STRUCT_TO_USPACE(taskid, &phone->callee->task->taskid);
-
-	return IPC_GET_RETVAL(call.data);
-}
-
-/** Ask target process to connect me somewhere
- *
- * @return phoneid - on success, error otherwise
- */
-__native sys_ipc_connect_me_to(__native phoneid, __native arg1,
-			       __native arg2)
-{
-	call_t call;
-	phone_t *phone;
-	int newphid;
-
-	GET_CHECK_PHONE(phone, phoneid, return ENOENT);
-
-	newphid = phone_alloc();
-	if (newphid < 0)
-		return ELIMIT;
-
-	ipc_call_static_init(&call);
-	IPC_SET_METHOD(call.data, IPC_M_CONNECT_ME_TO);
-	IPC_SET_ARG1(call.data, arg1);
-	IPC_SET_ARG2(call.data, arg2);
-	IPC_SET_ARG3(call.data, (__native)&TASK->phones[newphid]);
-
-	ipc_call_sync(phone, &call);
-
-	if (IPC_GET_RETVAL(call.data)) { /* Connection failed */
-		phone_dealloc(newphid);
-		return IPC_GET_RETVAL(call.data);
-	}
-
-	return newphid;
-}
-
 /** Hang up the phone
- *
- * 
  *
  */
@@ -449,7 +426,5 @@
  * @return Callid, if callid & 1, then the call is answer
  */
-__native sys_ipc_wait_for_call(ipc_data_t *calldata, task_id_t *taskid,
-			       __native flags)
-					     
+__native sys_ipc_wait_for_call(ipc_data_t *calldata, __native flags)
 {
 	call_t *call;
@@ -461,6 +436,5 @@
 
 	if (call->flags & IPC_CALL_ANSWERED) {
-		if (process_answer(&TASK->answerbox, call))
-			goto restart;
+		process_answer(call);
 
 		ASSERT(! (call->flags & IPC_CALL_STATIC_ALLOC));
@@ -482,8 +456,7 @@
 		goto restart;
 
-	/* Include phone address('id') of the caller in the request */
+	/* Include phone address('id') of the caller in the request,
+	 * copy whole call->data, not only call->data.args */
 	STRUCT_TO_USPACE(calldata, &call->data);
-	if (IPC_GET_METHOD(call->data) == IPC_M_CONNECT_ME_TO)
-		STRUCT_TO_USPACE(taskid, &TASK->taskid);
 	return (__native)call;
 }
