diff --git a/tcp.c b/tcp.c
index f334ca5..5c40e18 100644
--- a/tcp.c
+++ b/tcp.c
@@ -755,106 +755,42 @@ static void tcp_sock_set_bufsize(const struct ctx *c, int s)
 /**
  * tcp_update_check_tcp4() - Calculate TCP checksum for IPv4
  * @iph:	IPv4 header
- * @iov:	Pointer to the array of IO vectors
- * @iov_cnt:	Length of the array
- * @l4offset:	IPv4 payload offset in the iovec array
+ * @th:		TCP header (updated)
+ * @payload:	TCP payload
  */
-void tcp_update_check_tcp4(const struct iphdr *iph,
-			   const struct iovec *iov, int iov_cnt,
-			   size_t l4offset)
+void tcp_update_check_tcp4(const struct iphdr *iph, struct tcphdr *th,
+			   struct iov_tail *payload)
 {
 	uint16_t l4len = ntohs(iph->tot_len) - sizeof(struct iphdr);
-	struct iov_tail l4 = IOV_TAIL(iov, iov_cnt, l4offset);
 	struct in_addr saddr = { .s_addr = iph->saddr };
 	struct in_addr daddr = { .s_addr = iph->daddr };
-	size_t check_ofs;
-	uint16_t *check;
-	int check_idx;
 	uint32_t sum;
-	char *ptr;
 
 	sum = proto_ipv4_header_psum(l4len, IPPROTO_TCP, saddr, daddr);
 
-	check_idx = iov_skip_bytes(iov, iov_cnt,
-				   l4offset + offsetof(struct tcphdr, check),
-				   &check_ofs);
-
-	if (check_idx >= iov_cnt) {
-		err("TCP4 buffer is too small, iov size %zd, check offset %zd",
-		    iov_size(iov, iov_cnt),
-		    l4offset + offsetof(struct tcphdr, check));
-		return;
-	}
-
-	if (check_ofs + sizeof(*check) > iov[check_idx].iov_len) {
-		err("TCP4 checksum field memory is not contiguous "
-		    "check_ofs %zd check_idx %d iov_len %zd",
-		    check_ofs, check_idx, iov[check_idx].iov_len);
-		return;
-	}
-
-	ptr = (char *)iov[check_idx].iov_base + check_ofs;
-	if ((uintptr_t)ptr & (__alignof__(*check) - 1)) {
-		err("TCP4 checksum field is not correctly aligned in memory");
-		return;
-	}
-
-	check = (uint16_t *)ptr;
-
-	*check = 0;
-	*check = csum_iov_tail(&l4, sum);
+	th->check = 0;
+	sum = csum_unfolded(th, sizeof(*th), sum);
+	th->check = csum_iov_tail(payload, sum);
 }
 
 /**
  * tcp_update_check_tcp6() - Calculate TCP checksum for IPv6
  * @ip6h:	IPv6 header
- * @iov:	Pointer to the array of IO vectors
- * @iov_cnt:	Length of the array
- * @l4offset:	IPv6 payload offset in the iovec array
+ * @th:		TCP header (updated)
+ * @payload:	TCP payload
  */
