Index: uspace/srv/net/udp/sock.c
===================================================================
--- uspace/srv/net/udp/sock.c	(revision 1038a9ca3ddebaa67ddd98d4752bccba035adcbf)
+++ uspace/srv/net/udp/sock.c	(revision 32d19f757b014501ef88e20a2fa7d354e4bc0b39)
@@ -51,6 +51,4 @@
 #include "ucall.h"
 
-#define FRAGMENT_SIZE 1024
-
 /** Free ports pool start. */
 #define UDP_FREE_PORTS_START		1025
@@ -63,4 +61,5 @@
 
 static void udp_sock_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg);
+static int udp_sock_recv_fibril(void *arg);
 
 int udp_sock_init(void)
@@ -82,6 +81,7 @@
 
 	socket = (udp_sockdata_t *)sock_core->specific_data;
-	assert(socket->assoc != NULL);
-	udp_uc_destroy(socket->assoc);
+	(void)socket;
+
+	/* XXX We need to force the receive fibril to quit */
 }
 
@@ -91,5 +91,5 @@
 	async_exch_t *exch = async_exchange_begin(sock_core->sess);
 	async_msg_5(exch, NET_SOCKET_RECEIVED, (sysarg_t)sock_core->socket_id,
-	    FRAGMENT_SIZE, 0, 0, 1);
+	    UDP_FRAGMENT_SIZE, 0, 0, 1);
 	async_exchange_end(exch);
 }
@@ -113,6 +113,28 @@
 	sock->client = client;
 
+	sock->recv_buffer_used = 0;
+	sock->recv_error = UDP_EOK;
+	fibril_mutex_initialize(&sock->recv_buffer_lock);
+	fibril_condvar_initialize(&sock->recv_buffer_cv);
+
 	rc = udp_uc_create(&sock->assoc);
 	if (rc != EOK) {
+		free(sock);
+		async_answer_0(callid, rc);
+		return;
+	}
+
+	sock->recv_fibril = fibril_create(udp_sock_recv_fibril, sock);
+	if (sock->recv_fibril == 0) {
+		udp_uc_destroy(sock->assoc);
+		free(sock);
+		async_answer_0(callid, ENOMEM);
+		return;
+	}
+
+	sock_id = SOCKET_GET_SOCKET_ID(call);
+	rc = socket_create(&client->sockets, client->sess, sock, &sock_id);
+	if (rc != EOK) {
+		fibril_destroy(sock->recv_fibril);
 		udp_uc_destroy(sock->assoc);
 		free(sock);
@@ -121,10 +143,5 @@
 	}
 
-	sock_id = SOCKET_GET_SOCKET_ID(call);
-	rc = socket_create(&client->sockets, client->sess, sock, &sock_id);
-	if (rc != EOK) {
-		async_answer_0(callid, rc);
-		return;
-	}
+	fibril_add_ready(sock->recv_fibril);
 
 	sock_core = socket_cores_find(&client->sockets, sock_id);
@@ -134,5 +151,5 @@
 	SOCKET_SET_SOCKET_ID(answer, sock_id);
 
-	SOCKET_SET_DATA_FRAGMENT_SIZE(answer, FRAGMENT_SIZE);
+	SOCKET_SET_DATA_FRAGMENT_SIZE(answer, UDP_FRAGMENT_SIZE);
 	SOCKET_SET_HEADER_SIZE(answer, sizeof(udp_header_t));
 	async_answer_3(callid, EOK, IPC_GET_ARG1(answer),
@@ -205,6 +222,4 @@
 	}
 
-	udp_sock_notify_data(sock_core);
-
 	log_msg(LVL_DEBUG, " - success");
 	async_answer_0(callid, rc);
@@ -245,5 +260,5 @@
 	ipc_callid_t wcallid;
 	size_t length;
-	uint8_t buffer[FRAGMENT_SIZE];
+	uint8_t buffer[UDP_FRAGMENT_SIZE];
 	udp_error_t urc;
 	int rc;
@@ -292,6 +307,4 @@
 			goto out;
 		}
-
-		udp_sock_notify_data(sock_core);
 	}
 
@@ -330,6 +343,6 @@
 		}
 
-		if (length > FRAGMENT_SIZE)
-			length = FRAGMENT_SIZE;
+		if (length > UDP_FRAGMENT_SIZE)
+			length = UDP_FRAGMENT_SIZE;
 
 		rc = async_data_write_finalize(wcallid, buffer, length);
@@ -367,5 +380,5 @@
 	
 	IPC_SET_ARG1(answer, 0);
-	SOCKET_SET_DATA_FRAGMENT_SIZE(answer, FRAGMENT_SIZE);
+	SOCKET_SET_DATA_FRAGMENT_SIZE(answer, UDP_FRAGMENT_SIZE);
 	async_answer_2(callid, EOK, IPC_GET_ARG1(answer),
 	    IPC_GET_ARG2(answer));
@@ -386,10 +399,8 @@
 	ipc_call_t answer;
 	ipc_callid_t rcallid;
-	uint8_t buffer[FRAGMENT_SIZE];
 	size_t data_len;
-	xflags_t xflags;
 	udp_error_t urc;
+	udp_sock_t rsock;
 	struct sockaddr_in addr;
