Index: uspace/lib/c/include/bitops.h
===================================================================
--- uspace/lib/c/include/bitops.h	(revision eea65f4146296a8ed82333d611ca58de009377b0)
+++ uspace/lib/c/include/bitops.h	(revision 6896409cd9474f55ef576a06416616a7b3889494)
@@ -40,9 +40,9 @@
 /** Mask with bit @a n set. */
 #define BIT_V(type, n) \
-    ((type)1 << ((n) - 1))
+    ((type)1 << (n))
 
 /** Mask with rightmost @a n bits set. */
 #define BIT_RRANGE(type, n) \
-    (BIT_V(type, (n) + 1) - 1)
+    (BIT_V(type, (n)) - 1)
 
 /** Mask with bits @a hi .. @a lo set. @a hi >= @a lo. */
Index: uspace/srv/net/tl/tcp/conn.c
===================================================================
--- uspace/srv/net/tl/tcp/conn.c	(revision eea65f4146296a8ed82333d611ca58de009377b0)
+++ uspace/srv/net/tl/tcp/conn.c	(revision 6896409cd9474f55ef576a06416616a7b3889494)
@@ -190,13 +190,14 @@
 	case st_syn_received:
 	case st_established:
-		log_msg(LVL_DEBUG, "FIN sent -> Fin-Wait-1");
+		log_msg(LVL_DEBUG, "%s: FIN sent -> Fin-Wait-1", conn->name);
 		tcp_conn_state_set(conn, st_fin_wait_1);
 		break;
 	case st_close_wait:
-		log_msg(LVL_DEBUG, "FIN sent -> Last-Ack");
+		log_msg(LVL_DEBUG, "%s: FIN sent -> Last-Ack", conn->name);
 		tcp_conn_state_set(conn, st_last_ack);
 		break;
 	default:
-		log_msg(LVL_ERROR, "Connection state %d", conn->cstate);
+		log_msg(LVL_ERROR, "%s: Connection state %d", conn->name,
+		    conn->cstate);
 		assert(false);
 	}
