Index: generic/include/errno.h
===================================================================
--- generic/include/errno.h	(revision b4b45210fc5bef84b7f8456d96320f10dd3f5245)
+++ generic/include/errno.h	(revision 9f222130bdbe659719771a8bd4c6c15f3d4afd38)
@@ -38,4 +38,7 @@
 #define EFORWARD   -5  /* Forward error */
 #define EPERM      -6  /* Permission denied */
+#define EHANGUP    -7  /* Answerbox closed cionnection, call sys_ipc_hangup
+			* to close the connection. Used by answerbox
+			* to close the connection.  */
 
 #endif
Index: generic/include/ipc/ipc.h
===================================================================
--- generic/include/ipc/ipc.h	(revision b4b45210fc5bef84b7f8456d96320f10dd3f5245)
+++ generic/include/ipc/ipc.h	(revision 9f222130bdbe659719771a8bd4c6c15f3d4afd38)
@@ -38,9 +38,10 @@
 
 /* Flags for calls */
-#define IPC_CALL_ANSWERED     (1<<0) /**< This is answer to a call */
-#define IPC_CALL_STATIC_ALLOC (1<<1) /**< This call will not be freed on error */
-#define IPC_CALL_DISPATCHED   (1<<2) /**< Call is in dispatch queue */
+#define IPC_CALL_ANSWERED       (1<<0) /**< This is answer to a call */
+#define IPC_CALL_STATIC_ALLOC   (1<<1) /**< This call will not be freed on error */
+#define IPC_CALL_DISPATCHED     (1<<2) /**< Call is in dispatch queue */
 #define IPC_CALL_DISCARD_ANSWER (1<<3) /**< Answer will not be passed to
 					* userspace, will be discarded */
+#define IPC_CALL_FORWARDED      (1<<4) /* Call was forwarded */
 
 /* Flags for ipc_wait_for_call */
@@ -156,9 +157,15 @@
 };
 
+typedef enum {
+	IPC_BUSY_FREE = 0,
+	IPC_BUSY_CONNECTING,
+	IPC_BUSY_CONNECTED
+} ipc_busy_t;
+
 struct phone_s {
 	SPINLOCK_DECLARE(lock);
 	link_t list;
 	answerbox_t *callee;
-	int busy;
+	ipc_busy_t busy;
 	atomic_t active_calls;
 };
@@ -182,5 +189,5 @@
 extern call_t * ipc_wait_for_call(answerbox_t *box, int flags);
 extern void ipc_answer(answerbox_t *box, call_t *request);
-extern void ipc_call(phone_t *phone, call_t *request);
+extern int ipc_call(phone_t *phone, call_t *call);
 extern void ipc_call_sync(phone_t *phone, call_t *request);
 extern void ipc_phone_init(phone_t *phone);
@@ -191,5 +198,5 @@
 extern void ipc_call_static_init(call_t *call);
 extern void task_print_list(void);
-extern void ipc_forward(call_t *call, phone_t *newphone, answerbox_t *oldbox);
+extern int ipc_forward(call_t *call, phone_t *newphone, answerbox_t *oldbox);
 
 extern answerbox_t *ipc_phone_0;
Index: generic/src/ipc/ipc.c
===================================================================
--- generic/src/ipc/ipc.c	(revision b4b45210fc5bef84b7f8456d96320f10dd3f5245)
+++ generic/src/ipc/ipc.c	(revision 9f222130bdbe659719771a8bd4c6c15f3d4afd38)
@@ -105,5 +105,5 @@
 
 	ASSERT(!phone->callee);
-	phone->busy = 1;
+	phone->busy = IPC_BUSY_CONNECTED;
 	phone->callee = box;
 
@@ -121,5 +121,6 @@
 	spinlock_initialize(&phone->lock, "phone_lock");
 	phone->callee = NULL;
-	phone->busy = 0;
+	phone->busy = IPC_BUSY_FREE;
+	atomic_set(&phone->active_calls, 0);
 }
 
@@ -172,6 +173,8 @@
 static void _ipc_call(phone_t *phone, answerbox_t *box, call_t *call)
 {
-	atomic_inc(&phone->active_calls);
-	call->data.phone = phone;
+	if (! (call->flags & IPC_CALL_FORWARDED)) {
+		atomic_inc(&phone->active_calls);
+		call->data.phone = phone;
+	}
 
 	spinlock_lock(&box->lock);
@@ -186,5 +189,5 @@
  * @param request Request to be sent
  */
-void ipc_call(phone_t *phone, call_t *call)
+int ipc_call(phone_t *phone, call_t *call)
 {
 	answerbox_t *box;
@@ -196,13 +199,22 @@
 		/* Trying to send over disconnected phone */
 		spinlock_unlock(&phone->lock);
-
-		call->data.phone = phone;
-		IPC_SET_RETVAL(call->data, ENOENT);
+		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);
+			if (phone->busy == IPC_BUSY_CONNECTED)
+				IPC_SET_RETVAL(call->data, EHANGUP);
+			else
+				IPC_SET_RETVAL(call->data, ENOENT);
+		}
+
 		_ipc_answer_free_call(call);
