summaryrefslogtreecommitdiff
path: root/tools/testing/selftests/net/tun.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-10-09 06:40:28 +0200
committerLinus Torvalds <torvalds@linux-foundation.org>2026-10-09 06:40:28 +0200
commitaf32da41b0327b9c6a37856ba82b6760d6c8d10e (patch)
tree1908c1d636394d7ab56ed3e469eb41e9cd357fd6 /tools/testing/selftests/net/tun.c
parent6c377d19d4a5116d9bec5203aa3c6c11523e7898 (diff)
parent37f12441f557468a56c1e27790413aa78c82afa2 (diff)
downloadlinux-next-stable.tar.gz
linux-next-stable.zip
Merge tag 'net-7.3-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/netstable
Pull networking fixes from Jakub Kicinski: "Including fixes from wireless, wireguard, CAN and Bluetooth. We have one known regression to wrap up in VLAN handling. Current release - regressions: - Bluetooth: RFCOMM: fix deadlock on rfcomm_mutex Previous releases - regressions: - can: fix regression in handling RPS after migrating metadata to skb_ext - eth: - iavf: fix regressions in reconfig impacting bonding - mana: fix packet forwarding performance regression - stmmac: remove buggy VLAN acceleration support Previous releases - always broken: - a few high prio fixes for tun, and af_packet - amt: fix a UaF on tunnel teardown - eth: - bnxt: fix PCIe AER recovery and FLR handling issues - macb: don't modify Tx skbs before taking ownership - axienet: don't leak Tx skbs on interface stop - wifi: - nxpwifi: number of LLM-ish fixes - assorted mt76 fixes" * tag 'net-7.3-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net: (128 commits) net: macb: copy shared skbs before appending the FCS net: macb: check TX ring before modifying skb vsock: Fix memory leak in vmci_transport_recv_dgram_cb() wireguard: noise: reject response consumption after intermediate initiation wireguard: queueing: preserve tstamp_type when encapsulating packet net: openvswitch: validate transport header presence in set_ipv6_addr net/smc: protect clcsock lifetime in smc_getname ipv6: do not warn on route notification size race ipv4: do not warn on route notification size race ipv4: validate checksum_start before completing checksum ptp: ocp: fix PCIe delay estimation calculation xen/netfront: don't leak the skb when xennet_fill_frags() fails net/packet: call packet_parse_headers after virtio_net_hdr_to_skb xen/netfront: drop RX packets with a short Ethernet header net: skbuff: don't leave stale bytes in skb_copy_and_csum_bits() net: sparx5: free the matchall entry on destroy selftests: mlxsw: Test port range occupancy on template create mlxsw: spectrum_flower: Fix port range register leak in tmplt_create() net: dsa: microchip: fix KSZ8765 fiber detection net/mlx5e: Order ICOSQ cc update after CQ doorbell ...
Diffstat (limited to 'tools/testing/selftests/net/tun.c')
-rw-r--r--tools/testing/selftests/net/tun.c136
1 files changed, 136 insertions, 0 deletions
diff --git a/tools/testing/selftests/net/tun.c b/tools/testing/selftests/net/tun.c
index abe488bac50b..afaa81c9bac5 100644
--- a/tools/testing/selftests/net/tun.c
+++ b/tools/testing/selftests/net/tun.c
@@ -9,6 +9,7 @@
#include <string.h>
#include <unistd.h>
#include <linux/if_tun.h>
+#include <netinet/tcp.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
@@ -542,6 +543,141 @@ TEST_F(tun, reattach_close_delete)
EXPECT_EQ(tun_delete(self->ifname), 0);
}
+FIXTURE(tun_vnet_gso)
+{
+ char ifname[IFNAMSIZ];
+ int fd;
+};
+
+FIXTURE_SETUP(tun_vnet_gso)
+{
+ int flags = IFF_TAP | IFF_NO_PI | IFF_VNET_HDR;
+
+ memset(self->ifname, 0, sizeof(self->ifname));
+ self->fd = tun_open(self->ifname, flags, 0, 0, NULL);
+ ASSERT_GE(self->fd, 0);
+}
+
+FIXTURE_TEARDOWN(tun_vnet_gso)
+{
+ if (self->fd >= 0)
+ close(self->fd);
+}
+
+static int build_vlan_tcpv4_gso_packet(uint8_t *buf, int payload_len)
+{
+ uint16_t vlan_tag[2] = { htons(100), htons(ETH_P_IP) };
+ uint8_t *cur = buf + sizeof(struct virtio_net_hdr);
+ struct virtio_net_hdr vh = { 0 };
+ struct tcphdr tcph = { 0 };
+ uint32_t sum;
+
+ cur += build_eth(cur, ETH_P_8021Q, param_hwaddr_outer_src,
+ param_hwaddr_outer_dst);
+
+ /* 802.1Q tag: VID=100, inner protocol=ETH_P_IP */
+ memcpy(cur, vlan_tag, sizeof(vlan_tag));
+ cur += sizeof(vlan_tag);
+
+ cur += build_ipv4_header(cur, IPPROTO_TCP,
+ sizeof(tcph) + payload_len,
+ &param_ipaddr4_outer_src,
+ &param_ipaddr4_outer_dst);
+
+ tcph.source = htons(12345);
+ tcph.dest = htons(80);
+ tcph.seq = htonl(1);
+ tcph.doff = sizeof(tcph) / 4;
+ tcph.ack = 1;
+ tcph.window = htons(65535);
+ memcpy(cur, &tcph, sizeof(tcph));
+ memset(cur + sizeof(tcph), PKT_DATA, payload_len);
+
+ sum = add_csum((const uint8_t *)&param_ipaddr4_outer_src,
+ sizeof(param_ipaddr4_outer_src));
+ sum += add_csum((const uint8_t *)&param_ipaddr4_outer_dst,
+ sizeof(param_ipaddr4_outer_dst));
+ sum += htons(IPPROTO_TCP) + htons(sizeof(tcph) + payload_len);
+ sum += add_csum(cur, sizeof(tcph) + payload_len);
+ tcph.check = finish_ip_csum(sum);
+ memcpy(cur, &tcph, sizeof(tcph));
+ cur += sizeof(tcph) + payload_len;
+
+ vh.gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
+ vh.gso_size = 1400;
+ vh.hdr_len = (cur - buf) - sizeof(vh) - payload_len;
+ memcpy(buf, &vh, sizeof(vh));
+
+ return cur - buf;
+}
+
+TEST_F(tun_vnet_gso, vlan_tcpv4_gso_no_csum)
+{
+ struct virtio_net_hdr vh;
+ uint8_t pkt[4096] = { 0 };
+ int len, ret;
+
+ len = build_vlan_tcpv4_gso_packet(pkt, 2800);
+ memcpy(&vh, pkt, sizeof(vh));
+
+ /* Valid VLAN-tagged TCPv4 GSO with flags = 0 (no NEEDS_CSUM) */
+ vh.flags = 0;
+ memcpy(pkt, &vh, sizeof(vh));
+ ret = write(self->fd, pkt, len);
+ ASSERT_EQ(ret, len);
+
+ /* Valid VLAN-tagged TCPv4 GSO with flags = DATA_VALID */
+ vh.flags = VIRTIO_NET_HDR_F_DATA_VALID;
+ memcpy(pkt, &vh, sizeof(vh));
+ ret = write(self->fd, pkt, len);
+ ASSERT_EQ(ret, len);
+
+ /* Mismatched GSO type (TCPV6 on VLAN-tagged IPv4 packet) */
+ vh.flags = 0;
+ vh.gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
+ memcpy(pkt, &vh, sizeof(vh));
+ ret = write(self->fd, pkt, len);
+ ASSERT_EQ(ret, -1);
+ ASSERT_EQ(errno, EINVAL);
+
+ /* TCP header truncated after 10 bytes, without NEEDS_CSUM.
+ * Requires the transport header offset found by flow dissection:
+ * pulling only sizeof(struct iphdr) + sizeof(struct tcphdr) bytes
+ * from the mac header would accept this frame.
+ */
+ vh.gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
+ vh.hdr_len = ETH_HLEN + 4 + sizeof(struct iphdr) + 10;
+ memcpy(pkt, &vh, sizeof(vh));
+ ret = write(self->fd, pkt, sizeof(vh) + vh.hdr_len);
+ ASSERT_EQ(ret, -1);
+ ASSERT_EQ(errno, EINVAL);
+}
+
+TEST_F(tun_vnet_gso, vlan_tcpv4_gso_no_csum_64k)
+{
+ /* Ethernet frame of 65540 bytes: skb->len is above U16_MAX when the
+ * frame is flow-dissected, before eth_type_trans() pulls ETH_HLEN.
+ */
+ const int payload_len = 65540 - ETH_HLEN - 4 -
+ sizeof(struct iphdr) - sizeof(struct tcphdr);
+ struct virtio_net_hdr vh;
+ uint8_t *pkt;
+ int len, ret;
+
+ pkt = calloc(1, sizeof(vh) + 65540);
+ ASSERT_NE(pkt, NULL);
+
+ len = build_vlan_tcpv4_gso_packet(pkt, payload_len);
+ ASSERT_EQ(len, sizeof(vh) + 65540);
+ memcpy(&vh, pkt, sizeof(vh));
+
+ vh.flags = 0;
+ memcpy(pkt, &vh, sizeof(vh));
+ ret = write(self->fd, pkt, len);
+ free(pkt);
+ ASSERT_EQ(ret, len);
+}
+
FIXTURE(tun_vnet_udptnl)
{
char ifname[IFNAMSIZ];