-void tcp_update_check_tcp6(const struct ipv6hdr *ip6h,
-			   const struct iovec *iov, int iov_cnt,
-			   size_t l4offset)
+void tcp_update_check_tcp6(const struct ipv6hdr *ip6h, struct tcphdr *th,
+			   struct iov_tail *payload)
 {
-	struct iov_tail l4 = IOV_TAIL(iov, iov_cnt, l4offset);
 	uint16_t l4len = ntohs(ip6h->payload_len);
-	size_t check_ofs;
-	uint16_t *check;
-	int check_idx;
 	uint32_t sum;
-	char *ptr;
 
 	sum = proto_ipv6_header_psum(l4len, IPPROTO_TCP, &ip6h->saddr,
 				     &ip6h->daddr);
 
-	check_idx = iov_skip_bytes(iov, iov_cnt,
-				   l4offset + offsetof(struct tcphdr, check),
-				   &check_ofs);
-
-	if (check_idx >= iov_cnt) {
-		err("TCP6 buffer is too small, iov size %zd, check offset %zd",
-		    iov_size(iov, iov_cnt),
-		    l4offset + offsetof(struct tcphdr, check));
-		return;
-	}
-
-	if (check_ofs + sizeof(*check) > iov[check_idx].iov_len) {
-		err("TCP6 checksum field memory is not contiguous "
-		    "check_ofs %zd check_idx %d iov_len %zd",
-		    check_ofs, check_idx, iov[check_idx].iov_len);
-		return;
-	}
-
-	ptr = (char *)iov[check_idx].iov_base + check_ofs;
-	if ((uintptr_t)ptr & (__alignof__(*check) - 1)) {
-		err("TCP6 checksum field is not correctly aligned in memory");
-		return;
-	}
-
-	check = (uint16_t *)ptr;
-
-	*check = 0;
-	*check = csum_iov_tail(&l4, sum);
+	th->check = 0;
+	sum = csum_unfolded(th, sizeof(*th), sum);
+	th->check = csum_iov_tail(payload, sum);
 }
 
 /**
@@ -1005,11 +941,12 @@ void tcp_fill_headers4(const struct tcp_tap_conn *conn,
 		bp->th.check = 0;
 	} else {
 		const struct iovec iov = {
-			.iov_base = bp,
-			.iov_len = ntohs(iph->tot_len) - sizeof(struct iphdr),
+			.iov_base = bp->data,
+			.iov_len = dlen,
 		};
+		struct iov_tail payload = IOV_TAIL(&iov, 1, 0);
 
-		tcp_update_check_tcp4(iph, &iov, 1, 0);
+		tcp_update_check_tcp4(iph, &bp->th, &payload);
 	}
 
 	tap_hdr_update(taph, l3len + sizeof(struct ethhdr));
@@ -1052,11 +989,12 @@ void tcp_fill_headers6(const struct tcp_tap_conn *conn,
 		bp->th.check = 0;
 	} else {
 		const struct iovec iov = {
-			.iov_base = bp,
-			.iov_len = ntohs(ip6h->payload_len)
+			.iov_base = bp->data,
+			.iov_len = dlen,
 		};
+		struct iov_tail payload = IOV_TAIL(&iov, 1, 0);
 
-		tcp_update_check_tcp6(ip6h, &iov, 1, 0);
+		tcp_update_check_tcp6(ip6h, &bp->th, &payload);
 	}
 
 	tap_hdr_update(taph, l4len + sizeof(*ip6h) + sizeof(struct ethhdr));
diff --git a/tcp_internal.h b/tcp_internal.h
index d7b125f..744c5c0 100644
--- a/tcp_internal.h
+++ b/tcp_internal.h
@@ -162,12 +162,10 @@ void tcp_rst_do(const struct ctx *c, struct tcp_tap_conn *conn);
 
 struct tcp_info_linux;
 
-void tcp_update_check_tcp4(const struct iphdr *iph,
-			   const struct iovec *iov, int iov_cnt,
-			   size_t l4offset);
-void tcp_update_check_tcp6(const struct ipv6hdr *ip6h,
-			   const struct iovec *iov, int iov_cnt,
-			   size_t l4offset);
+void tcp_update_check_tcp4(const struct iphdr *iph, struct tcphdr *th,
+			   struct iov_tail *payload);
+void tcp_update_check_tcp6(const struct ipv6hdr *ip6h, struct tcphdr *th,
+			   struct iov_tail *payload);
 void tcp_fill_headers4(const struct tcp_tap_conn *conn,
 		       struct tap_hdr *taph, struct iphdr *iph,
 		       struct tcp_payload_t *bp, size_t dlen,
diff --git a/tcp_vu.c b/tcp_vu.c
index bbae918..134650e 100644
--- a/tcp_vu.c
+++ b/tcp_vu.c
@@ -73,15 +73,19 @@ static void tcp_vu_update_check(const struct flowside *tapside,
 	char *base = iov[0].iov_base;
 
 	if (inany_v4(&tapside->oaddr)) {
+		struct tcphdr *th = vu_payloadv4(base);
 		const struct iphdr *iph = vu_ip(base);
+		struct iov_tail payload = IOV_TAIL(iov, iov_cnt,
+						   (char *)(th + 1) - base);
 
-		tcp_update_check_tcp4(iph, iov, iov_cnt,
-				      (char *)vu_payloadv4(base) - base);
+		tcp_update_check_tcp4(iph, th, &payload);
 	} else {
+		struct tcphdr *th = vu_payloadv6(base);
 		const struct ipv6hdr *ip6h = vu_ip(base);
+		struct iov_tail payload = IOV_TAIL(iov, iov_cnt,
+						   (char *)(th + 1) - base);
 
-		tcp_update_check_tcp6(ip6h, iov, iov_cnt,
-				      (char *)vu_payloadv6(base) - base);
+		tcp_update_check_tcp6(ip6h, th, &payload);
 	}
 }