-		return;
+		return ENOENT;
 	}
 	_ipc_call(phone, box, call);
 	
 	spinlock_unlock(&phone->lock);
+	return 0;
 }
 
@@ -221,6 +233,12 @@
 	box = phone->callee;
 	if (!box) {
+		if (phone->busy == IPC_BUSY_CONNECTING) {
+			spinlock_unlock(&phone->lock);
+			return -1;
+		}
+		/* Already disconnected phone */
+		phone->busy = IPC_BUSY_FREE;
 		spinlock_unlock(&phone->lock);
-		return -1;
+		return 0;
 	}
 
@@ -235,5 +253,5 @@
 	_ipc_call(phone, box, call);
 
-	phone->busy = 0;
+	phone->busy = IPC_BUSY_FREE;
 
 	spinlock_unlock(&phone->lock);
@@ -247,13 +265,16 @@
  * @param newbox Target answerbox
  * @param oldbox Old answerbox
- */
-void ipc_forward(call_t *call, phone_t *newphone, answerbox_t *oldbox)
+ * @return 0 on forward ok, error code, if there was error
+ * 
+ * - the return value serves only as an information for the forwarder,
+ *   the original caller is notified automatically with EFORWARD
+ */
+int ipc_forward(call_t *call, phone_t *newphone, answerbox_t *oldbox)
 {
 	spinlock_lock(&oldbox->lock);
-	atomic_dec(&call->data.phone->active_calls);
 	list_remove(&call->list);
 	spinlock_unlock(&oldbox->lock);
 
-	ipc_call(newphone, call);
+	return ipc_call(newphone, call);
 }
 
@@ -280,6 +301,4 @@
 		request = list_get_instance(box->answers.next, call_t, list);
 		list_remove(&request->list);
-		printf("%d %P\n", IPC_GET_METHOD(request->data), 
-		       request->data.phone);
 		atomic_dec(&request->data.phone->active_calls);
 	} else if (!list_empty(&box->calls)) {
@@ -314,5 +333,14 @@
 void ipc_cleanup(task_t *task)
 {
-	/* Cancel all calls in my dispatch queue */
+	int i;
+
+	/* Disconnect all our phones ('ipc_phone_hangup') */
+	for (i=0;i < IPC_MAX_PHONES; i++)
+		ipc_phone_hangup(&task->phones[i]);
+
+	/* Disconnect all phones connected to answerbox */
+
+	/* Answer all messages in 'calls' and 'dispatched_calls' queues */
 	
-}
+	/* Wait for all async answers to arrive */
+}
Index: generic/src/ipc/ipcrsc.c
===================================================================
--- generic/src/ipc/ipcrsc.c	(revision b4b45210fc5bef84b7f8456d96320f10dd3f5245)
+++ generic/src/ipc/ipcrsc.c	(revision 9f222130bdbe659719771a8bd4c6c15f3d4afd38)
@@ -71,21 +71,35 @@
  *   calls are answered, the phone is deallocated.
  *
- * *** The answerbox hangs up (ipc_answer(ESLAM))
- * - The phone is disconnected. IPC_M_ANSWERBOX_HUNGUP notification
- *   is sent to source task, the calling process is expected to
+ * *** The answerbox hangs up (ipc_answer(EHANGUP))
+ * - The phone is disconnected. EHANGUP response code is sent
+ *   to the calling process. All new calls through this phone
+ *   get a EHUNGUP error code, the task is expected to
  *   send an sys_ipc_hangup after cleaning up it's internal structures.
+ *
+ * Call forwarding
+ * 
+ * The call can be forwarded, so that the answer to call is passed directly
+ * to the original sender. However, this poses special problems regarding 
+ * routing of hangup messages.
+ *
+ * sys_ipc_hangup -> IPC_M_PHONE_HUNGUP
+ * - this message CANNOT be forwarded
+ *
+ * EHANGUP during forward
+ * - The *forwarding* phone will be closed, EFORWARD is sent to receiver.
+ *
+ * EHANGUP, ENOENT during forward
+ * - EFORWARD is sent to the receiver, ipc_forward returns error code EFORWARD
  *
  * Cleanup strategy
  * 
- * 1) Disconnect all our phones ('sys_ipc_hangup')
+ * 1) Disconnect all our phones ('ipc_phone_hangup').
  *
  * 2) Disconnect all phones connected to answerbox.
- *    * Send message 'PHONE_DISCONNECTED' to the target application 
- * - Once all phones are disconnected, no further calls can arrive
  *
  * 3) Answer all messages in 'calls' and 'dispatched_calls' queues with
- *    appropriate error code.
+ *    appropriate error code (EHANGUP, EFORWARD).
  *
- * 4) Wait for all async answers to arrive
+ * 4) Wait for all async answers to arrive.
  * 
  */
