aboutgitcodebugslistschat
diff options
context:
space:
mode:
-rw-r--r--tcp.c106
-rw-r--r--tcp_internal.h10
-rw-r--r--tcp_vu.c12
3 files changed, 34 insertions, 94 deletions
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);
}
}