@@ -367,5 +368,6 @@
 
 	if ((seg->ctrl & CTL_RST) != 0) {
-		log_msg(LVL_DEBUG, "Connection reset. -> Closed");
+		log_msg(LVL_DEBUG, "%s: Connection reset. -> Closed",
+		    conn->name);
 		/* XXX Signal user error */
 		tcp_conn_state_set(conn, st_closed);
@@ -408,9 +410,10 @@
 
 	if (seq_no_syn_acked(conn)) {
-		log_msg(LVL_DEBUG, " syn acked -> Established");
+		log_msg(LVL_DEBUG, "%s: syn acked -> Established", conn->name);
 		tcp_conn_state_set(conn, st_established);
 		tcp_tqueue_ctrl_seg(conn, CTL_ACK /* XXX */);
 	} else {
-		log_msg(LVL_DEBUG, " syn not acked -> Syn-Received");
+		log_msg(LVL_DEBUG, "%s: syn not acked -> Syn-Received",
+		    conn->name);
 		tcp_conn_state_set(conn, st_syn_received);
 		tcp_tqueue_ctrl_seg(conn, CTL_SYN | CTL_ACK /* XXX */);
@@ -527,5 +530,5 @@
 	}
 
-	log_msg(LVL_DEBUG, "SYN ACKed -> Established");
+	log_msg(LVL_DEBUG, "%s: SYN ACKed -> Established", conn->name);
 
 	tcp_conn_state_set(conn, st_established);
@@ -601,5 +604,5 @@
 
 	if (conn->fin_is_acked) {
-		log_msg(LVL_DEBUG, " FIN acked -> Fin-Wait-2");
+		log_msg(LVL_DEBUG, "%s: FIN acked -> Fin-Wait-2", conn->name);
 		tcp_conn_state_set(conn, st_fin_wait_2);
 	}
@@ -666,5 +669,5 @@
 
 	if (conn->fin_is_acked) {
-		log_msg(LVL_DEBUG, " FIN acked -> Closed");
+		log_msg(LVL_DEBUG, "%s: FIN acked -> Closed", conn->name);
 		tcp_conn_remove(conn);
 		tcp_conn_state_set(conn, st_closed);
@@ -815,4 +818,7 @@
 		tcp_conn_trim_seg_to_wnd(conn, seg);
 	} else {
+		log_msg(LVL_DEBUG, "%s: Nothing left in segment, dropping "
+		    "(xfer_size=%zu, SEG.LEN=%zu, seg->ctrl=%u)",
+		    conn->name, xfer_size, seg->len, (unsigned)seg->ctrl);
 		/* Nothing left in segment */
 		tcp_segment_delete(seg);
@@ -855,13 +861,16 @@
 		case st_syn_received:
 		case st_established:
-			log_msg(LVL_DEBUG, "FIN received -> Close-Wait");
+			log_msg(LVL_DEBUG, "%s: FIN received -> Close-Wait",
+			    conn->name);
 			tcp_conn_state_set(conn, st_close_wait);
 			break;
 		case st_fin_wait_1:
-			log_msg(LVL_DEBUG, "FIN received -> Closing");
+			log_msg(LVL_DEBUG, "%s: FIN received -> Closing",
+			    conn->name);
 			tcp_conn_state_set(conn, st_closing);
 			break;
 		case st_fin_wait_2:
-			log_msg(LVL_DEBUG, "FIN received -> Time-Wait");
+			log_msg(LVL_DEBUG, "%s: FIN received -> Time-Wait",
+			    conn->name);
 			tcp_conn_state_set(conn, st_time_wait);
 			/* Start the Time-Wait timer */
@@ -904,4 +913,5 @@
 {
 	log_msg(LVL_DEBUG, "tcp_conn_seg_process(%p, %p)", conn, seg);
+	tcp_segment_dump(seg);
 
 	/* Check whether segment is acceptable */
@@ -989,5 +999,5 @@
 
 	log_msg(LVL_DEBUG, "tw_timeout_func(%p)", conn);
-	log_msg(LVL_DEBUG, " TW Timeout -> Closed");
+	log_msg(LVL_DEBUG, "%s: TW Timeout -> Closed", conn->name);
 
 	tcp_conn_remove(conn);
Index: uspace/srv/net/tl/tcp/header.c
===================================================================
--- uspace/srv/net/tl/tcp/header.c	(revision eea65f4146296a8ed82333d611ca58de009377b0)
+++ uspace/srv/net/tl/tcp/header.c	(revision 6896409cd9474f55ef576a06416616a7b3889494)
@@ -35,4 +35,5 @@
  */
 
+#include <bitops.h>
 #include <byteorder.h>
 #include <errno.h>
@@ -41,4 +42,5 @@
 #include "header.h"
 #include "segment.h"
+#include "seq_no.h"
 #include "std.h"
 #include "tcp_type.h"
@@ -73,15 +75,15 @@
 	ctl = 0;
 
-	if ((doff_flags & DF_URG) != 0)
+	if ((doff_flags & BIT_V(uint16_t, DF_URG)) != 0)
 		ctl |= 0 /* XXX */;
-	if ((doff_flags & DF_ACK) != 0)
+	if ((doff_flags & BIT_V(uint16_t, DF_ACK)) != 0)
 		ctl |= CTL_ACK;
-	if ((doff_flags & DF_PSH) != 0)
+	if ((doff_flags & BIT_V(uint16_t, DF_PSH)) != 0)
 		ctl |= 0 /* XXX */;
-	if ((doff_flags & DF_RST) != 0)
+	if ((doff_flags & BIT_V(uint16_t, DF_RST)) != 0)
 		ctl |= CTL_RST;
-	if ((doff_flags & DF_SYN) != 0)
+	if ((doff_flags & BIT_V(uint16_t, DF_SYN)) != 0)
 		ctl |= CTL_SYN;
-	if ((doff_flags & DF_FIN) != 0)
+	if ((doff_flags & BIT_V(uint16_t, DF_FIN)) != 0)
 		ctl |= CTL_FIN;
 
@@ -97,11 +99,11 @@
 
 	if ((ctl & CTL_ACK) != 0)
-		doff_flags |= DF_ACK;
+		doff_flags |= BIT_V(uint16_t, DF_ACK);
 	if ((ctl & CTL_RST) != 0)
-		doff_flags |= DF_RST;
+		doff_flags |= BIT_V(uint16_t, DF_RST);
 	if ((ctl & CTL_SYN) != 0)
-		doff_flags |= DF_SYN;
+		doff_flags |= BIT_V(uint16_t, DF_SYN);
 	if ((ctl & CTL_FIN) != 0)
-		doff_flags |= DF_FIN;
+		doff_flags |= BIT_V(uint16_t, DF_FIN);
 
 	*rdoff_flags = doff_flags;
@@ -203,4 +205,5 @@
 
 	tcp_header_decode(pdu->header, nseg);
+	nseg->len += seq_no_control_len(nseg->ctrl);
 
 	hdr = (tcp_header_t *)pdu->header;
Index: uspace/srv/net/tl/tcp/rqueue.c
===================================================================
--- uspace/srv/net/tl/tcp/rqueue.c	(revision eea65f4146296a8ed82333d611ca58de009377b0)
+++ uspace/srv/net/tl/tcp/rqueue.c	(revision 6896409cd9474f55ef576a06416616a7b3889494)
@@ -114,4 +114,6 @@
 	log_msg(LVL_DEBUG, "tcp_rqueue_insert_seg()");
 
+	tcp_segment_dump(seg);
+
 	rqe = calloc(1, sizeof(tcp_rqueue_entry_t));
 	if (rqe == NULL) {
Index: uspace/srv/net/tl/tcp/segment.c
===================================================================
--- uspace/srv/net/tl/tcp/segment.c	(revision eea65f4146296a8ed82333d611ca58de009377b0)
+++ uspace/srv/net/tl/tcp/segment.c	(revision 6896409cd9474f55ef576a06416616a7b3889494)
@@ -35,4 +35,5 @@
  */
 
+#include <io/log.h>
 #include <mem.h>
 #include <stdlib.h>
@@ -235,4 +236,19 @@
 }
 
+/** Dump segment contents to log.
+ *
+ * @param seg	Segment
+ */
+void tcp_segment_dump(tcp_segment_t *seg)
+{
+	log_msg(LVL_DEBUG, "Segment dump:");
+	log_msg(LVL_DEBUG, " - ctrl = %u", (unsigned)seg->ctrl);
+	log_msg(LVL_DEBUG, " - seq = % " PRIu32, seg->seq);
+	log_msg(LVL_DEBUG, " - ack = % " PRIu32, seg->ack);
+	log_msg(LVL_DEBUG, " - len = % " PRIu32, seg->len);
+	log_msg(LVL_DEBUG, " - wnd = % " PRIu32, seg->wnd);
+	log_msg(LVL_DEBUG, " - up = % " PRIu32, seg->up);
+}
+
 /**
  * @}
Index: uspace/srv/net/tl/tcp/segment.h
===================================================================
--- uspace/srv/net/tl/tcp/segment.h	(revision eea65f4146296a8ed82333d611ca58de009377b0)
+++ uspace/srv/net/tl/tcp/segment.h	(revision 6896409cd9474f55ef576a06416616a7b3889494)
@@ -48,4 +48,6 @@
 extern void tcp_segment_text_copy(tcp_segment_t *, void *, size_t);
 extern size_t tcp_segment_text_size(tcp_segment_t *);
+extern void tcp_segment_dump(tcp_segment_t *);
+
 
 
Index: uspace/srv/net/tl/tcp/test.c
===================================================================
--- uspace/srv/net/tl/tcp/test.c	(revision eea65f4146296a8ed82333d611ca58de009377b0)
+++ uspace/srv/net/tl/tcp/test.c	(revision 6896409cd9474f55ef576a06416616a7b3889494)
@@ -66,5 +66,5 @@
 		tcp_uc_receive(conn, rcv_buf, RCV_BUF_SIZE, &rcvd, &xflags);
 		if (rcvd == 0) {
-			printf("End of data reached.\n");
+			printf("S: End of data reached.\n");
 			break;
 		}
Index: uspace/srv/net/tl/tcp/tqueue.c
===================================================================
--- uspace/srv/net/tl/tcp/tqueue.c	(revision eea65f4146296a8ed82333d611ca58de009377b0)
+++ uspace/srv/net/tl/tcp/tqueue.c	(revision 6896409cd9474f55ef576a06416616a7b3889494)
@@ -152,8 +152,9 @@
 	size_t data_size;
 	tcp_control_t ctrl;
+	bool send_fin;
 
 	tcp_segment_t *seg;
 
-	log_msg(LVL_DEBUG, "tcp_tqueue_new_data()");
+	log_msg(LVL_DEBUG, "%s: tcp_tqueue_new_data()", conn->name);
 
 	/* Number of free sequence numbers in send window */
@@ -162,6 +163,6 @@
 
 	xfer_seqlen = min(snd_buf_seqlen, avail_wnd);
-	log_msg(LVL_DEBUG, "snd_buf_seqlen = %zu, SND.WND = %zu, "
-	    "xfer_seqlen = %zu", snd_buf_seqlen, conn->snd_wnd,
+	log_msg(LVL_DEBUG, "%s: snd_buf_seqlen = %zu, SND.WND = %zu, "
+	    "xfer_seqlen = %zu", conn->name, snd_buf_seqlen, conn->snd_wnd,
 	    xfer_seqlen);
 
@@ -171,6 +172,9 @@
 	/* XXX Do not always send immediately */
 
-	data_size = xfer_seqlen - (conn->snd_buf_fin ? 1 : 0);
-	if (conn->snd_buf_fin && data_size + 1 == xfer_seqlen) {
+	send_fin = conn->snd_buf_fin && xfer_seqlen == snd_buf_seqlen;
+	data_size = xfer_seqlen - (send_fin ? 1 : 0);
+
+	if (send_fin) {
+		log_msg(LVL_DEBUG, "%s: Sending out FIN.", conn->name);
 		/* We are sending out FIN */
 		ctrl = CTL_FIN;
@@ -190,5 +194,7 @@
 	    conn->snd_buf_used - data_size);
 	conn->snd_buf_used -= data_size;
-	conn->snd_buf_fin = false;
+
+	if (send_fin)
+		conn->snd_buf_fin = false;
 
 	tcp_tqueue_seg(conn, seg);
@@ -261,4 +267,6 @@
 	log_msg(LVL_DEBUG, "SEG.SEQ=%" PRIu32 ", SEG.WND=%" PRIu32,
 	    seg->seq, seg->wnd);
+
+	tcp_segment_dump(seg);
 /*
 	tcp_pdu_prepare(conn, seg, &data, &len);
