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