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