1*839b92feSJakub Kicinski // SPDX-License-Identifier: GPL-2.0 2*839b92feSJakub Kicinski 3*839b92feSJakub Kicinski #define _GNU_SOURCE 4*839b92feSJakub Kicinski 5*839b92feSJakub Kicinski #include <errno.h> 6*839b92feSJakub Kicinski #include <fcntl.h> 7*839b92feSJakub Kicinski #include <stdio.h> 8*839b92feSJakub Kicinski #include <stdlib.h> 9*839b92feSJakub Kicinski #include <string.h> 10*839b92feSJakub Kicinski #include <unistd.h> 11*839b92feSJakub Kicinski #include <linux/if.h> 12*839b92feSJakub Kicinski #include <linux/if_tun.h> 13*839b92feSJakub Kicinski #include <linux/netlink.h> 14*839b92feSJakub Kicinski #include <linux/rtnetlink.h> 15*839b92feSJakub Kicinski #include <sys/ioctl.h> 16*839b92feSJakub Kicinski #include <sys/socket.h> 17*839b92feSJakub Kicinski 18*839b92feSJakub Kicinski #include "../kselftest_harness.h" 19*839b92feSJakub Kicinski 20*839b92feSJakub Kicinski static int tun_attach(int fd, char *dev) 21*839b92feSJakub Kicinski { 22*839b92feSJakub Kicinski struct ifreq ifr; 23*839b92feSJakub Kicinski 24*839b92feSJakub Kicinski memset(&ifr, 0, sizeof(ifr)); 25*839b92feSJakub Kicinski strcpy(ifr.ifr_name, dev); 26*839b92feSJakub Kicinski ifr.ifr_flags = IFF_ATTACH_QUEUE; 27*839b92feSJakub Kicinski 28*839b92feSJakub Kicinski return ioctl(fd, TUNSETQUEUE, (void *) &ifr); 29*839b92feSJakub Kicinski } 30*839b92feSJakub Kicinski 31*839b92feSJakub Kicinski static int tun_detach(int fd, char *dev) 32*839b92feSJakub Kicinski { 33*839b92feSJakub Kicinski struct ifreq ifr; 34*839b92feSJakub Kicinski 35*839b92feSJakub Kicinski memset(&ifr, 0, sizeof(ifr)); 36*839b92feSJakub Kicinski strcpy(ifr.ifr_name, dev); 37*839b92feSJakub Kicinski ifr.ifr_flags = IFF_DETACH_QUEUE; 38*839b92feSJakub Kicinski 39*839b92feSJakub Kicinski return ioctl(fd, TUNSETQUEUE, (void *) &ifr); 40*839b92feSJakub Kicinski } 41*839b92feSJakub Kicinski 42*839b92feSJakub Kicinski static int tun_alloc(char *dev) 43*839b92feSJakub Kicinski { 44*839b92feSJakub Kicinski struct ifreq ifr; 45*839b92feSJakub Kicinski int fd, err; 46*839b92feSJakub Kicinski 47*839b92feSJakub Kicinski fd = open("/dev/net/tun", O_RDWR); 48*839b92feSJakub Kicinski if (fd < 0) { 49*839b92feSJakub Kicinski fprintf(stderr, "can't open tun: %s\n", strerror(errno)); 50*839b92feSJakub Kicinski return fd; 51*839b92feSJakub Kicinski } 52*839b92feSJakub Kicinski 53*839b92feSJakub Kicinski memset(&ifr, 0, sizeof(ifr)); 54*839b92feSJakub Kicinski strcpy(ifr.ifr_name, dev); 55*839b92feSJakub Kicinski ifr.ifr_flags = IFF_TAP | IFF_NAPI | IFF_MULTI_QUEUE; 56*839b92feSJakub Kicinski 57*839b92feSJakub Kicinski err = ioctl(fd, TUNSETIFF, (void *) &ifr); 58*839b92feSJakub Kicinski if (err < 0) { 59*839b92feSJakub Kicinski fprintf(stderr, "can't TUNSETIFF: %s\n", strerror(errno)); 60*839b92feSJakub Kicinski close(fd); 61*839b92feSJakub Kicinski return err; 62*839b92feSJakub Kicinski } 63*839b92feSJakub Kicinski strcpy(dev, ifr.ifr_name); 64*839b92feSJakub Kicinski return fd; 65*839b92feSJakub Kicinski } 66*839b92feSJakub Kicinski 67*839b92feSJakub Kicinski static int tun_delete(char *dev) 68*839b92feSJakub Kicinski { 69*839b92feSJakub Kicinski struct { 70*839b92feSJakub Kicinski struct nlmsghdr nh; 71*839b92feSJakub Kicinski struct ifinfomsg ifm; 72*839b92feSJakub Kicinski unsigned char data[64]; 73*839b92feSJakub Kicinski } req; 74*839b92feSJakub Kicinski struct rtattr *rta; 75*839b92feSJakub Kicinski int ret, rtnl; 76*839b92feSJakub Kicinski 77*839b92feSJakub Kicinski rtnl = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); 78*839b92feSJakub Kicinski if (rtnl < 0) { 79*839b92feSJakub Kicinski fprintf(stderr, "can't open rtnl: %s\n", strerror(errno)); 80*839b92feSJakub Kicinski return 1; 81*839b92feSJakub Kicinski } 82*839b92feSJakub Kicinski 83*839b92feSJakub Kicinski memset(&req, 0, sizeof(req)); 84*839b92feSJakub Kicinski req.nh.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.ifm))); 85*839b92feSJakub Kicinski req.nh.nlmsg_flags = NLM_F_REQUEST; 86*839b92feSJakub Kicinski req.nh.nlmsg_type = RTM_DELLINK; 87*839b92feSJakub Kicinski 88*839b92feSJakub Kicinski req.ifm.ifi_family = AF_UNSPEC; 89*839b92feSJakub Kicinski 90*839b92feSJakub Kicinski rta = (struct rtattr *)(((char *)&req) + NLMSG_ALIGN(req.nh.nlmsg_len)); 91*839b92feSJakub Kicinski rta->rta_type = IFLA_IFNAME; 92*839b92feSJakub Kicinski rta->rta_len = RTA_LENGTH(IFNAMSIZ); 93*839b92feSJakub Kicinski req.nh.nlmsg_len += rta->rta_len; 94*839b92feSJakub Kicinski memcpy(RTA_DATA(rta), dev, IFNAMSIZ); 95*839b92feSJakub Kicinski 96*839b92feSJakub Kicinski ret = send(rtnl, &req, req.nh.nlmsg_len, 0); 97*839b92feSJakub Kicinski if (ret < 0) 98*839b92feSJakub Kicinski fprintf(stderr, "can't send: %s\n", strerror(errno)); 99*839b92feSJakub Kicinski ret = (unsigned int)ret != req.nh.nlmsg_len; 100*839b92feSJakub Kicinski 101*839b92feSJakub Kicinski close(rtnl); 102*839b92feSJakub Kicinski return ret; 103*839b92feSJakub Kicinski } 104*839b92feSJakub Kicinski 105*839b92feSJakub Kicinski FIXTURE(tun) 106*839b92feSJakub Kicinski { 107*839b92feSJakub Kicinski char ifname[IFNAMSIZ]; 108*839b92feSJakub Kicinski int fd, fd2; 109*839b92feSJakub Kicinski }; 110*839b92feSJakub Kicinski 111*839b92feSJakub Kicinski FIXTURE_SETUP(tun) 112*839b92feSJakub Kicinski { 113*839b92feSJakub Kicinski memset(self->ifname, 0, sizeof(self->ifname)); 114*839b92feSJakub Kicinski 115*839b92feSJakub Kicinski self->fd = tun_alloc(self->ifname); 116*839b92feSJakub Kicinski ASSERT_GE(self->fd, 0); 117*839b92feSJakub Kicinski 118*839b92feSJakub Kicinski self->fd2 = tun_alloc(self->ifname); 119*839b92feSJakub Kicinski ASSERT_GE(self->fd2, 0); 120*839b92feSJakub Kicinski } 121*839b92feSJakub Kicinski 122*839b92feSJakub Kicinski FIXTURE_TEARDOWN(tun) 123*839b92feSJakub Kicinski { 124*839b92feSJakub Kicinski if (self->fd >= 0) 125*839b92feSJakub Kicinski close(self->fd); 126*839b92feSJakub Kicinski if (self->fd2 >= 0) 127*839b92feSJakub Kicinski close(self->fd2); 128*839b92feSJakub Kicinski } 129*839b92feSJakub Kicinski 130*839b92feSJakub Kicinski TEST_F(tun, delete_detach_close) { 131*839b92feSJakub Kicinski EXPECT_EQ(tun_delete(self->ifname), 0); 132*839b92feSJakub Kicinski EXPECT_EQ(tun_detach(self->fd, self->ifname), -1); 133*839b92feSJakub Kicinski EXPECT_EQ(errno, 22); 134*839b92feSJakub Kicinski } 135*839b92feSJakub Kicinski 136*839b92feSJakub Kicinski TEST_F(tun, detach_delete_close) { 137*839b92feSJakub Kicinski EXPECT_EQ(tun_detach(self->fd, self->ifname), 0); 138*839b92feSJakub Kicinski EXPECT_EQ(tun_delete(self->ifname), 0); 139*839b92feSJakub Kicinski } 140*839b92feSJakub Kicinski 141*839b92feSJakub Kicinski TEST_F(tun, detach_close_delete) { 142*839b92feSJakub Kicinski EXPECT_EQ(tun_detach(self->fd, self->ifname), 0); 143*839b92feSJakub Kicinski close(self->fd); 144*839b92feSJakub Kicinski self->fd = -1; 145*839b92feSJakub Kicinski EXPECT_EQ(tun_delete(self->ifname), 0); 146*839b92feSJakub Kicinski } 147*839b92feSJakub Kicinski 148*839b92feSJakub Kicinski TEST_F(tun, reattach_delete_close) { 149*839b92feSJakub Kicinski EXPECT_EQ(tun_detach(self->fd, self->ifname), 0); 150*839b92feSJakub Kicinski EXPECT_EQ(tun_attach(self->fd, self->ifname), 0); 151*839b92feSJakub Kicinski EXPECT_EQ(tun_delete(self->ifname), 0); 152*839b92feSJakub Kicinski } 153*839b92feSJakub Kicinski 154*839b92feSJakub Kicinski TEST_F(tun, reattach_close_delete) { 155*839b92feSJakub Kicinski EXPECT_EQ(tun_detach(self->fd, self->ifname), 0); 156*839b92feSJakub Kicinski EXPECT_EQ(tun_attach(self->fd, self->ifname), 0); 157*839b92feSJakub Kicinski close(self->fd); 158*839b92feSJakub Kicinski self->fd = -1; 159*839b92feSJakub Kicinski EXPECT_EQ(tun_delete(self->ifname), 0); 160*839b92feSJakub Kicinski } 161*839b92feSJakub Kicinski 162*839b92feSJakub Kicinski TEST_HARNESS_MAIN 163