@@ -117,6 +131,6 @@
 	
 	for (i=0; i < IPC_MAX_PHONES; i++) {
-		if (!TASK->phones[i].busy && !atomic_get(&TASK->phones[i].active_calls)) {
-			TASK->phones[i].busy = 1;
+		if (TASK->phones[i].busy==IPC_BUSY_FREE && !atomic_get(&TASK->phones[i].active_calls)) {
+			TASK->phones[i].busy = IPC_BUSY_CONNECTING;
 			break;
 		}
@@ -137,8 +151,8 @@
 	spinlock_lock(&TASK->lock);
 
-	ASSERT(TASK->phones[phoneid].busy);
+	ASSERT(TASK->phones[phoneid].busy == IPC_BUSY_CONNECTING);
 	ASSERT(! TASK->phones[phoneid].callee);
 
-	TASK->phones[phoneid].busy = 0;
+	TASK->phones[phoneid].busy = IPC_BUSY_FREE;
 	spinlock_unlock(&TASK->lock);
 }
@@ -156,5 +170,5 @@
 	phone_t *phone = &TASK->phones[phoneid];
 	
-	ASSERT(phone->busy);
+	ASSERT(phone->busy == IPC_BUSY_CONNECTING);
 	ipc_phone_connect(phone, box);
 }
Index: generic/src/ipc/sysipc.c
===================================================================
--- generic/src/ipc/sysipc.c	(revision b4b45210fc5bef84b7f8456d96320f10dd3f5245)
+++ generic/src/ipc/sysipc.c	(revision 9f222130bdbe659719771a8bd4c6c15f3d4afd38)
@@ -76,7 +76,7 @@
 
 /** Return true if the caller (ipc_answer) should save
- * the old call contents and call answer_preprocess
- */
-static inline int answer_will_preprocess(call_t *call)
+ * the old call contents for answer_preprocess
+ */
+static inline int answer_need_old(call_t *call)
 {
 	if (IPC_GET_METHOD(call->data) == IPC_M_CONNECT_TO_ME)
@@ -91,4 +91,12 @@
 {
 	int phoneid;
+
+	if (IPC_GET_RETVAL(answer->data) == EHANGUP) {
+		/* Atomic operation */
+		answer->data.phone->callee = NULL;
+	}
+
+	if (!olddata)
+		return;
 
 	if (IPC_GET_METHOD(*olddata) == IPC_M_CONNECT_TO_ME) {
@@ -98,5 +106,5 @@
 			phone_dealloc(phoneid);
 		} else {
-			/* The connection was accepted */
+				/* The connection was accepted */
 			phone_connect(phoneid,&answer->sender->answerbox);
 		}
@@ -118,4 +126,7 @@
 static int process_answer(answerbox_t *box,call_t *call)
 {
+	if (IPC_GET_RETVAL(call->data) == EHANGUP && \
+	    call->flags & IPC_CALL_FORWARDED)
+		IPC_SET_RETVAL(call->data, EFORWARD);
 	return 0;
 }
@@ -276,4 +287,6 @@
 		return ENOENT;
 
+	call->flags |= IPC_CALL_FORWARDED;
+
 	GET_CHECK_PHONE(phone, phoneid, { 
 		IPC_SET_RETVAL(call->data, EFORWARD);
@@ -299,7 +312,5 @@
 	}
 
-	ipc_forward(call, phone, &TASK->answerbox);
-
-	return 0;
+	return ipc_forward(call, phone, &TASK->answerbox);
 }
 
@@ -310,5 +321,5 @@
 	call_t *call;
 	ipc_data_t saved_data;
-	int preprocess = 0;
+	int saveddata = 0;
 
 	call = get_call(callid);
@@ -316,7 +327,7 @@
 		return ENOENT;
 
-	if (answer_will_preprocess(call)) {
+	if (answer_need_old(call)) {
 		memcpy(&saved_data, &call->data, sizeof(call->data));
-		preprocess = 1;
+		saveddata = 1;
 	}
 
@@ -324,7 +335,5 @@
 	IPC_SET_ARG1(call->data, arg1);
 	IPC_SET_ARG2(call->data, arg2);
-
-	if (preprocess)
-		answer_preprocess(call, &saved_data);
+	answer_preprocess(call, saveddata ? &saved_data : NULL);
 
 	ipc_answer(&TASK->answerbox, call);
@@ -337,5 +346,5 @@
 	call_t *call;
 	ipc_data_t saved_data;
-	int preprocess = 0;
+	int saveddata = 0;
 
 	call = get_call(callid);
@@ -343,13 +352,12 @@
 		return ENOENT;
 
-	if (answer_will_preprocess(call)) {
+	if (answer_need_old(call)) {
 		memcpy(&saved_data, &call->data, sizeof(call->data));
-		preprocess = 1;
+		saveddata = 1;
 	}
 	copy_from_uspace(&call->data.args, &data->args, 
 			 sizeof(call->data.args));
 
-	if (preprocess)
-		answer_preprocess(call, &saved_data);
+	answer_preprocess(call, saveddata ? &saved_data : NULL);
 	
 	ipc_answer(&TASK->answerbox, call);
@@ -449,4 +457,6 @@
 restart:	
 	call = ipc_wait_for_call(&TASK->answerbox, flags);
+	if (!call)
+		return 0;
 
 	if (call->flags & IPC_CALL_ANSWERED) {
