10ad011ecSGleb Smirnoff /*- 20ad011ecSGleb Smirnoff * SPDX-License-Identifier: BSD-2-Clause 30ad011ecSGleb Smirnoff * 40ad011ecSGleb Smirnoff * Copyright (c) 2023 Gleb Smirnoff <glebius@FreeBSD.org> 50ad011ecSGleb Smirnoff * 60ad011ecSGleb Smirnoff * Redistribution and use in source and binary forms, with or without 70ad011ecSGleb Smirnoff * modification, are permitted provided that the following conditions 80ad011ecSGleb Smirnoff * are met: 90ad011ecSGleb Smirnoff * 1. Redistributions of source code must retain the above copyright 100ad011ecSGleb Smirnoff * notice, this list of conditions and the following disclaimer. 110ad011ecSGleb Smirnoff * 2. Redistributions in binary form must reproduce the above copyright 120ad011ecSGleb Smirnoff * notice, this list of conditions and the following disclaimer in the 130ad011ecSGleb Smirnoff * documentation and/or other materials provided with the distribution. 140ad011ecSGleb Smirnoff * 150ad011ecSGleb Smirnoff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 160ad011ecSGleb Smirnoff * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 170ad011ecSGleb Smirnoff * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 180ad011ecSGleb Smirnoff * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 190ad011ecSGleb Smirnoff * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 200ad011ecSGleb Smirnoff * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 210ad011ecSGleb Smirnoff * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 220ad011ecSGleb Smirnoff * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 230ad011ecSGleb Smirnoff * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 240ad011ecSGleb Smirnoff * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 250ad011ecSGleb Smirnoff * SUCH DAMAGE. 260ad011ecSGleb Smirnoff */ 270ad011ecSGleb Smirnoff 280ad011ecSGleb Smirnoff #include <sys/param.h> 290ad011ecSGleb Smirnoff #include <sys/ioctl.h> 300ad011ecSGleb Smirnoff #include <sys/time.h> 310ad011ecSGleb Smirnoff #include <sys/socket.h> 320ad011ecSGleb Smirnoff #include <sys/module.h> 330ad011ecSGleb Smirnoff #include <errno.h> 340ad011ecSGleb Smirnoff #include <fcntl.h> 350ad011ecSGleb Smirnoff #include <signal.h> 360ad011ecSGleb Smirnoff #include <stdlib.h> 370ad011ecSGleb Smirnoff #include <unistd.h> 380ad011ecSGleb Smirnoff 390ad011ecSGleb Smirnoff #include <netlink/netlink.h> 400ad011ecSGleb Smirnoff #include <netlink/netlink_route.h> 410ad011ecSGleb Smirnoff 42*8338ea1dSGleb Smirnoff #include <netinet/in.h> 43*8338ea1dSGleb Smirnoff #include <arpa/inet.h> 44*8338ea1dSGleb Smirnoff 450ad011ecSGleb Smirnoff #include <atf-c.h> 460ad011ecSGleb Smirnoff 470ad011ecSGleb Smirnoff static struct itimerval itv = { 480ad011ecSGleb Smirnoff .it_interval = { 0, 0 }, 490ad011ecSGleb Smirnoff .it_value = { 1, 0 }, /* one second */ 500ad011ecSGleb Smirnoff }; 510ad011ecSGleb Smirnoff static sig_atomic_t timer_done = 0; 520ad011ecSGleb Smirnoff static void 530ad011ecSGleb Smirnoff sigalarm(int sig __unused) 540ad011ecSGleb Smirnoff { 550ad011ecSGleb Smirnoff 560ad011ecSGleb Smirnoff timer_done = 1; 570ad011ecSGleb Smirnoff } 580ad011ecSGleb Smirnoff 590ad011ecSGleb Smirnoff static struct sigaction sigact = { 600ad011ecSGleb Smirnoff .sa_handler = sigalarm, 610ad011ecSGleb Smirnoff }; 620ad011ecSGleb Smirnoff 630ad011ecSGleb Smirnoff static struct nlmsghdr hdr = (struct nlmsghdr) { 640ad011ecSGleb Smirnoff .nlmsg_type = RTM_GETLINK, 650ad011ecSGleb Smirnoff .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK, 660ad011ecSGleb Smirnoff .nlmsg_len = sizeof(struct nlmsghdr), 670ad011ecSGleb Smirnoff }; 680ad011ecSGleb Smirnoff 690ad011ecSGleb Smirnoff #define BUFLEN 1000 700ad011ecSGleb Smirnoff 710ad011ecSGleb Smirnoff static int 720ad011ecSGleb Smirnoff fullsocket(void) 730ad011ecSGleb Smirnoff { 740ad011ecSGleb Smirnoff char buf[BUFLEN]; 750ad011ecSGleb Smirnoff socklen_t slen = sizeof(int); 760ad011ecSGleb Smirnoff int fd, sendspace, recvspace, sendavail, recvavail, rsize; 770ad011ecSGleb Smirnoff u_int cnt = 0; 780ad011ecSGleb Smirnoff 790ad011ecSGleb Smirnoff ATF_REQUIRE((fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) != -1); 800ad011ecSGleb Smirnoff ATF_REQUIRE(getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sendspace, 810ad011ecSGleb Smirnoff &slen) == 0); 820ad011ecSGleb Smirnoff ATF_REQUIRE(getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &recvspace, 830ad011ecSGleb Smirnoff &slen) == 0); 840ad011ecSGleb Smirnoff 850ad011ecSGleb Smirnoff /* Check the expected size of reply on a single RTM_GETLINK. */ 860ad011ecSGleb Smirnoff ATF_REQUIRE(send(fd, &hdr, sizeof(hdr), 0) == sizeof(hdr)); 870ad011ecSGleb Smirnoff ATF_REQUIRE(recv(fd, buf, sizeof(hdr), MSG_WAITALL | MSG_PEEK) == 880ad011ecSGleb Smirnoff sizeof(hdr)); 890ad011ecSGleb Smirnoff ATF_REQUIRE(ioctl(fd, FIONREAD, &rsize) != -1); 900ad011ecSGleb Smirnoff 910ad011ecSGleb Smirnoff 920ad011ecSGleb Smirnoff /* 930ad011ecSGleb Smirnoff * Flood the socket with requests, without reading out the replies. 940ad011ecSGleb Smirnoff * While we are flooding, the kernel tries to process the requests. 950ad011ecSGleb Smirnoff * Kernel takes off requests from the send buffer and puts replies 960ad011ecSGleb Smirnoff * on receive buffer. Once the receive buffer is full it stops working 970ad011ecSGleb Smirnoff * on queue in the send buffer. At this point we must get a solid 980ad011ecSGleb Smirnoff * failure. However, if we flood faster than kernel taskqueue runs, 990ad011ecSGleb Smirnoff * we may get intermittent failures. 1000ad011ecSGleb Smirnoff */ 1010ad011ecSGleb Smirnoff do { 1020ad011ecSGleb Smirnoff ssize_t rv; 1030ad011ecSGleb Smirnoff 1040ad011ecSGleb Smirnoff rv = send(fd, &hdr, sizeof(hdr), MSG_DONTWAIT); 1050ad011ecSGleb Smirnoff if (__predict_true(rv == sizeof(hdr))) 1060ad011ecSGleb Smirnoff cnt++; 1070ad011ecSGleb Smirnoff else { 1080ad011ecSGleb Smirnoff ATF_REQUIRE(errno == EAGAIN); 1090ad011ecSGleb Smirnoff ATF_REQUIRE(sizeof(hdr) * cnt > sendspace); 1100ad011ecSGleb Smirnoff } 1110ad011ecSGleb Smirnoff ATF_REQUIRE(ioctl(fd, FIONREAD, &recvavail) != -1); 1120ad011ecSGleb Smirnoff ATF_REQUIRE(ioctl(fd, FIONWRITE, &sendavail) != -1); 1130ad011ecSGleb Smirnoff } while (recvavail <= recvspace - rsize || 1140ad011ecSGleb Smirnoff sendavail <= sendspace - sizeof(hdr)); 1150ad011ecSGleb Smirnoff 1160ad011ecSGleb Smirnoff return (fd); 1170ad011ecSGleb Smirnoff } 1180ad011ecSGleb Smirnoff 1190ad011ecSGleb Smirnoff ATF_TC_WITHOUT_HEAD(overflow); 1200ad011ecSGleb Smirnoff ATF_TC_BODY(overflow, tc) 1210ad011ecSGleb Smirnoff { 1220ad011ecSGleb Smirnoff char buf[BUFLEN]; 1230ad011ecSGleb Smirnoff int fd; 1240ad011ecSGleb Smirnoff 1250ad011ecSGleb Smirnoff fd = fullsocket(); 1260ad011ecSGleb Smirnoff 1270ad011ecSGleb Smirnoff /* Both buffers full: block. */ 1280ad011ecSGleb Smirnoff timer_done = 0; 1290ad011ecSGleb Smirnoff ATF_REQUIRE(sigaction(SIGALRM, &sigact, NULL) == 0); 1300ad011ecSGleb Smirnoff ATF_REQUIRE(setitimer(ITIMER_REAL, &itv, NULL) == 0); 1310ad011ecSGleb Smirnoff ATF_REQUIRE(send(fd, &hdr, sizeof(hdr), 0) == -1); 1320ad011ecSGleb Smirnoff ATF_REQUIRE(errno == EINTR); 1330ad011ecSGleb Smirnoff ATF_REQUIRE(timer_done == 1); 1340ad011ecSGleb Smirnoff 1350ad011ecSGleb Smirnoff /* 1360ad011ecSGleb Smirnoff * Now, reading something from the receive buffer should wake up the 1370ad011ecSGleb Smirnoff * taskqueue and send buffer should start getting drained. 1380ad011ecSGleb Smirnoff */ 1390ad011ecSGleb Smirnoff ATF_REQUIRE(recv(fd, buf, BUFLEN, 0) > sizeof(hdr)); 1400ad011ecSGleb Smirnoff timer_done = 0; 1410ad011ecSGleb Smirnoff ATF_REQUIRE(setitimer(ITIMER_REAL, &itv, NULL) == 0); 1420ad011ecSGleb Smirnoff ATF_REQUIRE(send(fd, &hdr, sizeof(hdr), 0) == sizeof(hdr)); 1430ad011ecSGleb Smirnoff ATF_REQUIRE(timer_done == 0); 1440ad011ecSGleb Smirnoff } 1450ad011ecSGleb Smirnoff 1460ad011ecSGleb Smirnoff ATF_TC_WITHOUT_HEAD(peek); 1470ad011ecSGleb Smirnoff ATF_TC_BODY(peek, tc) 1480ad011ecSGleb Smirnoff { 1490ad011ecSGleb Smirnoff char *buf; 1500ad011ecSGleb Smirnoff ssize_t ss, ss1; 1510ad011ecSGleb Smirnoff int fd; 1520ad011ecSGleb Smirnoff 1530ad011ecSGleb Smirnoff ATF_REQUIRE((fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) != -1); 1540ad011ecSGleb Smirnoff 1550ad011ecSGleb Smirnoff ATF_REQUIRE(send(fd, &hdr, sizeof(hdr), 0) == sizeof(hdr)); 1560ad011ecSGleb Smirnoff ss = recv(fd, buf, 0, MSG_WAITALL | MSG_PEEK | MSG_TRUNC); 1570ad011ecSGleb Smirnoff ATF_REQUIRE((buf = malloc(ss)) != NULL); 1580ad011ecSGleb Smirnoff ATF_REQUIRE(recv(fd, buf, ss, MSG_WAITALL) == ss); 1590ad011ecSGleb Smirnoff } 1600ad011ecSGleb Smirnoff 1610ad011ecSGleb Smirnoff struct nl_control { 1620ad011ecSGleb Smirnoff struct nlattr nla; 1630ad011ecSGleb Smirnoff uint32_t val; 1640ad011ecSGleb Smirnoff }; 1650ad011ecSGleb Smirnoff 1660ad011ecSGleb Smirnoff static void 1670ad011ecSGleb Smirnoff cmsg_check(struct msghdr *msg) 1680ad011ecSGleb Smirnoff { 1690ad011ecSGleb Smirnoff static pid_t pid = 0; 1700ad011ecSGleb Smirnoff struct cmsghdr *cmsg; 1710ad011ecSGleb Smirnoff struct nl_control *nlc; 1720ad011ecSGleb Smirnoff 1730ad011ecSGleb Smirnoff ATF_REQUIRE((cmsg = CMSG_FIRSTHDR(msg)) != NULL); 1740ad011ecSGleb Smirnoff ATF_REQUIRE(cmsg->cmsg_level == SOL_NETLINK); 1750ad011ecSGleb Smirnoff ATF_REQUIRE(cmsg->cmsg_type == NETLINK_MSG_INFO); 1760ad011ecSGleb Smirnoff nlc = (struct nl_control *)CMSG_DATA(cmsg); 1770ad011ecSGleb Smirnoff ATF_REQUIRE(nlc[0].nla.nla_type == NLMSGINFO_ATTR_PROCESS_ID); 1780ad011ecSGleb Smirnoff if (pid == 0) 1790ad011ecSGleb Smirnoff pid = getpid(); 1800ad011ecSGleb Smirnoff ATF_REQUIRE(nlc[0].val == pid); 1810ad011ecSGleb Smirnoff ATF_REQUIRE(nlc[1].nla.nla_type == NLMSGINFO_ATTR_PORT_ID); 1820ad011ecSGleb Smirnoff /* XXX need another test to test port id */ 1830ad011ecSGleb Smirnoff ATF_REQUIRE(nlc[1].val == 0); 1840ad011ecSGleb Smirnoff ATF_REQUIRE(CMSG_NXTHDR(msg, cmsg) == NULL); 1850ad011ecSGleb Smirnoff ATF_REQUIRE((msg->msg_flags & MSG_CTRUNC) == 0); 1860ad011ecSGleb Smirnoff } 1870ad011ecSGleb Smirnoff 1880ad011ecSGleb Smirnoff ATF_TC_WITHOUT_HEAD(sizes); 1890ad011ecSGleb Smirnoff ATF_TC_BODY(sizes, tc) 1900ad011ecSGleb Smirnoff { 1910ad011ecSGleb Smirnoff #define NLMSG_LARGE 2048 /* XXX: match kernel nl_buf */ 1920ad011ecSGleb Smirnoff char buf[NLMSG_LARGE * 10]; 1930ad011ecSGleb Smirnoff char cbuf[CMSG_SPACE(sizeof(struct nl_control) * 2)]; 1940ad011ecSGleb Smirnoff struct iovec iov; 1950ad011ecSGleb Smirnoff struct msghdr msg = { 1960ad011ecSGleb Smirnoff .msg_iov = &iov, 1970ad011ecSGleb Smirnoff .msg_iovlen = 1, 1980ad011ecSGleb Smirnoff .msg_control = cbuf, 1990ad011ecSGleb Smirnoff .msg_controllen = sizeof(cbuf), 2000ad011ecSGleb Smirnoff }; 2010ad011ecSGleb Smirnoff ssize_t ss; 2020ad011ecSGleb Smirnoff int fd, size, rsize; 2030ad011ecSGleb Smirnoff 2040ad011ecSGleb Smirnoff fd = fullsocket(); 2050ad011ecSGleb Smirnoff 2060ad011ecSGleb Smirnoff /* 2070ad011ecSGleb Smirnoff * Set NETLINK_MSG_INFO, so that later cmsg_check will check that any 2080ad011ecSGleb Smirnoff * read is accompanied with control data. 2090ad011ecSGleb Smirnoff */ 2100ad011ecSGleb Smirnoff ATF_REQUIRE(setsockopt(fd, SOL_NETLINK, NETLINK_MSG_INFO, 2110ad011ecSGleb Smirnoff &(int){1}, sizeof(int)) == 0); 2120ad011ecSGleb Smirnoff 2130ad011ecSGleb Smirnoff iov = (struct iovec ){ 2140ad011ecSGleb Smirnoff .iov_base = &hdr, 2150ad011ecSGleb Smirnoff .iov_len = sizeof(hdr), 2160ad011ecSGleb Smirnoff }; 2170ad011ecSGleb Smirnoff /* Obtain size of the first message in the socket. */ 2180ad011ecSGleb Smirnoff ss = recvmsg(fd, &msg, MSG_WAITALL | MSG_PEEK | MSG_TRUNC); 2190ad011ecSGleb Smirnoff ATF_REQUIRE(ss == hdr.nlmsg_len); 2200ad011ecSGleb Smirnoff /* And overall amount of data in the socket. */ 2210ad011ecSGleb Smirnoff ATF_REQUIRE(ioctl(fd, FIONREAD, &rsize) != -1); 2220ad011ecSGleb Smirnoff cmsg_check(&msg); 2230ad011ecSGleb Smirnoff 2240ad011ecSGleb Smirnoff /* Zero-sized read should not affect state of the socket buffer. */ 2250ad011ecSGleb Smirnoff ATF_REQUIRE(recv(fd, buf, 0, 0) == 0); 2260ad011ecSGleb Smirnoff ATF_REQUIRE(ioctl(fd, FIONREAD, &size) != -1); 2270ad011ecSGleb Smirnoff ATF_REQUIRE(size == rsize); 2280ad011ecSGleb Smirnoff 2290ad011ecSGleb Smirnoff /* 2300ad011ecSGleb Smirnoff * Undersized read should lose a message. This isn't exactly 2310ad011ecSGleb Smirnoff * pronounced in the Netlink RFC, but it always says that Netlink 2320ad011ecSGleb Smirnoff * socket is an analog of the BSD routing socket, and this is how 2330ad011ecSGleb Smirnoff * a route(4) socket deals with undersized read. 2340ad011ecSGleb Smirnoff */ 2350ad011ecSGleb Smirnoff iov = (struct iovec ){ 2360ad011ecSGleb Smirnoff .iov_base = buf, 2370ad011ecSGleb Smirnoff .iov_len = sizeof(hdr), 2380ad011ecSGleb Smirnoff }; 2390ad011ecSGleb Smirnoff ATF_REQUIRE(recvmsg(fd, &msg, 0) == sizeof(hdr)); 2400ad011ecSGleb Smirnoff ATF_REQUIRE(msg.msg_flags & MSG_TRUNC); 2410ad011ecSGleb Smirnoff ATF_REQUIRE(hdr.nlmsg_len > sizeof(hdr)); 2420ad011ecSGleb Smirnoff size = rsize - hdr.nlmsg_len; 2430ad011ecSGleb Smirnoff ATF_REQUIRE(ioctl(fd, FIONREAD, &rsize) != -1); 2440ad011ecSGleb Smirnoff ATF_REQUIRE(size == rsize); 2450ad011ecSGleb Smirnoff cmsg_check(&msg); 2460ad011ecSGleb Smirnoff 2470ad011ecSGleb Smirnoff /* 2480ad011ecSGleb Smirnoff * Large read should span several nl_bufs, seeing no boundaries. 2490ad011ecSGleb Smirnoff */ 2500ad011ecSGleb Smirnoff iov = (struct iovec ){ 2510ad011ecSGleb Smirnoff .iov_base = buf, 2520ad011ecSGleb Smirnoff .iov_len = sizeof(buf) < rsize ? sizeof(buf) : rsize, 2530ad011ecSGleb Smirnoff }; 2540ad011ecSGleb Smirnoff ss = recvmsg(fd, &msg, 0); 2550ad011ecSGleb Smirnoff ATF_REQUIRE(ss > NLMSG_LARGE * 9 || ss == rsize); 2560ad011ecSGleb Smirnoff cmsg_check(&msg); 2570ad011ecSGleb Smirnoff } 2580ad011ecSGleb Smirnoff 259*8338ea1dSGleb Smirnoff /* 260*8338ea1dSGleb Smirnoff * Check that NETLINK_ADD_MEMBERSHIP subscribes us. Add & delete a temporary 261*8338ea1dSGleb Smirnoff * route and check if announcements came in. 262*8338ea1dSGleb Smirnoff */ 263*8338ea1dSGleb Smirnoff ATF_TC_WITHOUT_HEAD(membership); 264*8338ea1dSGleb Smirnoff ATF_TC_BODY(membership, tc) 265*8338ea1dSGleb Smirnoff { 266*8338ea1dSGleb Smirnoff struct { 267*8338ea1dSGleb Smirnoff struct nlmsghdr hdr; 268*8338ea1dSGleb Smirnoff struct rtmsg rtm; 269*8338ea1dSGleb Smirnoff struct nlattr rta_dst; 270*8338ea1dSGleb Smirnoff struct in_addr dst; 271*8338ea1dSGleb Smirnoff struct nlattr rta_oif; 272*8338ea1dSGleb Smirnoff uint32_t oif; 273*8338ea1dSGleb Smirnoff } msg = { 274*8338ea1dSGleb Smirnoff .hdr.nlmsg_type = RTM_NEWROUTE, 275*8338ea1dSGleb Smirnoff .hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL, 276*8338ea1dSGleb Smirnoff .hdr.nlmsg_len = sizeof(msg), 277*8338ea1dSGleb Smirnoff .rtm.rtm_family = AF_INET, 278*8338ea1dSGleb Smirnoff .rtm.rtm_protocol = RTPROT_STATIC, 279*8338ea1dSGleb Smirnoff .rtm.rtm_type = RTN_UNICAST, 280*8338ea1dSGleb Smirnoff .rtm.rtm_dst_len = 32, 281*8338ea1dSGleb Smirnoff .rta_dst.nla_type = RTA_DST, 282*8338ea1dSGleb Smirnoff .rta_dst.nla_len = sizeof(struct in_addr) + 283*8338ea1dSGleb Smirnoff sizeof(struct nlattr), 284*8338ea1dSGleb Smirnoff .dst.s_addr = inet_addr("127.0.0.127"), 285*8338ea1dSGleb Smirnoff .rta_oif.nla_type = RTA_OIF, 286*8338ea1dSGleb Smirnoff .rta_oif.nla_len = sizeof(uint32_t) + sizeof(struct nlattr), 287*8338ea1dSGleb Smirnoff .oif = 1, 288*8338ea1dSGleb Smirnoff }; 289*8338ea1dSGleb Smirnoff int fd; 290*8338ea1dSGleb Smirnoff 291*8338ea1dSGleb Smirnoff ATF_REQUIRE((fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) != -1); 292*8338ea1dSGleb Smirnoff ATF_REQUIRE(setsockopt(fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, 293*8338ea1dSGleb Smirnoff &(int){RTNLGRP_IPV4_ROUTE}, sizeof(int)) == 0); 294*8338ea1dSGleb Smirnoff ATF_REQUIRE(send(fd, &msg, sizeof(msg), 0) == sizeof(msg)); 295*8338ea1dSGleb Smirnoff msg.hdr.nlmsg_type = RTM_DELROUTE; 296*8338ea1dSGleb Smirnoff msg.hdr.nlmsg_len -= sizeof(struct nlattr) + sizeof(uint32_t); 297*8338ea1dSGleb Smirnoff ATF_REQUIRE(send(fd, &msg, msg.hdr.nlmsg_len, 0) == msg.hdr.nlmsg_len); 298*8338ea1dSGleb Smirnoff ATF_REQUIRE(recv(fd, &msg, sizeof(msg), 0) == sizeof(msg)); 299*8338ea1dSGleb Smirnoff ATF_REQUIRE(msg.hdr.nlmsg_type == RTM_NEWROUTE); 300*8338ea1dSGleb Smirnoff ATF_REQUIRE(recv(fd, &msg, sizeof(msg), 0) == sizeof(msg)); 301*8338ea1dSGleb Smirnoff ATF_REQUIRE(msg.hdr.nlmsg_type == RTM_DELROUTE); 302*8338ea1dSGleb Smirnoff } 303*8338ea1dSGleb Smirnoff 3040ad011ecSGleb Smirnoff ATF_TP_ADD_TCS(tp) 3050ad011ecSGleb Smirnoff { 3060ad011ecSGleb Smirnoff if (modfind("netlink") == -1) 3070ad011ecSGleb Smirnoff atf_tc_skip("netlink module not loaded"); 3080ad011ecSGleb Smirnoff 3090ad011ecSGleb Smirnoff ATF_TP_ADD_TC(tp, overflow); 3100ad011ecSGleb Smirnoff ATF_TP_ADD_TC(tp, peek); 3110ad011ecSGleb Smirnoff ATF_TP_ADD_TC(tp, sizes); 312*8338ea1dSGleb Smirnoff ATF_TP_ADD_TC(tp, membership); 3130ad011ecSGleb Smirnoff 3140ad011ecSGleb Smirnoff return (atf_no_error()); 3150ad011ecSGleb Smirnoff } 316