Index: uspace/srv/net/tcp/Makefile
===================================================================
--- uspace/srv/net/tcp/Makefile	(revision 8ebc5b8afff1eee31b5dccfd149defa4473bba75)
+++ uspace/srv/net/tcp/Makefile	(revision e73dbc1172df2b8d470314ee1bd2a68d69c55b5f)
@@ -37,5 +37,5 @@
 BINARY = tcp
 
-SOURCES = \
+SOURCES_COMMON = \
 	conn.c \
 	iqueue.c \
@@ -44,17 +44,20 @@
 	rqueue.c \
 	segment.c \
-	service.c \
 	seq_no.c \
-	tcp.c \
 	test.c \
 	tqueue.c \
 	ucall.c
 
+SOURCES = \
+	$(SOURCES_COMMON) \
+	service.c \
+	tcp.c
+
 TEST_SOURCES = \
-	pdu.c \
-	segment.c \
-	seq_no.c \
+	$(SOURCES_COMMON) \
 	test/main.c \
-	test/pdu.c
+	test/pdu.c \
+	test/segment.c \
+	test/seq_no.c
 
 include $(USPACE_PREFIX)/Makefile.common
Index: uspace/srv/net/tcp/seq_no.c
===================================================================
--- uspace/srv/net/tcp/seq_no.c	(revision 8ebc5b8afff1eee31b5dccfd149defa4473bba75)
+++ uspace/srv/net/tcp/seq_no.c	(revision e73dbc1172df2b8d470314ee1bd2a68d69c55b5f)
@@ -134,5 +134,12 @@
 }
 
-/** Determine whether segment is fully acked */
+/** Determine whether segment is fully acked.
+ *
+ * @param conn Connection
+ * @param seg  Segment
+ * @param ack  Last received ACK (i.e. SND.UNA)
+ *
+ * @return @c true if segment is fully acked, @c false otherwise
+ */
 bool seq_no_segment_acked(tcp_conn_t *conn, tcp_segment_t *seg, uint32_t ack)
 {
@@ -141,5 +148,9 @@
 }
 
-/** Determine whether initial SYN is acked */
+/** Determine whether initial SYN is acked.
+ *
+ * @param conn Connection
+ * @return @c true if initial SYN is acked, @c false otherwise
+ */
 bool seq_no_syn_acked(tcp_conn_t *conn)
 {
@@ -147,14 +158,30 @@
 }
 
-/** Determine whether segment overlaps the receive window */
+/** Determine whether segment overlaps the receive window.
+ *
+ * @param conn Connection
+ * @param seg  Segment
+ * @return @c true if segment overlaps the receive window, @c false otherwise
+ */
 bool seq_no_segment_acceptable(tcp_conn_t *conn, tcp_segment_t *seg)
 {
 	bool b_in, e_in;
-
+	bool wb_in, we_in;
+
+	/* Beginning of segment is inside window */
 	b_in = seq_no_le_lt(conn->rcv_nxt, seg->seq, conn->rcv_nxt
 	    + conn->rcv_wnd);
 
+	/* End of segment is inside window */
 	e_in = seq_no_le_lt(conn->rcv_nxt, seg->seq + seg->len - 1,
 	    conn->rcv_nxt + conn->rcv_wnd);
+
+	/* Beginning of window is inside segment */
+	wb_in = seq_no_le_lt(seg->seq, conn->rcv_nxt,
+	    seg->seq + seg->len);
+
+	/* End of window is inside segment */
+	we_in = seq_no_le_lt(seg->seq, conn->rcv_nxt + conn->rcv_wnd - 1,
+	    seg->seq + seg->len);
 
 	if (seg->len == 0 && conn->rcv_wnd == 0) {
@@ -165,9 +192,13 @@
 		return false;
 	} else {
-		return b_in || e_in;
-	}
-}
-
-/** Determine size that control bits occupy in sequence space. */
+		return b_in || e_in || wb_in || we_in;
+	}
+}
+
+/** Determine size that control bits occupy in sequence space.
+ *
+ * @param ctrl Control bits combination
+ * @return Number of sequence space units occupied
+ */
 uint32_t seq_no_control_len(tcp_control_t ctrl)
 {
@@ -183,5 +214,11 @@
 }
 
-/** Calculate the amount of trim needed to fit segment in receive window. */
+/** Calculate the amount of trim needed to fit segment in receive window.
+ *
+ * @param conn  Connection
+ * @param seg   Segment
+ * @param left  Place to store number of units to trim at the beginning
+ * @param right Place to store number of units to trim at the end
+ */
 void seq_no_seg_trim_calc(tcp_conn_t *conn, tcp_segment_t *seg,
     uint32_t *left, uint32_t *right)
Index: uspace/srv/net/tcp/test/main.c
===================================================================
--- uspace/srv/net/tcp/test/main.c	(revision 8ebc5b8afff1eee31b5dccfd149defa4473bba75)
+++ uspace/srv/net/tcp/test/main.c	(revision e73dbc1172df2b8d470314ee1bd2a68d69c55b5f)
@@ -27,9 +27,37 @@
  */
 