-	udp_sock_t rsock;
 	int rc;
 
@@ -416,7 +427,19 @@
 	(void)flags;
 
-	urc = udp_uc_receive(socket->assoc, buffer, FRAGMENT_SIZE, &data_len,
-	    &xflags, &rsock);
-	log_msg(LVL_DEBUG, "**** udp_uc_receive done, data_len=%zu", data_len);
+	log_msg(LVL_DEBUG, "udp_sock_recvfrom(): lock recv_buffer lock");
+	fibril_mutex_lock(&socket->recv_buffer_lock);
+	while (socket->recv_buffer_used == 0 && socket->recv_error == UDP_EOK) {
+		log_msg(LVL_DEBUG, "udp_sock_recvfrom(): wait for cv");
+		fibril_condvar_wait(&socket->recv_buffer_cv,
+		    &socket->recv_buffer_lock);
+	}
+
+	log_msg(LVL_DEBUG, "Got data in sock recv_buffer");
+
+	rsock = socket->recv_fsock;
+	data_len = socket->recv_buffer_used;
+	urc = socket->recv_error;
+
+	log_msg(LVL_DEBUG, "**** recv data_len=%zu", data_len);
 
 	switch (urc) {
@@ -437,4 +460,5 @@
 	log_msg(LVL_DEBUG, "**** udp_uc_receive -> %d", rc);
 	if (rc != EOK) {
+		fibril_mutex_unlock(&socket->recv_buffer_lock);
 		fibril_mutex_unlock(&socket->lock);
 		async_answer_0(callid, rc);
@@ -450,4 +474,5 @@
 		log_msg(LVL_DEBUG, "addr read receive");
 		if (!async_data_read_receive(&rcallid, &addr_length)) {
+			fibril_mutex_unlock(&socket->recv_buffer_lock);
 			fibril_mutex_unlock(&socket->lock);
 			async_answer_0(callid, EINVAL);
@@ -461,4 +486,5 @@
 		rc = async_data_read_finalize(rcallid, &addr, addr_length);
 		if (rc != EOK) {
+			fibril_mutex_unlock(&socket->recv_buffer_lock);
 			fibril_mutex_unlock(&socket->lock);
 			async_answer_0(callid, EINVAL);
@@ -469,4 +495,5 @@
 	log_msg(LVL_DEBUG, "data read receive");
 	if (!async_data_read_receive(&rcallid, &length)) {
+		fibril_mutex_unlock(&socket->recv_buffer_lock);
 		fibril_mutex_unlock(&socket->lock);
 		async_answer_0(callid, EINVAL);
@@ -478,5 +505,5 @@
 
 	log_msg(LVL_DEBUG, "data read finalize");
-	rc = async_data_read_finalize(rcallid, buffer, length);
+	rc = async_data_read_finalize(rcallid, socket->recv_buffer, length);
 
 	if (length < data_len && rc == EOK)
@@ -489,7 +516,9 @@
 	async_answer_3(callid, EOK, IPC_GET_ARG1(answer),
 	    IPC_GET_ARG2(answer), IPC_GET_ARG3(answer));
-	
-	/* Push one fragment notification to client's queue */
-	udp_sock_notify_data(sock_core);
+
+	socket->recv_buffer_used = 0;
+
+	fibril_condvar_broadcast(&socket->recv_buffer_cv);
+	fibril_mutex_unlock(&socket->recv_buffer_lock);
 	fibril_mutex_unlock(&socket->lock);
 }
@@ -538,4 +567,46 @@
 }
 
+static int udp_sock_recv_fibril(void *arg)
+{
+	udp_sockdata_t *sock = (udp_sockdata_t *)arg;
+	udp_error_t urc;
+	xflags_t xflags;
+	size_t rcvd;
+
+	log_msg(LVL_DEBUG, "udp_sock_recv_fibril()");
+
+	while (true) {
+		log_msg(LVL_DEBUG, "[] wait for rcv buffer empty()");
+		fibril_mutex_lock(&sock->recv_buffer_lock);
+		while (sock->recv_buffer_used != 0) {
+			fibril_condvar_wait(&sock->recv_buffer_cv,
+			    &sock->recv_buffer_lock);
+		}
+
+		log_msg(LVL_DEBUG, "[] call udp_uc_receive()");
+		urc = udp_uc_receive(sock->assoc, sock->recv_buffer,
+		    UDP_FRAGMENT_SIZE, &rcvd, &xflags, &sock->recv_fsock);
+		sock->recv_error = urc;
+
+		udp_sock_notify_data(sock->sock_core);
+
+		if (urc != UDP_EOK) {
+			fibril_condvar_broadcast(&sock->recv_buffer_cv);
+			fibril_mutex_unlock(&sock->recv_buffer_lock);
+			break;
+		}
+
+		log_msg(LVL_DEBUG, "[] got data - broadcast recv_buffer_cv");
+
+		sock->recv_buffer_used = rcvd;
+		fibril_mutex_unlock(&sock->recv_buffer_lock);
+		fibril_condvar_broadcast(&sock->recv_buffer_cv);
+	}
+
+	udp_uc_destroy(sock->assoc);
+
+	return 0;
+}
+
 static void udp_sock_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
 {
