Index: uspace/srv/net/tl/tcp/tcp.c
===================================================================
--- uspace/srv/net/tl/tcp/tcp.c	(revision 092e4f1fe1d53967d7144a0646a2cb1aad934d00)
+++ uspace/srv/net/tl/tcp/tcp.c	(revision b35fea35ac7e82f4ee646caa0e340f694339fb64)
@@ -205,4 +205,5 @@
 static int tcp_queue_received_packet(socket_core_t *, tcp_socket_data_t *,
     packet_t *, int, size_t);
+static void tcp_queue_received_end_of_data(socket_core_t *socket);
 
 static int tcp_received_msg(device_id_t, packet_t *, services_t, services_t);
@@ -504,4 +505,5 @@
 	size_t offset;
 	uint32_t new_sequence_number;
+	bool forced_ack;
 	int rc;
 
@@ -512,9 +514,13 @@
 	assert(packet);
 
+	forced_ack = false;
+
 	new_sequence_number = ntohl(header->sequence_number);
 	old_incoming = socket_data->next_incoming;
 
-	if (header->finalize)
-		socket_data->fin_incoming = new_sequence_number;
+	if (header->finalize) {
+		socket_data->fin_incoming = new_sequence_number +
+		    total_length - TCP_HEADER_LENGTH(header);
+	}
 
 	/* Trim begining if containing expected data */
@@ -760,9 +766,16 @@
 		/* Release duplicite or restricted */
 		pq_release_remote(tcp_globals.net_phone, packet_get_id(packet));
-	}
-
-	/* Change state according to the acknowledging incoming fin */
-	if (IS_IN_INTERVAL_OVERFLOW(old_incoming, socket_data->fin_incoming,
-	    socket_data->next_incoming)) {
+		forced_ack = true;
+	}
+
+	if (header->finalize)
+		socket_data->next_incoming += 1;
+
+	/* If next in sequence is an incoming FIN */
+	if (socket_data->next_incoming == socket_data->fin_incoming) {
+		/* Advance sequence number */
+		socket_data->next_incoming += 1;
+
+		/* Handle FIN */
 		switch (socket_data->state) {
 		case TCP_SOCKET_FIN_WAIT_1:
@@ -771,5 +784,9 @@
 			socket_data->state = TCP_SOCKET_CLOSING;
 			break;
-		/*case TCP_ESTABLISHED:*/
+		case TCP_SOCKET_ESTABLISHED:
+			/* Queue end-of-data marker on the socket. */
+			tcp_queue_received_end_of_data(socket);
+			socket_data->state = TCP_SOCKET_CLOSE_WAIT;
+			break;
 		default:
 			socket_data->state = TCP_SOCKET_CLOSE_WAIT;
@@ -779,5 +796,5 @@
 
 	packet = tcp_get_packets_to_send(socket, socket_data);
-	if (!packet) {
+	if (!packet && (socket_data->next_incoming != old_incoming || forced_ack)) {
 		/* Create the notification packet */
 		rc = tcp_create_notification_packet(&packet, socket,
@@ -835,4 +852,22 @@
 
 	return EOK;
+}
+
+/** Queue end-of-data marker on the socket.
+ *
+ * Next element in the sequence space is FIN. Queue end-of-data marker
+ * on the socket.
+ *
+ * @param socket	Socket
+ */
+static void tcp_queue_received_end_of_data(socket_core_t *socket)
+{
+	assert(socket != NULL);
+
+	/* Notify the destination socket */
+	async_msg_5(socket->phone, NET_SOCKET_RECEIVED,
+	    (sysarg_t) socket->socket_id,
+	    0, 0, 0,
+	    (sysarg_t) 0 /* 0 fragments == no more data */);
 }
 