+#include <mem.h>
 #include <pcut/pcut.h>
+
+#include "main.h"
+#include "../segment.h"
+#include "../tcp_type.h"
+
+/** Verify that two segments have the same content */
+void test_seg_same(tcp_segment_t *a, tcp_segment_t *b)
+{
+	PCUT_ASSERT_INT_EQUALS(a->ctrl, b->ctrl);
+	PCUT_ASSERT_INT_EQUALS(a->seq, b->seq);
+	PCUT_ASSERT_INT_EQUALS(a->ack, b->ack);
+	PCUT_ASSERT_INT_EQUALS(a->len, b->len);
+	PCUT_ASSERT_INT_EQUALS(a->wnd, b->wnd);
+	PCUT_ASSERT_INT_EQUALS(a->up, b->up);
+	PCUT_ASSERT_INT_EQUALS(tcp_segment_text_size(a),
+	    tcp_segment_text_size(b));
+	if (tcp_segment_text_size(a) != 0)
+		PCUT_ASSERT_NOT_NULL(a->data);
+	if (tcp_segment_text_size(b) != 0)
+		PCUT_ASSERT_NOT_NULL(b->data);
+	if (tcp_segment_text_size(a) != 0) {
+		PCUT_ASSERT_INT_EQUALS(0, memcmp(a->data, b->data,
+		    tcp_segment_text_size(a)));
+	}
+}
 
 PCUT_INIT
 
 PCUT_IMPORT(pdu);
+PCUT_IMPORT(segment);
+PCUT_IMPORT(seq_no);
 
 PCUT_MAIN()
Index: uspace/srv/net/tcp/test/main.h
===================================================================
--- uspace/srv/net/tcp/test/main.h	(revision e73dbc1172df2b8d470314ee1bd2a68d69c55b5f)
+++ uspace/srv/net/tcp/test/main.h	(revision e73dbc1172df2b8d470314ee1bd2a68d69c55b5f)
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2017 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup tcp
+ * @{
+ */
+/** @file
+ */
+
+#ifndef TEST_MAIN_H
+#define TEST_MAIN_H
+
+#include "../tcp_type.h"
+
+extern void test_seg_same(tcp_segment_t *, tcp_segment_t *);
+
+#endif
+
+/** @}
+ */
Index: uspace/srv/net/tcp/test/pdu.c
===================================================================
--- uspace/srv/net/tcp/test/pdu.c	(revision 8ebc5b8afff1eee31b5dccfd149defa4473bba75)
+++ uspace/srv/net/tcp/test/pdu.c	(revision e73dbc1172df2b8d470314ee1bd2a68d69c55b5f)
@@ -29,31 +29,11 @@
 #include <errno.h>
 #include <inet/endpoint.h>
+#include <mem.h>
 #include <pcut/pcut.h>
-#include <str.h>
 #include <stdlib.h>
 
+#include "main.h"
 #include "../pdu.h"
 #include "../segment.h"
-
-/** Verify that two segments have the same content */
-static void pdu_seg_cmp(tcp_segment_t *a, tcp_segment_t *b)
-{
-	PCUT_ASSERT_INT_EQUALS(a->ctrl, b->ctrl);
-	PCUT_ASSERT_INT_EQUALS(a->seq, b->seq);
-	PCUT_ASSERT_INT_EQUALS(a->ack, b->ack);
-	PCUT_ASSERT_INT_EQUALS(a->len, b->len);
-	PCUT_ASSERT_INT_EQUALS(a->wnd, b->wnd);
-	PCUT_ASSERT_INT_EQUALS(a->up, b->up);
-	PCUT_ASSERT_INT_EQUALS(tcp_segment_text_size(a),
-	    tcp_segment_text_size(b));
-	if (tcp_segment_text_size(a) != 0)
-		PCUT_ASSERT_NOT_NULL(a->data);
-	if (tcp_segment_text_size(b) != 0)
-		PCUT_ASSERT_NOT_NULL(b->data);
-	if (tcp_segment_text_size(a) != 0) {
-		PCUT_ASSERT_INT_EQUALS(0, memcmp(a->data, b->data,
-		    tcp_segment_text_size(a)));
-	}
-}
 
 PCUT_INIT
@@ -86,5 +66,5 @@
 	PCUT_ASSERT_INT_EQUALS(EOK, rc);
 
-	pdu_seg_cmp(seg, dseg);
+	test_seg_same(seg, dseg);
 	tcp_segment_delete(seg);
 }
@@ -124,5 +104,5 @@
 	PCUT_ASSERT_INT_EQUALS(EOK, rc);
 
-	pdu_seg_cmp(seg, dseg);
+	test_seg_same(seg, dseg);
 	tcp_segment_delete(seg);
 	free(data);
Index: uspace/srv/net/tcp/test/segment.c
===================================================================
--- uspace/srv/net/tcp/test/segment.c	(revision e73dbc1172df2b8d470314ee1bd2a68d69c55b5f)
+++ uspace/srv/net/tcp/test/segment.c	(revision e73dbc1172df2b8d470314ee1bd2a68d69c55b5f)
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 2017 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <pcut/pcut.h>
+
+#include "main.h"
+#include "../segment.h"
+
+PCUT_INIT
+
+PCUT_TEST_SUITE(segment);
+
+/** Test create/destroy control segment */
+PCUT_TEST(ctrl_seg_mkdel)
+{
+	tcp_segment_t *seg;
+
+	seg = tcp_segment_make_ctrl(CTL_SYN);
+	PCUT_ASSERT_NOT_NULL(seg);
+	tcp_segment_delete(seg);
+}
+
+/** Test create/destroy data segment */
+PCUT_TEST(data_seg_mkdel)
+{
+	tcp_segment_t *seg;
+	uint8_t *data;
+	size_t i, dsize;
+
+	dsize = 15;
+	data = malloc(dsize);
+	PCUT_ASSERT_NOT_NULL(data);
+
+	for (i = 0; i < dsize; i++)
+		data[i] = (uint8_t) i;
+
+	seg = tcp_segment_make_data(CTL_SYN, data, dsize);
+	PCUT_ASSERT_NOT_NULL(seg);
+
+	tcp_segment_delete(seg);
+	free(data);
+}
+
+/** Test create/duplicate/destroy control segment */
+PCUT_TEST(ctrl_seg_dup)
+{
+	tcp_segment_t *seg, *dup;
+
+	seg = tcp_segment_make_ctrl(CTL_SYN);
+	PCUT_ASSERT_NOT_NULL(seg);
+
+	seg->seq = 20;
+	seg->ack = 19;
+	seg->wnd = 18;
+	seg->up = 17;
+
+	dup = tcp_segment_dup(seg);
+	test_seg_same(seg, dup);
+
+	tcp_segment_delete(seg);
+	tcp_segment_delete(dup);
+}
+
+/** Test create/duplicate/destroy data segment */
+PCUT_TEST(data_seg_dup)
+{
+	tcp_segment_t *seg, *dup;
+	uint8_t *data;
+	size_t i, dsize;
+
+	dsize = 15;
+	data = malloc(dsize);
+	PCUT_ASSERT_NOT_NULL(data);
+
+	for (i = 0; i < dsize; i++)
+		data[i] = (uint8_t) i;
+
+	seg = tcp_segment_make_data(CTL_SYN, data, dsize);
+	PCUT_ASSERT_NOT_NULL(seg);
+
+	seg->seq = 20;
+	seg->ack = 19;
+	seg->wnd = 18;
+	seg->up = 17;
+
+	dup = tcp_segment_dup(seg);
+	test_seg_same(seg, dup);
+
+	tcp_segment_delete(seg);
+	tcp_segment_delete(dup);
+	free(data);
+}
+
+/** Test reset segment for segment with ACK not set */
+PCUT_TEST(noack_seg_rst)
+{
+	tcp_segment_t *seg, *rst;
+
+	seg = tcp_segment_make_ctrl(CTL_SYN);
+	PCUT_ASSERT_NOT_NULL(seg);
+
+	seg->seq = 20;
+	seg->ack = 19;
+	seg->wnd = 18;
+	seg->up = 17;
+
+	rst = tcp_segment_make_rst(seg);
+	PCUT_ASSERT_NOT_NULL(seg);
+
+	tcp_segment_delete(seg);
+	tcp_segment_delete(rst);
+}
+
+/** Test reset segment for segment with ACK set */
+PCUT_TEST(ack_seg_rst)
+{
+	tcp_segment_t *seg, *rst;
+
+	seg = tcp_segment_make_ctrl(CTL_SYN | CTL_ACK);
+	PCUT_ASSERT_NOT_NULL(seg);
+
+	seg->seq = 20;
+	seg->ack = 19;
+	seg->wnd = 18;
+	seg->up = 17;
+
+	rst = tcp_segment_make_rst(seg);
+	PCUT_ASSERT_NOT_NULL(seg);
+
+	tcp_segment_delete(seg);
+	tcp_segment_delete(rst);
+}
+
+/** Test copying out data segment text */
+PCUT_TEST(data_seg_text)
+{
+	tcp_segment_t *seg;
+	uint8_t *data;
+	uint8_t *cdata;
+	size_t i, dsize;
+
+	dsize = 15;
+	data = malloc(dsize);
+	PCUT_ASSERT_NOT_NULL(data);
+	cdata = malloc(dsize);
+	PCUT_ASSERT_NOT_NULL(cdata);
+
+	for (i = 0; i < dsize; i++)
+		data[i] = (uint8_t) i;
+
+	seg = tcp_segment_make_data(CTL_SYN, data, dsize);
+	PCUT_ASSERT_NOT_NULL(seg);
+
+	PCUT_ASSERT_INT_EQUALS(dsize, tcp_segment_text_size(seg));
+	tcp_segment_text_copy(seg, cdata, dsize);
+
+	for (i = 0; i < dsize; i++)
+		PCUT_ASSERT_INT_EQUALS(data[i], cdata[i]);
+
+	tcp_segment_delete(seg);
+	free(data);
+	free(cdata);
+}
+
+/** Test trimming data segment text */
+PCUT_TEST(data_seg_trim)
+{
+	tcp_segment_t *seg;
+	uint8_t *data;
+	uint8_t *cdata;
+	size_t i, dsize;
+
+	dsize = 15;
+	data = malloc(dsize);
+	PCUT_ASSERT_NOT_NULL(data);
+	cdata = malloc(dsize);
+	PCUT_ASSERT_NOT_NULL(cdata);
+
+	for (i = 0; i < dsize; i++)
+		data[i] = (uint8_t) i;
+
+	seg = tcp_segment_make_data(CTL_SYN | CTL_FIN, data, dsize);
+	PCUT_ASSERT_NOT_NULL(seg);
+
+	PCUT_ASSERT_INT_EQUALS(dsize, tcp_segment_text_size(seg));
+	tcp_segment_text_copy(seg, cdata, dsize);
+
+	for (i = 0; i < dsize; i++)
+		PCUT_ASSERT_INT_EQUALS(data[i], cdata[i]);
+
+	PCUT_ASSERT_INT_EQUALS(CTL_SYN | CTL_FIN, seg->ctrl);
+
+	tcp_segment_trim(seg, 1, 0);
+	PCUT_ASSERT_INT_EQUALS(CTL_FIN, seg->ctrl);
+	PCUT_ASSERT_INT_EQUALS(dsize, tcp_segment_text_size(seg));
+
+	tcp_segment_trim(seg, 0, 1);
+	PCUT_ASSERT_INT_EQUALS(0, seg->ctrl);
+	PCUT_ASSERT_INT_EQUALS(dsize, tcp_segment_text_size(seg));
+
+	tcp_segment_trim(seg, 1, 0);
+	PCUT_ASSERT_INT_EQUALS(0, seg->ctrl);
+	PCUT_ASSERT_INT_EQUALS(dsize - 1, tcp_segment_text_size(seg));
+
+	tcp_segment_text_copy(seg, cdata, dsize - 1);
+	for (i = 0; i < dsize - 1; i++)
+		PCUT_ASSERT_INT_EQUALS(data[i + 1], cdata[i]);
+
+	tcp_segment_trim(seg, 0, 1);
+	PCUT_ASSERT_INT_EQUALS(0, seg->ctrl);
+	PCUT_ASSERT_INT_EQUALS(dsize - 2, tcp_segment_text_size(seg));
+
+	tcp_segment_text_copy(seg, cdata, dsize - 2);
+	for (i = 0; i < dsize - 2; i++)
+		PCUT_ASSERT_INT_EQUALS(data[i + 1], cdata[i]);
+
+	tcp_segment_delete(seg);
+	free(data);
+	free(cdata);
+}
+
+PCUT_EXPORT(segment);
Index: uspace/srv/net/tcp/test/seq_no.c
===================================================================
--- uspace/srv/net/tcp/test/seq_no.c	(revision e73dbc1172df2b8d470314ee1bd2a68d69c55b5f)
+++ uspace/srv/net/tcp/test/seq_no.c	(revision e73dbc1172df2b8d470314ee1bd2a68d69c55b5f)
@@ -0,0 +1,502 @@
+/*
+ * Copyright (c) 2017 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <inet/endpoint.h>
+#include <pcut/pcut.h>
+
+#include "../conn.h"
+#include "../segment.h"
+#include "../seq_no.h"
+
+PCUT_INIT
+
+PCUT_TEST_SUITE(seq_no);
+
+/** Test seq_no_ack_acceptable() */
+PCUT_TEST(ack_acceptable)
+{
+	tcp_conn_t *conn;
+	inet_ep2_t epp;
+
+	inet_ep2_init(&epp);
+	conn = tcp_conn_new(&epp);
+	PCUT_ASSERT_NOT_NULL(conn);
+
+	/* ACK is acceptable iff SND.UNA < SEG.ACK <= SND.NXT */
+
+	conn->snd_una = 10;
+	conn->snd_nxt = 30;
+
+	PCUT_ASSERT_FALSE(seq_no_ack_acceptable(conn, 9));
+	PCUT_ASSERT_FALSE(seq_no_ack_acceptable(conn, 10));
+	PCUT_ASSERT_TRUE(seq_no_ack_acceptable(conn, 11));
+	PCUT_ASSERT_TRUE(seq_no_ack_acceptable(conn, 29));
+	PCUT_ASSERT_TRUE(seq_no_ack_acceptable(conn, 30));
+	PCUT_ASSERT_FALSE(seq_no_ack_acceptable(conn, 31));
+
+	/* We also test whether seq_no_lt_le() wraps around properly */
+
+	conn->snd_una = 30;
+	conn->snd_nxt = 10;
+
+	PCUT_ASSERT_FALSE(seq_no_ack_acceptable(conn, 29));
+	PCUT_ASSERT_FALSE(seq_no_ack_acceptable(conn, 30));
+	PCUT_ASSERT_TRUE(seq_no_ack_acceptable(conn, 31));
+	PCUT_ASSERT_TRUE(seq_no_ack_acceptable(conn, 9));
+	PCUT_ASSERT_TRUE(seq_no_ack_acceptable(conn, 10));
+	PCUT_ASSERT_FALSE(seq_no_ack_acceptable(conn, 11));
+
+	tcp_conn_delete(conn);
+}
+
+/** Test seq_no_ack_duplicate() */
+PCUT_TEST(ack_duplicate)
+{
+	tcp_conn_t *conn;
+	inet_ep2_t epp;
+
+	inet_ep2_init(&epp);
+	conn = tcp_conn_new(&epp);
+	PCUT_ASSERT_NOT_NULL(conn);
+
+	/* ACK is duplicate iff SEG.ACK <= SND.UNA */
+
+	conn->snd_una = 10;
+
+	PCUT_ASSERT_TRUE(seq_no_ack_duplicate(conn, 9));
+	PCUT_ASSERT_TRUE(seq_no_ack_duplicate(conn, 10));
+	PCUT_ASSERT_FALSE(seq_no_ack_duplicate(conn, 11));
+
+	conn->snd_una = (uint32_t) -10;
+
+	PCUT_ASSERT_TRUE(seq_no_ack_duplicate(conn, (uint32_t) -11));
+	PCUT_ASSERT_TRUE(seq_no_ack_duplicate(conn, (uint32_t) -10));
+	PCUT_ASSERT_FALSE(seq_no_ack_duplicate(conn, (uint32_t) -9));
+
+	tcp_conn_delete(conn);
+}
+
+/** Test seq_no_in_rcv_wnd() */
+PCUT_TEST(in_rcv_wnd)
+{
+	tcp_conn_t *conn;
+	inet_ep2_t epp;
+
+	inet_ep2_init(&epp);
+	conn = tcp_conn_new(&epp);
+	PCUT_ASSERT_NOT_NULL(conn);
+
+	/* In receive window iff RCV.WND <= SEG.SEQ <= SND.UNA */
+
+	conn->rcv_nxt = 10;
+	conn->rcv_wnd = 20;
+
+	PCUT_ASSERT_FALSE(seq_no_in_rcv_wnd(conn, 9));
+	PCUT_ASSERT_TRUE(seq_no_in_rcv_wnd(conn, 10));
+	PCUT_ASSERT_TRUE(seq_no_in_rcv_wnd(conn, 11));
+	PCUT_ASSERT_TRUE(seq_no_in_rcv_wnd(conn, 29));
+	PCUT_ASSERT_FALSE(seq_no_in_rcv_wnd(conn, 30));
+	PCUT_ASSERT_FALSE(seq_no_in_rcv_wnd(conn, 31));
+
+	/* We also test whether seq_no_le_lt() wraps around properly */
+
+	conn->rcv_nxt = 20;
+	conn->rcv_wnd = (uint32_t) -10;
+
+	PCUT_ASSERT_FALSE(seq_no_in_rcv_wnd(conn,19));
+	PCUT_ASSERT_TRUE(seq_no_in_rcv_wnd(conn, 20));
+	PCUT_ASSERT_TRUE(seq_no_in_rcv_wnd(conn, 21));
+	PCUT_ASSERT_TRUE(seq_no_in_rcv_wnd(conn, 9));
+	PCUT_ASSERT_FALSE(seq_no_in_rcv_wnd(conn, 10));
+	PCUT_ASSERT_FALSE(seq_no_in_rcv_wnd(conn, 11));
+
+	tcp_conn_delete(conn);
+}
+
+/** Test seq_no_new_wnd_update() */
+PCUT_TEST(new_wnd_update)
+{
+	tcp_conn_t *conn;
+	inet_ep2_t epp;
+	tcp_segment_t *seg;
+
+	inet_ep2_init(&epp);
+	conn = tcp_conn_new(&epp);
+	PCUT_ASSERT_NOT_NULL(conn);
+
+	/*
+	 * Segment must be acceptable. Segment has new window update iff
+	 * either SND.WL1 < SEG.SEQ or
+	 * (SND.WL1 = SEG.SEQ and SND.WL2 <= SEG.ACK)
+	 */
+
+	conn->rcv_nxt = 10;
+	conn->rcv_wnd = 20;
+	conn->snd_una = 30;
+	conn->snd_wnd = 40;
+	conn->snd_wl1 = 15;
+	conn->snd_wl2 = 60;
+
+	seg = tcp_segment_make_ctrl(CTL_ACK);
+	PCUT_ASSERT_NOT_NULL(seg);
+
+	seg->seq = 14;
+	seg->ack = 80;
+	PCUT_ASSERT_FALSE(seq_no_new_wnd_update(conn, seg));
+
+	seg->seq = 15;
+	seg->ack = 59;
+	PCUT_ASSERT_FALSE(seq_no_new_wnd_update(conn, seg));
+
+	seg->seq = 15;
+	seg->ack = 60;
+	PCUT_ASSERT_TRUE(seq_no_new_wnd_update(conn, seg));
+
+	seg->seq = 16;
+	seg->ack = 50;
+	PCUT_ASSERT_TRUE(seq_no_new_wnd_update(conn, seg));
+
+	tcp_segment_delete(seg);
+	tcp_conn_delete(conn);
+}
+
+/** Test seq_no_segment_acked() */
+PCUT_TEST(segment_acked)
+{
+	tcp_conn_t *conn;
+	inet_ep2_t epp;
+	tcp_segment_t *seg;
+	uint8_t *data;
+	size_t dsize;
+
+	inet_ep2_init(&epp);
+	conn = tcp_conn_new(&epp);
+	PCUT_ASSERT_NOT_NULL(conn);
+
+	dsize = 15;
+	data = calloc(dsize, 1);
+	PCUT_ASSERT_NOT_NULL(data);
+
+	seg = tcp_segment_make_data(0, data, dsize);
+	PCUT_ASSERT_NOT_NULL(seg);
+
+	/* Segment is acked iff SEG.SEQ + SEG.LEN <= SND.UNA */
+
+	seg->seq = 10;
+	PCUT_ASSERT_INT_EQUALS(dsize, seg->len);
+
+	PCUT_ASSERT_FALSE(seq_no_segment_acked(conn, seg, 24));
+	PCUT_ASSERT_TRUE(seq_no_segment_acked(conn, seg, 25));
+
+	tcp_segment_delete(seg);
+	tcp_conn_delete(conn);
+	free(data);
+}
+
+/** Test seq_no_syn_acked() */
+PCUT_TEST(syn_acked)
+{
+	tcp_conn_t *conn;
+	inet_ep2_t epp;
+
+	inet_ep2_init(&epp);
+	conn = tcp_conn_new(&epp);
+	PCUT_ASSERT_NOT_NULL(conn);
+
+	conn->iss = 1;
+	conn->snd_una = 1;
+	conn->snd_nxt = 2;
+
+	PCUT_ASSERT_FALSE(seq_no_syn_acked(conn));
+
+	conn->snd_una = 2;
+	PCUT_ASSERT_TRUE(seq_no_syn_acked(conn));
+
+	tcp_conn_delete(conn);
+}
+
+/** Test seq_no_segment_acceptable() */
+PCUT_TEST(segment_acceptable)
+{
+	tcp_conn_t *conn;
+	inet_ep2_t epp;
+	tcp_segment_t *seg;
+	uint8_t *data;
+	size_t dsize;
+
+	inet_ep2_init(&epp);
+	conn = tcp_conn_new(&epp);
+	PCUT_ASSERT_NOT_NULL(conn);
+
+	dsize = 15;
+	data = calloc(dsize, 1);
+	PCUT_ASSERT_NOT_NULL(data);
+
+	seg = tcp_segment_make_data(0, data, dsize);
+	PCUT_ASSERT_NOT_NULL(seg);
+
+	/* Segment acceptable iff overlaps receive window */
+
+	/* Segment shorter than receive window */
+	conn->rcv_nxt = 30;
+	conn->rcv_wnd = 20;
+
+	PCUT_ASSERT_INT_EQUALS(dsize, seg->len);
+
+	seg->seq = 10;
+	PCUT_ASSERT_FALSE(seq_no_segment_acceptable(conn, seg));
+
+	seg->seq = 15;
+	PCUT_ASSERT_FALSE(seq_no_segment_acceptable(conn, seg));
+
+	seg->seq = 16;
+	PCUT_ASSERT_TRUE(seq_no_segment_acceptable(conn, seg));
+
+	seg->seq = 49;
+	PCUT_ASSERT_TRUE(seq_no_segment_acceptable(conn, seg));
+
+	seg->seq = 50;
+	PCUT_ASSERT_FALSE(seq_no_segment_acceptable(conn, seg));
+
+	/* Segment longer than receive window */
+	conn->rcv_nxt = 30;
+	conn->rcv_wnd = 10;
+
+	PCUT_ASSERT_INT_EQUALS(dsize, seg->len);
+
+	seg->seq = 10;
+	PCUT_ASSERT_FALSE(seq_no_segment_acceptable(conn, seg));
+
+	seg->seq = 15;
+	PCUT_ASSERT_FALSE(seq_no_segment_acceptable(conn, seg));
+
+	seg->seq = 16;
+	PCUT_ASSERT_TRUE(seq_no_segment_acceptable(conn, seg));
+
+	seg->seq = 39;
+	PCUT_ASSERT_TRUE(seq_no_segment_acceptable(conn, seg));
+
+	seg->seq = 40;
+	PCUT_ASSERT_FALSE(seq_no_segment_acceptable(conn, seg));
+
+	tcp_segment_delete(seg);
+	tcp_conn_delete(conn);
+	free(data);
+}
+
+/** Test seq_no_seg_trim_calc() */
+PCUT_TEST(seg_trim_calc)
+{
+	tcp_conn_t *conn;
+	inet_ep2_t epp;
+	tcp_segment_t *seg;
+	uint8_t *data;
+	size_t dsize;
+	uint32_t ltrim, rtrim;
+
+	inet_ep2_init(&epp);
+	conn = tcp_conn_new(&epp);
+	PCUT_ASSERT_NOT_NULL(conn);
+
+	dsize = 15;
+	data = calloc(dsize, 1);
+	PCUT_ASSERT_NOT_NULL(data);
+
+	seg = tcp_segment_make_data(0, data, dsize);
+	PCUT_ASSERT_NOT_NULL(seg);
+
+	/* Segment must be acceptable, amount of trim needed */
+
+	/* Segment shorter than receive window */
+	conn->rcv_nxt = 30;
+	conn->rcv_wnd = 20;
+
+	PCUT_ASSERT_INT_EQUALS(dsize, seg->len);
+
+	seg->seq = 16;
+	seq_no_seg_trim_calc(conn, seg, &ltrim, &rtrim);
+	PCUT_ASSERT_INT_EQUALS(14, ltrim);
+	PCUT_ASSERT_INT_EQUALS(0, rtrim);
+
+	seg->seq = 17;
+	seq_no_seg_trim_calc(conn, seg, &ltrim, &rtrim);
+	PCUT_ASSERT_INT_EQUALS(13, ltrim);
+	PCUT_ASSERT_INT_EQUALS(0, rtrim);
+
+	seg->seq = 29;
+	seq_no_seg_trim_calc(conn, seg, &ltrim, &rtrim);
+	PCUT_ASSERT_INT_EQUALS(1, ltrim);
+	PCUT_ASSERT_INT_EQUALS(0, rtrim);
+
+	seg->seq = 30;
+	seq_no_seg_trim_calc(conn, seg, &ltrim, &rtrim);
+	PCUT_ASSERT_INT_EQUALS(0, ltrim);
+	PCUT_ASSERT_INT_EQUALS(0, rtrim);
+
+	seg->seq = 31;
+	seq_no_seg_trim_calc(conn, seg, &ltrim, &rtrim);
+	PCUT_ASSERT_INT_EQUALS(0, ltrim);
+	PCUT_ASSERT_INT_EQUALS(0, rtrim);
+
+	seg->seq = 35;
+	seq_no_seg_trim_calc(conn, seg, &ltrim, &rtrim);
+	PCUT_ASSERT_INT_EQUALS(0, ltrim);
+	PCUT_ASSERT_INT_EQUALS(0, rtrim);
+
+	seg->seq = 36;
+	seq_no_seg_trim_calc(conn, seg, &ltrim, &rtrim);
+	PCUT_ASSERT_INT_EQUALS(0, ltrim);
+	PCUT_ASSERT_INT_EQUALS(1, rtrim);
+
+	seg->seq = 37;
+	seq_no_seg_trim_calc(conn, seg, &ltrim, &rtrim);
+	PCUT_ASSERT_INT_EQUALS(0, ltrim);
+	PCUT_ASSERT_INT_EQUALS(2, rtrim);
+
+	seg->seq = 48;
+	seq_no_seg_trim_calc(conn, seg, &ltrim, &rtrim);
+	PCUT_ASSERT_INT_EQUALS(0, ltrim);
+	PCUT_ASSERT_INT_EQUALS(13, rtrim);
+
+	seg->seq = 49;
+	seq_no_seg_trim_calc(conn, seg, &ltrim, &rtrim);
+	PCUT_ASSERT_INT_EQUALS(0, ltrim);
+	PCUT_ASSERT_INT_EQUALS(14, rtrim);
+
+	/* Segment longer than receive window */
+	conn->rcv_nxt = 30;
+	conn->rcv_wnd = 10;
+
+	PCUT_ASSERT_INT_EQUALS(dsize, seg->len);
+
+	seg->seq = 16;
+	seq_no_seg_trim_calc(conn, seg, &ltrim, &rtrim);
+	PCUT_ASSERT_INT_EQUALS(14, ltrim);
+	PCUT_ASSERT_INT_EQUALS(0, rtrim);
+
+	seg->seq = 17;
+	seq_no_seg_trim_calc(conn, seg, &ltrim, &rtrim);
+	PCUT_ASSERT_INT_EQUALS(13, ltrim);
+	PCUT_ASSERT_INT_EQUALS(0, rtrim);
+
+	seg->seq = 24;
+	seq_no_seg_trim_calc(conn, seg, &ltrim, &rtrim);
+	PCUT_ASSERT_INT_EQUALS(6, ltrim);
+	PCUT_ASSERT_INT_EQUALS(0, rtrim);
+
+	seg->seq = 25;
+	seq_no_seg_trim_calc(conn, seg, &ltrim, &rtrim);
+	PCUT_ASSERT_INT_EQUALS(5, ltrim);
+	PCUT_ASSERT_INT_EQUALS(0, rtrim);
+
+	seg->seq = 26;
+	seq_no_seg_trim_calc(conn, seg, &ltrim, &rtrim);
+	PCUT_ASSERT_INT_EQUALS(4, ltrim);
+	PCUT_ASSERT_INT_EQUALS(1, rtrim);
+
+	tcp_segment_delete(seg);
+	tcp_conn_delete(conn);
+	free(data);
+}
+
+/** Test seq_no_seg_cmp() */
+PCUT_TEST(seg_cmp)
+{
+	tcp_conn_t *conn;
+	inet_ep2_t epp;
+	tcp_segment_t *seg1, *seg2;
+	uint8_t *data;
+	size_t dsize;
+
+	inet_ep2_init(&epp);
+	conn = tcp_conn_new(&epp);
+	PCUT_ASSERT_NOT_NULL(conn);
+
+	dsize = 15;
+	data = calloc(dsize, 1);
+	PCUT_ASSERT_NOT_NULL(data);
+
+	seg1 = tcp_segment_make_data(0, data, dsize);
+	PCUT_ASSERT_NOT_NULL(seg1);
+	seg2 = tcp_segment_make_data(0, data, dsize);
+	PCUT_ASSERT_NOT_NULL(seg2);
+
+	/* Both segments must be acceptable */
+
+	conn->rcv_nxt = 10;
+	conn->rcv_wnd = 20;
+
+	PCUT_ASSERT_INT_EQUALS(dsize, seg1->len);
+	PCUT_ASSERT_INT_EQUALS(dsize, seg2->len);
+
+	seg1->seq = 5;
+	seg2->seq = 6;
+	PCUT_ASSERT_INT_EQUALS(-1, seq_no_seg_cmp(conn, seg1, seg2));
+
+	seg1->seq = 6;
+	seg2->seq = 6;
+	PCUT_ASSERT_INT_EQUALS(0, seq_no_seg_cmp(conn, seg1, seg2));
+
+	seg1->seq = 6;
+	seg2->seq = 5;
+	PCUT_ASSERT_INT_EQUALS(1, seq_no_seg_cmp(conn, seg1, seg2));
+
+	tcp_segment_delete(seg1);
+	tcp_segment_delete(seg2);
+	tcp_conn_delete(conn);
+	free(data);
+}
+
+/** Test seq_no_control_len() */
+PCUT_TEST(control_len)
+{
+	PCUT_ASSERT_INT_EQUALS(0, seq_no_control_len(0));
+	PCUT_ASSERT_INT_EQUALS(0, seq_no_control_len(CTL_ACK));
+	PCUT_ASSERT_INT_EQUALS(0, seq_no_control_len(CTL_RST));
+	PCUT_ASSERT_INT_EQUALS(0, seq_no_control_len(CTL_ACK | CTL_RST));
+	PCUT_ASSERT_INT_EQUALS(1, seq_no_control_len(CTL_SYN));
+	PCUT_ASSERT_INT_EQUALS(1, seq_no_control_len(CTL_FIN));
+	PCUT_ASSERT_INT_EQUALS(1, seq_no_control_len(CTL_SYN | CTL_ACK));
+	PCUT_ASSERT_INT_EQUALS(1, seq_no_control_len(CTL_FIN | CTL_ACK));
+	PCUT_ASSERT_INT_EQUALS(1, seq_no_control_len(CTL_SYN | CTL_RST));
+	PCUT_ASSERT_INT_EQUALS(1, seq_no_control_len(CTL_FIN | CTL_RST));
+	PCUT_ASSERT_INT_EQUALS(1, seq_no_control_len(CTL_SYN | CTL_ACK |
+	    CTL_RST));
+	PCUT_ASSERT_INT_EQUALS(1, seq_no_control_len(CTL_FIN | CTL_ACK |
+	    CTL_RST));
+	PCUT_ASSERT_INT_EQUALS(2, seq_no_control_len(CTL_SYN | CTL_FIN));
+	PCUT_ASSERT_INT_EQUALS(2, seq_no_control_len(CTL_SYN | CTL_FIN |
+	    CTL_ACK));
+	PCUT_ASSERT_INT_EQUALS(2, seq_no_control_len(CTL_SYN | CTL_FIN |
+	    CTL_RST));
+	PCUT_ASSERT_INT_EQUALS(2, seq_no_control_len(CTL_SYN | CTL_FIN |
+	    CTL_ACK | CTL_RST));
+}
+
+PCUT_EXPORT(seq_no);
