1*d07d7c3dSDanielle Ratson // SPDX-License-Identifier: GPL-2.0 2*d07d7c3dSDanielle Ratson 3*d07d7c3dSDanielle Ratson #include <arpa/inet.h> 4*d07d7c3dSDanielle Ratson #include <error.h> 5*d07d7c3dSDanielle Ratson #include <linux/errqueue.h> 6*d07d7c3dSDanielle Ratson #include <linux/icmp.h> 7*d07d7c3dSDanielle Ratson #include <linux/icmpv6.h> 8*d07d7c3dSDanielle Ratson #include <linux/in6.h> 9*d07d7c3dSDanielle Ratson #include <linux/ip.h> 10*d07d7c3dSDanielle Ratson #include <linux/ipv6.h> 11*d07d7c3dSDanielle Ratson #include <netinet/in.h> 12*d07d7c3dSDanielle Ratson #include <netinet/udp.h> 13*d07d7c3dSDanielle Ratson #include <poll.h> 14*d07d7c3dSDanielle Ratson #include <sched.h> 15*d07d7c3dSDanielle Ratson #include <stdbool.h> 16*d07d7c3dSDanielle Ratson #include <stdint.h> 17*d07d7c3dSDanielle Ratson #include <stdio.h> 18*d07d7c3dSDanielle Ratson #include <stdlib.h> 19*d07d7c3dSDanielle Ratson #include <sys/ioctl.h> 20*d07d7c3dSDanielle Ratson #include <sys/socket.h> 21*d07d7c3dSDanielle Ratson 22*d07d7c3dSDanielle Ratson #include "../kselftest_harness.h" 23*d07d7c3dSDanielle Ratson 24*d07d7c3dSDanielle Ratson static const unsigned short src_port = 44444; 25*d07d7c3dSDanielle Ratson static const unsigned short dst_port = 55555; 26*d07d7c3dSDanielle Ratson static const int min_orig_dgram_len = 128; 27*d07d7c3dSDanielle Ratson static const int min_payload_len_v4 = 28*d07d7c3dSDanielle Ratson min_orig_dgram_len - sizeof(struct iphdr) - sizeof(struct udphdr); 29*d07d7c3dSDanielle Ratson static const int min_payload_len_v6 = 30*d07d7c3dSDanielle Ratson min_orig_dgram_len - sizeof(struct ipv6hdr) - sizeof(struct udphdr); 31*d07d7c3dSDanielle Ratson static const uint8_t orig_payload_byte = 0xAA; 32*d07d7c3dSDanielle Ratson 33*d07d7c3dSDanielle Ratson struct sockaddr_inet { 34*d07d7c3dSDanielle Ratson union { 35*d07d7c3dSDanielle Ratson struct sockaddr_in6 v6; 36*d07d7c3dSDanielle Ratson struct sockaddr_in v4; 37*d07d7c3dSDanielle Ratson struct sockaddr sa; 38*d07d7c3dSDanielle Ratson }; 39*d07d7c3dSDanielle Ratson socklen_t len; 40*d07d7c3dSDanielle Ratson }; 41*d07d7c3dSDanielle Ratson 42*d07d7c3dSDanielle Ratson struct ip_case_info { 43*d07d7c3dSDanielle Ratson int domain; 44*d07d7c3dSDanielle Ratson int level; 45*d07d7c3dSDanielle Ratson int opt1; 46*d07d7c3dSDanielle Ratson int opt2; 47*d07d7c3dSDanielle Ratson int proto; 48*d07d7c3dSDanielle Ratson int (*build_func)(uint8_t *buf, ssize_t buflen, bool with_ext, 49*d07d7c3dSDanielle Ratson int payload_len, bool bad_csum, bool bad_len, 50*d07d7c3dSDanielle Ratson bool smaller_len); 51*d07d7c3dSDanielle Ratson int min_payload; 52*d07d7c3dSDanielle Ratson }; 53*d07d7c3dSDanielle Ratson 54*d07d7c3dSDanielle Ratson static int bringup_loopback(void) 55*d07d7c3dSDanielle Ratson { 56*d07d7c3dSDanielle Ratson struct ifreq ifr = { 57*d07d7c3dSDanielle Ratson .ifr_name = "lo" 58*d07d7c3dSDanielle Ratson }; 59*d07d7c3dSDanielle Ratson int fd; 60*d07d7c3dSDanielle Ratson 61*d07d7c3dSDanielle Ratson fd = socket(AF_INET, SOCK_DGRAM, 0); 62*d07d7c3dSDanielle Ratson if (fd < 0) 63*d07d7c3dSDanielle Ratson return -1; 64*d07d7c3dSDanielle Ratson 65*d07d7c3dSDanielle Ratson if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) 66*d07d7c3dSDanielle Ratson goto err; 67*d07d7c3dSDanielle Ratson 68*d07d7c3dSDanielle Ratson ifr.ifr_flags = ifr.ifr_flags | IFF_UP; 69*d07d7c3dSDanielle Ratson 70*d07d7c3dSDanielle Ratson if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) 71*d07d7c3dSDanielle Ratson goto err; 72*d07d7c3dSDanielle Ratson 73*d07d7c3dSDanielle Ratson close(fd); 74*d07d7c3dSDanielle Ratson return 0; 75*d07d7c3dSDanielle Ratson 76*d07d7c3dSDanielle Ratson err: 77*d07d7c3dSDanielle Ratson close(fd); 78*d07d7c3dSDanielle Ratson return -1; 79*d07d7c3dSDanielle Ratson } 80*d07d7c3dSDanielle Ratson 81*d07d7c3dSDanielle Ratson static uint16_t csum(const void *buf, size_t len) 82*d07d7c3dSDanielle Ratson { 83*d07d7c3dSDanielle Ratson const uint8_t *data = buf; 84*d07d7c3dSDanielle Ratson uint32_t sum = 0; 85*d07d7c3dSDanielle Ratson 86*d07d7c3dSDanielle Ratson while (len > 1) { 87*d07d7c3dSDanielle Ratson sum += (data[0] << 8) | data[1]; 88*d07d7c3dSDanielle Ratson data += 2; 89*d07d7c3dSDanielle Ratson len -= 2; 90*d07d7c3dSDanielle Ratson } 91*d07d7c3dSDanielle Ratson 92*d07d7c3dSDanielle Ratson if (len == 1) 93*d07d7c3dSDanielle Ratson sum += data[0] << 8; 94*d07d7c3dSDanielle Ratson 95*d07d7c3dSDanielle Ratson while (sum >> 16) 96*d07d7c3dSDanielle Ratson sum = (sum & 0xFFFF) + (sum >> 16); 97*d07d7c3dSDanielle Ratson 98*d07d7c3dSDanielle Ratson return ~sum & 0xFFFF; 99*d07d7c3dSDanielle Ratson } 100*d07d7c3dSDanielle Ratson 101*d07d7c3dSDanielle Ratson static int poll_err(int fd) 102*d07d7c3dSDanielle Ratson { 103*d07d7c3dSDanielle Ratson struct pollfd pfd; 104*d07d7c3dSDanielle Ratson 105*d07d7c3dSDanielle Ratson memset(&pfd, 0, sizeof(pfd)); 106*d07d7c3dSDanielle Ratson pfd.fd = fd; 107*d07d7c3dSDanielle Ratson 108*d07d7c3dSDanielle Ratson if (poll(&pfd, 1, 5000) != 1 || pfd.revents != POLLERR) 109*d07d7c3dSDanielle Ratson return -1; 110*d07d7c3dSDanielle Ratson 111*d07d7c3dSDanielle Ratson return 0; 112*d07d7c3dSDanielle Ratson } 113*d07d7c3dSDanielle Ratson 114*d07d7c3dSDanielle Ratson static void set_addr(struct sockaddr_inet *addr, int domain, 115*d07d7c3dSDanielle Ratson unsigned short port) 116*d07d7c3dSDanielle Ratson { 117*d07d7c3dSDanielle Ratson memset(addr, 0, sizeof(*addr)); 118*d07d7c3dSDanielle Ratson 119*d07d7c3dSDanielle Ratson switch (domain) { 120*d07d7c3dSDanielle Ratson case AF_INET: 121*d07d7c3dSDanielle Ratson addr->v4.sin_family = AF_INET; 122*d07d7c3dSDanielle Ratson addr->v4.sin_port = htons(port); 123*d07d7c3dSDanielle Ratson addr->v4.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 124*d07d7c3dSDanielle Ratson addr->len = sizeof(addr->v4); 125*d07d7c3dSDanielle Ratson break; 126*d07d7c3dSDanielle Ratson case AF_INET6: 127*d07d7c3dSDanielle Ratson addr->v6.sin6_family = AF_INET6; 128*d07d7c3dSDanielle Ratson addr->v6.sin6_port = htons(port); 129*d07d7c3dSDanielle Ratson addr->v6.sin6_addr = in6addr_loopback; 130*d07d7c3dSDanielle Ratson addr->len = sizeof(addr->v6); 131*d07d7c3dSDanielle Ratson break; 132*d07d7c3dSDanielle Ratson } 133*d07d7c3dSDanielle Ratson } 134*d07d7c3dSDanielle Ratson 135*d07d7c3dSDanielle Ratson static int bind_and_setsockopt(int fd, const struct ip_case_info *info) 136*d07d7c3dSDanielle Ratson { 137*d07d7c3dSDanielle Ratson struct sockaddr_inet addr; 138*d07d7c3dSDanielle Ratson int opt = 1; 139*d07d7c3dSDanielle Ratson 140*d07d7c3dSDanielle Ratson set_addr(&addr, info->domain, src_port); 141*d07d7c3dSDanielle Ratson 142*d07d7c3dSDanielle Ratson if (setsockopt(fd, info->level, info->opt1, &opt, sizeof(opt)) < 0) 143*d07d7c3dSDanielle Ratson return -1; 144*d07d7c3dSDanielle Ratson 145*d07d7c3dSDanielle Ratson if (setsockopt(fd, info->level, info->opt2, &opt, sizeof(opt)) < 0) 146*d07d7c3dSDanielle Ratson return -1; 147*d07d7c3dSDanielle Ratson 148*d07d7c3dSDanielle Ratson return bind(fd, &addr.sa, addr.len); 149*d07d7c3dSDanielle Ratson } 150*d07d7c3dSDanielle Ratson 151*d07d7c3dSDanielle Ratson static int build_rfc4884_ext(uint8_t *buf, size_t buflen, bool bad_csum, 152*d07d7c3dSDanielle Ratson bool bad_len, bool smaller_len) 153*d07d7c3dSDanielle Ratson { 154*d07d7c3dSDanielle Ratson struct icmp_extobj_hdr *objh; 155*d07d7c3dSDanielle Ratson struct icmp_ext_hdr *exthdr; 156*d07d7c3dSDanielle Ratson size_t obj_len, ext_len; 157*d07d7c3dSDanielle Ratson uint16_t sum; 158*d07d7c3dSDanielle Ratson 159*d07d7c3dSDanielle Ratson /* Use an object payload of 4 bytes */ 160*d07d7c3dSDanielle Ratson obj_len = sizeof(*objh) + sizeof(uint32_t); 161*d07d7c3dSDanielle Ratson ext_len = sizeof(*exthdr) + obj_len; 162*d07d7c3dSDanielle Ratson 163*d07d7c3dSDanielle Ratson if (ext_len > buflen) 164*d07d7c3dSDanielle Ratson return -EINVAL; 165*d07d7c3dSDanielle Ratson 166*d07d7c3dSDanielle Ratson exthdr = (struct icmp_ext_hdr *)buf; 167*d07d7c3dSDanielle Ratson objh = (struct icmp_extobj_hdr *)(buf + sizeof(*exthdr)); 168*d07d7c3dSDanielle Ratson 169*d07d7c3dSDanielle Ratson exthdr->version = 2; 170*d07d7c3dSDanielle Ratson /* When encoding a bad object length, either encode a length too small 171*d07d7c3dSDanielle Ratson * to fit the object header or too big to fit in the packet. 172*d07d7c3dSDanielle Ratson */ 173*d07d7c3dSDanielle Ratson if (bad_len) 174*d07d7c3dSDanielle Ratson obj_len = smaller_len ? sizeof(*objh) - 1 : obj_len * 2; 175*d07d7c3dSDanielle Ratson objh->length = htons(obj_len); 176*d07d7c3dSDanielle Ratson 177*d07d7c3dSDanielle Ratson sum = csum(buf, ext_len); 178*d07d7c3dSDanielle Ratson exthdr->checksum = htons(bad_csum ? sum - 1 : sum); 179*d07d7c3dSDanielle Ratson 180*d07d7c3dSDanielle Ratson return ext_len; 181*d07d7c3dSDanielle Ratson } 182*d07d7c3dSDanielle Ratson 183*d07d7c3dSDanielle Ratson static int build_orig_dgram_v4(uint8_t *buf, ssize_t buflen, int payload_len) 184*d07d7c3dSDanielle Ratson { 185*d07d7c3dSDanielle Ratson struct udphdr *udph; 186*d07d7c3dSDanielle Ratson struct iphdr *iph; 187*d07d7c3dSDanielle Ratson size_t len = 0; 188*d07d7c3dSDanielle Ratson 189*d07d7c3dSDanielle Ratson len = sizeof(*iph) + sizeof(*udph) + payload_len; 190*d07d7c3dSDanielle Ratson if (len > buflen) 191*d07d7c3dSDanielle Ratson return -EINVAL; 192*d07d7c3dSDanielle Ratson 193*d07d7c3dSDanielle Ratson iph = (struct iphdr *)buf; 194*d07d7c3dSDanielle Ratson udph = (struct udphdr *)(buf + sizeof(*iph)); 195*d07d7c3dSDanielle Ratson 196*d07d7c3dSDanielle Ratson iph->version = 4; 197*d07d7c3dSDanielle Ratson iph->ihl = 5; 198*d07d7c3dSDanielle Ratson iph->protocol = IPPROTO_UDP; 199*d07d7c3dSDanielle Ratson iph->saddr = htonl(INADDR_LOOPBACK); 200*d07d7c3dSDanielle Ratson iph->daddr = htonl(INADDR_LOOPBACK); 201*d07d7c3dSDanielle Ratson iph->tot_len = htons(len); 202*d07d7c3dSDanielle Ratson iph->check = htons(csum(iph, sizeof(*iph))); 203*d07d7c3dSDanielle Ratson 204*d07d7c3dSDanielle Ratson udph->source = htons(src_port); 205*d07d7c3dSDanielle Ratson udph->dest = htons(dst_port); 206*d07d7c3dSDanielle Ratson udph->len = htons(sizeof(*udph) + payload_len); 207*d07d7c3dSDanielle Ratson 208*d07d7c3dSDanielle Ratson memset(buf + sizeof(*iph) + sizeof(*udph), orig_payload_byte, 209*d07d7c3dSDanielle Ratson payload_len); 210*d07d7c3dSDanielle Ratson 211*d07d7c3dSDanielle Ratson return len; 212*d07d7c3dSDanielle Ratson } 213*d07d7c3dSDanielle Ratson 214*d07d7c3dSDanielle Ratson static int build_orig_dgram_v6(uint8_t *buf, ssize_t buflen, int payload_len) 215*d07d7c3dSDanielle Ratson { 216*d07d7c3dSDanielle Ratson struct udphdr *udph; 217*d07d7c3dSDanielle Ratson struct ipv6hdr *iph; 218*d07d7c3dSDanielle Ratson size_t len = 0; 219*d07d7c3dSDanielle Ratson 220*d07d7c3dSDanielle Ratson len = sizeof(*iph) + sizeof(*udph) + payload_len; 221*d07d7c3dSDanielle Ratson if (len > buflen) 222*d07d7c3dSDanielle Ratson return -EINVAL; 223*d07d7c3dSDanielle Ratson 224*d07d7c3dSDanielle Ratson iph = (struct ipv6hdr *)buf; 225*d07d7c3dSDanielle Ratson udph = (struct udphdr *)(buf + sizeof(*iph)); 226*d07d7c3dSDanielle Ratson 227*d07d7c3dSDanielle Ratson iph->version = 6; 228*d07d7c3dSDanielle Ratson iph->payload_len = htons(sizeof(*udph) + payload_len); 229*d07d7c3dSDanielle Ratson iph->nexthdr = IPPROTO_UDP; 230*d07d7c3dSDanielle Ratson iph->saddr = in6addr_loopback; 231*d07d7c3dSDanielle Ratson iph->daddr = in6addr_loopback; 232*d07d7c3dSDanielle Ratson 233*d07d7c3dSDanielle Ratson udph->source = htons(src_port); 234*d07d7c3dSDanielle Ratson udph->dest = htons(dst_port); 235*d07d7c3dSDanielle Ratson udph->len = htons(sizeof(*udph) + payload_len); 236*d07d7c3dSDanielle Ratson 237*d07d7c3dSDanielle Ratson memset(buf + sizeof(*iph) + sizeof(*udph), orig_payload_byte, 238*d07d7c3dSDanielle Ratson payload_len); 239*d07d7c3dSDanielle Ratson 240*d07d7c3dSDanielle Ratson return len; 241*d07d7c3dSDanielle Ratson } 242*d07d7c3dSDanielle Ratson 243*d07d7c3dSDanielle Ratson static int build_icmpv4_pkt(uint8_t *buf, ssize_t buflen, bool with_ext, 244*d07d7c3dSDanielle Ratson int payload_len, bool bad_csum, bool bad_len, 245*d07d7c3dSDanielle Ratson bool smaller_len) 246*d07d7c3dSDanielle Ratson { 247*d07d7c3dSDanielle Ratson struct icmphdr *icmph; 248*d07d7c3dSDanielle Ratson int len, ret; 249*d07d7c3dSDanielle Ratson 250*d07d7c3dSDanielle Ratson len = sizeof(*icmph); 251*d07d7c3dSDanielle Ratson memset(buf, 0, buflen); 252*d07d7c3dSDanielle Ratson 253*d07d7c3dSDanielle Ratson icmph = (struct icmphdr *)buf; 254*d07d7c3dSDanielle Ratson icmph->type = ICMP_DEST_UNREACH; 255*d07d7c3dSDanielle Ratson icmph->code = ICMP_PORT_UNREACH; 256*d07d7c3dSDanielle Ratson icmph->checksum = 0; 257*d07d7c3dSDanielle Ratson 258*d07d7c3dSDanielle Ratson ret = build_orig_dgram_v4(buf + len, buflen - len, payload_len); 259*d07d7c3dSDanielle Ratson if (ret < 0) 260*d07d7c3dSDanielle Ratson return ret; 261*d07d7c3dSDanielle Ratson 262*d07d7c3dSDanielle Ratson len += ret; 263*d07d7c3dSDanielle Ratson 264*d07d7c3dSDanielle Ratson icmph->un.reserved[1] = (len - sizeof(*icmph)) / sizeof(uint32_t); 265*d07d7c3dSDanielle Ratson 266*d07d7c3dSDanielle Ratson if (with_ext) { 267*d07d7c3dSDanielle Ratson ret = build_rfc4884_ext(buf + len, buflen - len, 268*d07d7c3dSDanielle Ratson bad_csum, bad_len, smaller_len); 269*d07d7c3dSDanielle Ratson if (ret < 0) 270*d07d7c3dSDanielle Ratson return ret; 271*d07d7c3dSDanielle Ratson 272*d07d7c3dSDanielle Ratson len += ret; 273*d07d7c3dSDanielle Ratson } 274*d07d7c3dSDanielle Ratson 275*d07d7c3dSDanielle Ratson icmph->checksum = htons(csum(icmph, len)); 276*d07d7c3dSDanielle Ratson return len; 277*d07d7c3dSDanielle Ratson } 278*d07d7c3dSDanielle Ratson 279*d07d7c3dSDanielle Ratson static int build_icmpv6_pkt(uint8_t *buf, ssize_t buflen, bool with_ext, 280*d07d7c3dSDanielle Ratson int payload_len, bool bad_csum, bool bad_len, 281*d07d7c3dSDanielle Ratson bool smaller_len) 282*d07d7c3dSDanielle Ratson { 283*d07d7c3dSDanielle Ratson struct icmp6hdr *icmph; 284*d07d7c3dSDanielle Ratson int len, ret; 285*d07d7c3dSDanielle Ratson 286*d07d7c3dSDanielle Ratson len = sizeof(*icmph); 287*d07d7c3dSDanielle Ratson memset(buf, 0, buflen); 288*d07d7c3dSDanielle Ratson 289*d07d7c3dSDanielle Ratson icmph = (struct icmp6hdr *)buf; 290*d07d7c3dSDanielle Ratson icmph->icmp6_type = ICMPV6_DEST_UNREACH; 291*d07d7c3dSDanielle Ratson icmph->icmp6_code = ICMPV6_PORT_UNREACH; 292*d07d7c3dSDanielle Ratson icmph->icmp6_cksum = 0; 293*d07d7c3dSDanielle Ratson 294*d07d7c3dSDanielle Ratson ret = build_orig_dgram_v6(buf + len, buflen - len, payload_len); 295*d07d7c3dSDanielle Ratson if (ret < 0) 296*d07d7c3dSDanielle Ratson return ret; 297*d07d7c3dSDanielle Ratson 298*d07d7c3dSDanielle Ratson len += ret; 299*d07d7c3dSDanielle Ratson 300*d07d7c3dSDanielle Ratson icmph->icmp6_datagram_len = (len - sizeof(*icmph)) / sizeof(uint64_t); 301*d07d7c3dSDanielle Ratson 302*d07d7c3dSDanielle Ratson if (with_ext) { 303*d07d7c3dSDanielle Ratson ret = build_rfc4884_ext(buf + len, buflen - len, 304*d07d7c3dSDanielle Ratson bad_csum, bad_len, smaller_len); 305*d07d7c3dSDanielle Ratson if (ret < 0) 306*d07d7c3dSDanielle Ratson return ret; 307*d07d7c3dSDanielle Ratson 308*d07d7c3dSDanielle Ratson len += ret; 309*d07d7c3dSDanielle Ratson } 310*d07d7c3dSDanielle Ratson 311*d07d7c3dSDanielle Ratson icmph->icmp6_cksum = htons(csum(icmph, len)); 312*d07d7c3dSDanielle Ratson return len; 313*d07d7c3dSDanielle Ratson } 314*d07d7c3dSDanielle Ratson 315*d07d7c3dSDanielle Ratson FIXTURE(rfc4884) {}; 316*d07d7c3dSDanielle Ratson 317*d07d7c3dSDanielle Ratson FIXTURE_SETUP(rfc4884) 318*d07d7c3dSDanielle Ratson { 319*d07d7c3dSDanielle Ratson int ret; 320*d07d7c3dSDanielle Ratson 321*d07d7c3dSDanielle Ratson ret = unshare(CLONE_NEWNET); 322*d07d7c3dSDanielle Ratson ASSERT_EQ(ret, 0) { 323*d07d7c3dSDanielle Ratson TH_LOG("unshare(CLONE_NEWNET) failed: %s", strerror(errno)); 324*d07d7c3dSDanielle Ratson } 325*d07d7c3dSDanielle Ratson 326*d07d7c3dSDanielle Ratson ret = bringup_loopback(); 327*d07d7c3dSDanielle Ratson ASSERT_EQ(ret, 0) TH_LOG("Failed to bring up loopback interface"); 328*d07d7c3dSDanielle Ratson } 329*d07d7c3dSDanielle Ratson 330*d07d7c3dSDanielle Ratson FIXTURE_TEARDOWN(rfc4884) 331*d07d7c3dSDanielle Ratson { 332*d07d7c3dSDanielle Ratson } 333*d07d7c3dSDanielle Ratson 334*d07d7c3dSDanielle Ratson const struct ip_case_info ipv4_info = { 335*d07d7c3dSDanielle Ratson .domain = AF_INET, 336*d07d7c3dSDanielle Ratson .level = SOL_IP, 337*d07d7c3dSDanielle Ratson .opt1 = IP_RECVERR, 338*d07d7c3dSDanielle Ratson .opt2 = IP_RECVERR_RFC4884, 339*d07d7c3dSDanielle Ratson .proto = IPPROTO_ICMP, 340*d07d7c3dSDanielle Ratson .build_func = build_icmpv4_pkt, 341*d07d7c3dSDanielle Ratson .min_payload = min_payload_len_v4, 342*d07d7c3dSDanielle Ratson }; 343*d07d7c3dSDanielle Ratson 344*d07d7c3dSDanielle Ratson const struct ip_case_info ipv6_info = { 345*d07d7c3dSDanielle Ratson .domain = AF_INET6, 346*d07d7c3dSDanielle Ratson .level = SOL_IPV6, 347*d07d7c3dSDanielle Ratson .opt1 = IPV6_RECVERR, 348*d07d7c3dSDanielle Ratson .opt2 = IPV6_RECVERR_RFC4884, 349*d07d7c3dSDanielle Ratson .proto = IPPROTO_ICMPV6, 350*d07d7c3dSDanielle Ratson .build_func = build_icmpv6_pkt, 351*d07d7c3dSDanielle Ratson .min_payload = min_payload_len_v6, 352*d07d7c3dSDanielle Ratson }; 353*d07d7c3dSDanielle Ratson 354*d07d7c3dSDanielle Ratson FIXTURE_VARIANT(rfc4884) { 355*d07d7c3dSDanielle Ratson /* IPv4/v6 related information */ 356*d07d7c3dSDanielle Ratson struct ip_case_info info; 357*d07d7c3dSDanielle Ratson /* Whether to append an ICMP extension or not */ 358*d07d7c3dSDanielle Ratson bool with_ext; 359*d07d7c3dSDanielle Ratson /* UDP payload length */ 360*d07d7c3dSDanielle Ratson int payload_len; 361*d07d7c3dSDanielle Ratson /* Whether to generate a bad checksum in the ICMP extension structure */ 362*d07d7c3dSDanielle Ratson bool bad_csum; 363*d07d7c3dSDanielle Ratson /* Whether to generate a bad length in the ICMP object header */ 364*d07d7c3dSDanielle Ratson bool bad_len; 365*d07d7c3dSDanielle Ratson /* Whether it is too small to fit the object header or too big to fit 366*d07d7c3dSDanielle Ratson * in the packet 367*d07d7c3dSDanielle Ratson */ 368*d07d7c3dSDanielle Ratson bool smaller_len; 369*d07d7c3dSDanielle Ratson }; 370*d07d7c3dSDanielle Ratson 371*d07d7c3dSDanielle Ratson /* Tests that a valid ICMPv4 error message with extension and the original 372*d07d7c3dSDanielle Ratson * datagram is smaller than 128 bytes, generates an error with zero offset, 373*d07d7c3dSDanielle Ratson * and does not raise the SO_EE_RFC4884_FLAG_INVALID flag. 374*d07d7c3dSDanielle Ratson */ 375*d07d7c3dSDanielle Ratson FIXTURE_VARIANT_ADD(rfc4884, ipv4_ext_small_payload) { 376*d07d7c3dSDanielle Ratson .info = ipv4_info, 377*d07d7c3dSDanielle Ratson .with_ext = true, 378*d07d7c3dSDanielle Ratson .payload_len = 64, 379*d07d7c3dSDanielle Ratson .bad_csum = false, 380*d07d7c3dSDanielle Ratson .bad_len = false, 381*d07d7c3dSDanielle Ratson }; 382*d07d7c3dSDanielle Ratson 383*d07d7c3dSDanielle Ratson /* Tests that a valid ICMPv4 error message with extension and 128 bytes original 384*d07d7c3dSDanielle Ratson * datagram, generates an error with the expected offset, and does not raise the 385*d07d7c3dSDanielle Ratson * SO_EE_RFC4884_FLAG_INVALID flag. 386*d07d7c3dSDanielle Ratson */ 387*d07d7c3dSDanielle Ratson FIXTURE_VARIANT_ADD(rfc4884, ipv4_ext) { 388*d07d7c3dSDanielle Ratson .info = ipv4_info, 389*d07d7c3dSDanielle Ratson .with_ext = true, 390*d07d7c3dSDanielle Ratson .payload_len = min_payload_len_v4, 391*d07d7c3dSDanielle Ratson .bad_csum = false, 392*d07d7c3dSDanielle Ratson .bad_len = false, 393*d07d7c3dSDanielle Ratson }; 394*d07d7c3dSDanielle Ratson 395*d07d7c3dSDanielle Ratson /* Tests that a valid ICMPv4 error message with extension and the original 396*d07d7c3dSDanielle Ratson * datagram is larger than 128 bytes, generates an error with the expected 397*d07d7c3dSDanielle Ratson * offset, and does not raise the SO_EE_RFC4884_FLAG_INVALID flag. 398*d07d7c3dSDanielle Ratson */ 399*d07d7c3dSDanielle Ratson FIXTURE_VARIANT_ADD(rfc4884, ipv4_ext_large_payload) { 400*d07d7c3dSDanielle Ratson .info = ipv4_info, 401*d07d7c3dSDanielle Ratson .with_ext = true, 402*d07d7c3dSDanielle Ratson .payload_len = 256, 403*d07d7c3dSDanielle Ratson .bad_csum = false, 404*d07d7c3dSDanielle Ratson .bad_len = false, 405*d07d7c3dSDanielle Ratson }; 406*d07d7c3dSDanielle Ratson 407*d07d7c3dSDanielle Ratson /* Tests that a valid ICMPv4 error message without extension and the original 408*d07d7c3dSDanielle Ratson * datagram is smaller than 128 bytes, generates an error with zero offset, 409*d07d7c3dSDanielle Ratson * and does not raise the SO_EE_RFC4884_FLAG_INVALID flag. 410*d07d7c3dSDanielle Ratson */ 411*d07d7c3dSDanielle Ratson FIXTURE_VARIANT_ADD(rfc4884, ipv4_no_ext_small_payload) { 412*d07d7c3dSDanielle Ratson .info = ipv4_info, 413*d07d7c3dSDanielle Ratson .with_ext = false, 414*d07d7c3dSDanielle Ratson .payload_len = 64, 415*d07d7c3dSDanielle Ratson .bad_csum = false, 416*d07d7c3dSDanielle Ratson .bad_len = false, 417*d07d7c3dSDanielle Ratson }; 418*d07d7c3dSDanielle Ratson 419*d07d7c3dSDanielle Ratson /* Tests that a valid ICMPv4 error message without extension and 128 bytes 420*d07d7c3dSDanielle Ratson * original datagram, generates an error with zero offset, and does not raise 421*d07d7c3dSDanielle Ratson * the SO_EE_RFC4884_FLAG_INVALID flag. 422*d07d7c3dSDanielle Ratson */ 423*d07d7c3dSDanielle Ratson FIXTURE_VARIANT_ADD(rfc4884, ipv4_no_ext_min_payload) { 424*d07d7c3dSDanielle Ratson .info = ipv4_info, 425*d07d7c3dSDanielle Ratson .with_ext = false, 426*d07d7c3dSDanielle Ratson .payload_len = min_payload_len_v4, 427*d07d7c3dSDanielle Ratson .bad_csum = false, 428*d07d7c3dSDanielle Ratson .bad_len = false, 429*d07d7c3dSDanielle Ratson }; 430*d07d7c3dSDanielle Ratson 431*d07d7c3dSDanielle Ratson /* Tests that a valid ICMPv4 error message without extension and the original 432*d07d7c3dSDanielle Ratson * datagram is larger than 128 bytes, generates an error with zero offset, 433*d07d7c3dSDanielle Ratson * and does not raise the SO_EE_RFC4884_FLAG_INVALID flag. 434*d07d7c3dSDanielle Ratson */ 435*d07d7c3dSDanielle Ratson FIXTURE_VARIANT_ADD(rfc4884, ipv4_no_ext_large_payload) { 436*d07d7c3dSDanielle Ratson .info = ipv4_info, 437*d07d7c3dSDanielle Ratson .with_ext = false, 438*d07d7c3dSDanielle Ratson .payload_len = 256, 439*d07d7c3dSDanielle Ratson .bad_csum = false, 440*d07d7c3dSDanielle Ratson .bad_len = false, 441*d07d7c3dSDanielle Ratson }; 442*d07d7c3dSDanielle Ratson 443*d07d7c3dSDanielle Ratson /* Tests that an ICMPv4 error message with extension and an invalid checksum, 444*d07d7c3dSDanielle Ratson * generates an error with the expected offset, and raises the 445*d07d7c3dSDanielle Ratson * SO_EE_RFC4884_FLAG_INVALID flag. 446*d07d7c3dSDanielle Ratson */ 447*d07d7c3dSDanielle Ratson FIXTURE_VARIANT_ADD(rfc4884, ipv4_invalid_ext_checksum) { 448*d07d7c3dSDanielle Ratson .info = ipv4_info, 449*d07d7c3dSDanielle Ratson .with_ext = true, 450*d07d7c3dSDanielle Ratson .payload_len = min_payload_len_v4, 451*d07d7c3dSDanielle Ratson .bad_csum = true, 452*d07d7c3dSDanielle Ratson .bad_len = false, 453*d07d7c3dSDanielle Ratson }; 454*d07d7c3dSDanielle Ratson 455*d07d7c3dSDanielle Ratson /* Tests that an ICMPv4 error message with extension and an object length 456*d07d7c3dSDanielle Ratson * smaller than the object header, generates an error with the expected offset, 457*d07d7c3dSDanielle Ratson * and raises the SO_EE_RFC4884_FLAG_INVALID flag. 458*d07d7c3dSDanielle Ratson */ 459*d07d7c3dSDanielle Ratson FIXTURE_VARIANT_ADD(rfc4884, ipv4_invalid_ext_length_small) { 460*d07d7c3dSDanielle Ratson .info = ipv4_info, 461*d07d7c3dSDanielle Ratson .with_ext = true, 462*d07d7c3dSDanielle Ratson .payload_len = min_payload_len_v4, 463*d07d7c3dSDanielle Ratson .bad_csum = false, 464*d07d7c3dSDanielle Ratson .bad_len = true, 465*d07d7c3dSDanielle Ratson .smaller_len = true, 466*d07d7c3dSDanielle Ratson }; 467*d07d7c3dSDanielle Ratson 468*d07d7c3dSDanielle Ratson /* Tests that an ICMPv4 error message with extension and an object length that 469*d07d7c3dSDanielle Ratson * is too big to fit in the packet, generates an error with the expected offset, 470*d07d7c3dSDanielle Ratson * and raises the SO_EE_RFC4884_FLAG_INVALID flag. 471*d07d7c3dSDanielle Ratson */ 472*d07d7c3dSDanielle Ratson FIXTURE_VARIANT_ADD(rfc4884, ipv4_invalid_ext_length_large) { 473*d07d7c3dSDanielle Ratson .info = ipv4_info, 474*d07d7c3dSDanielle Ratson .with_ext = true, 475*d07d7c3dSDanielle Ratson .payload_len = min_payload_len_v4, 476*d07d7c3dSDanielle Ratson .bad_csum = false, 477*d07d7c3dSDanielle Ratson .bad_len = true, 478*d07d7c3dSDanielle Ratson .smaller_len = false, 479*d07d7c3dSDanielle Ratson }; 480*d07d7c3dSDanielle Ratson 481*d07d7c3dSDanielle Ratson /* Tests that a valid ICMPv6 error message with extension and the original 482*d07d7c3dSDanielle Ratson * datagram is smaller than 128 bytes, generates an error with zero offset, 483*d07d7c3dSDanielle Ratson * and does not raise the SO_EE_RFC4884_FLAG_INVALID flag. 484*d07d7c3dSDanielle Ratson */ 485*d07d7c3dSDanielle Ratson FIXTURE_VARIANT_ADD(rfc4884, ipv6_ext_small_payload) { 486*d07d7c3dSDanielle Ratson .info = ipv6_info, 487*d07d7c3dSDanielle Ratson .with_ext = true, 488*d07d7c3dSDanielle Ratson .payload_len = 64, 489*d07d7c3dSDanielle Ratson .bad_csum = false, 490*d07d7c3dSDanielle Ratson .bad_len = false, 491*d07d7c3dSDanielle Ratson }; 492*d07d7c3dSDanielle Ratson 493*d07d7c3dSDanielle Ratson /* Tests that a valid ICMPv6 error message with extension and 128 bytes original 494*d07d7c3dSDanielle Ratson * datagram, generates an error with the expected offset, and does not raise the 495*d07d7c3dSDanielle Ratson * SO_EE_RFC4884_FLAG_INVALID flag. 496*d07d7c3dSDanielle Ratson */ 497*d07d7c3dSDanielle Ratson FIXTURE_VARIANT_ADD(rfc4884, ipv6_ext) { 498*d07d7c3dSDanielle Ratson .info = ipv6_info, 499*d07d7c3dSDanielle Ratson .with_ext = true, 500*d07d7c3dSDanielle Ratson .payload_len = min_payload_len_v6, 501*d07d7c3dSDanielle Ratson .bad_csum = false, 502*d07d7c3dSDanielle Ratson .bad_len = false, 503*d07d7c3dSDanielle Ratson }; 504*d07d7c3dSDanielle Ratson 505*d07d7c3dSDanielle Ratson /* Tests that a valid ICMPv6 error message with extension and the original 506*d07d7c3dSDanielle Ratson * datagram is larger than 128 bytes, generates an error with the expected 507*d07d7c3dSDanielle Ratson * offset, and does not raise the SO_EE_RFC4884_FLAG_INVALID flag. 508*d07d7c3dSDanielle Ratson */ 509*d07d7c3dSDanielle Ratson FIXTURE_VARIANT_ADD(rfc4884, ipv6_ext_large_payload) { 510*d07d7c3dSDanielle Ratson .info = ipv6_info, 511*d07d7c3dSDanielle Ratson .with_ext = true, 512*d07d7c3dSDanielle Ratson .payload_len = 256, 513*d07d7c3dSDanielle Ratson .bad_csum = false, 514*d07d7c3dSDanielle Ratson .bad_len = false, 515*d07d7c3dSDanielle Ratson }; 516*d07d7c3dSDanielle Ratson /* Tests that a valid ICMPv6 error message without extension and the original 517*d07d7c3dSDanielle Ratson * datagram is smaller than 128 bytes, generates an error with zero offset, 518*d07d7c3dSDanielle Ratson * and does not raise the SO_EE_RFC4884_FLAG_INVALID flag. 519*d07d7c3dSDanielle Ratson */ 520*d07d7c3dSDanielle Ratson FIXTURE_VARIANT_ADD(rfc4884, ipv6_no_ext_small_payload) { 521*d07d7c3dSDanielle Ratson .info = ipv6_info, 522*d07d7c3dSDanielle Ratson .with_ext = false, 523*d07d7c3dSDanielle Ratson .payload_len = 64, 524*d07d7c3dSDanielle Ratson .bad_csum = false, 525*d07d7c3dSDanielle Ratson .bad_len = false, 526*d07d7c3dSDanielle Ratson }; 527*d07d7c3dSDanielle Ratson 528*d07d7c3dSDanielle Ratson /* Tests that a valid ICMPv6 error message without extension and 128 bytes 529*d07d7c3dSDanielle Ratson * original datagram, generates an error with zero offset, and does not 530*d07d7c3dSDanielle Ratson * raise the SO_EE_RFC4884_FLAG_INVALID flag. 531*d07d7c3dSDanielle Ratson */ 532*d07d7c3dSDanielle Ratson FIXTURE_VARIANT_ADD(rfc4884, ipv6_no_ext_min_payload) { 533*d07d7c3dSDanielle Ratson .info = ipv6_info, 534*d07d7c3dSDanielle Ratson .with_ext = false, 535*d07d7c3dSDanielle Ratson .payload_len = min_payload_len_v6, 536*d07d7c3dSDanielle Ratson .bad_csum = false, 537*d07d7c3dSDanielle Ratson .bad_len = false, 538*d07d7c3dSDanielle Ratson }; 539*d07d7c3dSDanielle Ratson 540*d07d7c3dSDanielle Ratson /* Tests that a valid ICMPv6 error message without extension and the original 541*d07d7c3dSDanielle Ratson * datagram is larger than 128 bytes, generates an error with zero offset, 542*d07d7c3dSDanielle Ratson * and does not raise the SO_EE_RFC4884_FLAG_INVALID flag. 543*d07d7c3dSDanielle Ratson */ 544*d07d7c3dSDanielle Ratson FIXTURE_VARIANT_ADD(rfc4884, ipv6_no_ext_large_payload) { 545*d07d7c3dSDanielle Ratson .info = ipv6_info, 546*d07d7c3dSDanielle Ratson .with_ext = false, 547*d07d7c3dSDanielle Ratson .payload_len = 256, 548*d07d7c3dSDanielle Ratson .bad_csum = false, 549*d07d7c3dSDanielle Ratson .bad_len = false, 550*d07d7c3dSDanielle Ratson }; 551*d07d7c3dSDanielle Ratson 552*d07d7c3dSDanielle Ratson /* Tests that an ICMPv6 error message with extension and an invalid checksum, 553*d07d7c3dSDanielle Ratson * generates an error with the expected offset, and raises the 554*d07d7c3dSDanielle Ratson * SO_EE_RFC4884_FLAG_INVALID flag. 555*d07d7c3dSDanielle Ratson */ 556*d07d7c3dSDanielle Ratson FIXTURE_VARIANT_ADD(rfc4884, ipv6_invalid_ext_checksum) { 557*d07d7c3dSDanielle Ratson .info = ipv6_info, 558*d07d7c3dSDanielle Ratson .with_ext = true, 559*d07d7c3dSDanielle Ratson .payload_len = min_payload_len_v6, 560*d07d7c3dSDanielle Ratson .bad_csum = true, 561*d07d7c3dSDanielle Ratson .bad_len = false, 562*d07d7c3dSDanielle Ratson }; 563*d07d7c3dSDanielle Ratson 564*d07d7c3dSDanielle Ratson /* Tests that an ICMPv6 error message with extension and an object length 565*d07d7c3dSDanielle Ratson * smaller than the object header, generates an error with the expected offset, 566*d07d7c3dSDanielle Ratson * and raises the SO_EE_RFC4884_FLAG_INVALID flag. 567*d07d7c3dSDanielle Ratson */ 568*d07d7c3dSDanielle Ratson FIXTURE_VARIANT_ADD(rfc4884, ipv6_invalid_ext_length_small) { 569*d07d7c3dSDanielle Ratson .info = ipv6_info, 570*d07d7c3dSDanielle Ratson .with_ext = true, 571*d07d7c3dSDanielle Ratson .payload_len = min_payload_len_v6, 572*d07d7c3dSDanielle Ratson .bad_csum = false, 573*d07d7c3dSDanielle Ratson .bad_len = true, 574*d07d7c3dSDanielle Ratson .smaller_len = true, 575*d07d7c3dSDanielle Ratson }; 576*d07d7c3dSDanielle Ratson 577*d07d7c3dSDanielle Ratson /* Tests that an ICMPv6 error message with extension and an object length that 578*d07d7c3dSDanielle Ratson * is too big to fit in the packet, generates an error with the expected offset, 579*d07d7c3dSDanielle Ratson * and raises the SO_EE_RFC4884_FLAG_INVALID flag. 580*d07d7c3dSDanielle Ratson */ 581*d07d7c3dSDanielle Ratson FIXTURE_VARIANT_ADD(rfc4884, ipv6_invalid_ext_length_large) { 582*d07d7c3dSDanielle Ratson .info = ipv6_info, 583*d07d7c3dSDanielle Ratson .with_ext = true, 584*d07d7c3dSDanielle Ratson .payload_len = min_payload_len_v6, 585*d07d7c3dSDanielle Ratson .bad_csum = false, 586*d07d7c3dSDanielle Ratson .bad_len = true, 587*d07d7c3dSDanielle Ratson .smaller_len = false, 588*d07d7c3dSDanielle Ratson }; 589*d07d7c3dSDanielle Ratson 590*d07d7c3dSDanielle Ratson static void 591*d07d7c3dSDanielle Ratson check_rfc4884_offset(struct __test_metadata *_metadata, int sock, 592*d07d7c3dSDanielle Ratson const FIXTURE_VARIANT(rfc4884) *v) 593*d07d7c3dSDanielle Ratson { 594*d07d7c3dSDanielle Ratson char rxbuf[1024]; 595*d07d7c3dSDanielle Ratson char ctrl[1024]; 596*d07d7c3dSDanielle Ratson struct iovec iov = { 597*d07d7c3dSDanielle Ratson .iov_base = rxbuf, 598*d07d7c3dSDanielle Ratson .iov_len = sizeof(rxbuf) 599*d07d7c3dSDanielle Ratson }; 600*d07d7c3dSDanielle Ratson struct msghdr msg = { 601*d07d7c3dSDanielle Ratson .msg_iov = &iov, 602*d07d7c3dSDanielle Ratson .msg_iovlen = 1, 603*d07d7c3dSDanielle Ratson .msg_control = ctrl, 604*d07d7c3dSDanielle Ratson .msg_controllen = sizeof(ctrl), 605*d07d7c3dSDanielle Ratson }; 606*d07d7c3dSDanielle Ratson struct cmsghdr *cmsg; 607*d07d7c3dSDanielle Ratson int recv; 608*d07d7c3dSDanielle Ratson 609*d07d7c3dSDanielle Ratson ASSERT_EQ(poll_err(sock), 0); 610*d07d7c3dSDanielle Ratson 611*d07d7c3dSDanielle Ratson recv = recvmsg(sock, &msg, MSG_ERRQUEUE); 612*d07d7c3dSDanielle Ratson ASSERT_GE(recv, 0) TH_LOG("recvmsg(MSG_ERRQUEUE) failed"); 613*d07d7c3dSDanielle Ratson 614*d07d7c3dSDanielle Ratson for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { 615*d07d7c3dSDanielle Ratson bool is_invalid, expected_invalid; 616*d07d7c3dSDanielle Ratson struct sock_extended_err *ee; 617*d07d7c3dSDanielle Ratson int expected_off; 618*d07d7c3dSDanielle Ratson uint16_t off; 619*d07d7c3dSDanielle Ratson 620*d07d7c3dSDanielle Ratson if (cmsg->cmsg_level != v->info.level || 621*d07d7c3dSDanielle Ratson cmsg->cmsg_type != v->info.opt1) { 622*d07d7c3dSDanielle Ratson TH_LOG("Unrelated cmsgs were encountered in recvmsg()"); 623*d07d7c3dSDanielle Ratson continue; 624*d07d7c3dSDanielle Ratson } 625*d07d7c3dSDanielle Ratson 626*d07d7c3dSDanielle Ratson ee = (struct sock_extended_err *)CMSG_DATA(cmsg); 627*d07d7c3dSDanielle Ratson off = ee->ee_rfc4884.len; 628*d07d7c3dSDanielle Ratson is_invalid = ee->ee_rfc4884.flags & SO_EE_RFC4884_FLAG_INVALID; 629*d07d7c3dSDanielle Ratson 630*d07d7c3dSDanielle Ratson expected_invalid = v->bad_csum || v->bad_len; 631*d07d7c3dSDanielle Ratson ASSERT_EQ(is_invalid, expected_invalid) { 632*d07d7c3dSDanielle Ratson TH_LOG("Expected invalidity flag to be %d, but got %d", 633*d07d7c3dSDanielle Ratson expected_invalid, is_invalid); 634*d07d7c3dSDanielle Ratson } 635*d07d7c3dSDanielle Ratson 636*d07d7c3dSDanielle Ratson expected_off = 637*d07d7c3dSDanielle Ratson (v->with_ext && v->payload_len >= v->info.min_payload) ? 638*d07d7c3dSDanielle Ratson v->payload_len : 0; 639*d07d7c3dSDanielle Ratson ASSERT_EQ(off, expected_off) { 640*d07d7c3dSDanielle Ratson TH_LOG("Expected RFC4884 offset %u, got %u", 641*d07d7c3dSDanielle Ratson expected_off, off); 642*d07d7c3dSDanielle Ratson } 643*d07d7c3dSDanielle Ratson break; 644*d07d7c3dSDanielle Ratson } 645*d07d7c3dSDanielle Ratson } 646*d07d7c3dSDanielle Ratson 647*d07d7c3dSDanielle Ratson TEST_F(rfc4884, rfc4884) 648*d07d7c3dSDanielle Ratson { 649*d07d7c3dSDanielle Ratson const typeof(variant) v = variant; 650*d07d7c3dSDanielle Ratson struct sockaddr_inet addr; 651*d07d7c3dSDanielle Ratson uint8_t pkt[1024]; 652*d07d7c3dSDanielle Ratson int dgram, raw; 653*d07d7c3dSDanielle Ratson int len, sent; 654*d07d7c3dSDanielle Ratson int err; 655*d07d7c3dSDanielle Ratson 656*d07d7c3dSDanielle Ratson dgram = socket(v->info.domain, SOCK_DGRAM, 0); 657*d07d7c3dSDanielle Ratson ASSERT_GE(dgram, 0) TH_LOG("Opening datagram socket failed"); 658*d07d7c3dSDanielle Ratson 659*d07d7c3dSDanielle Ratson err = bind_and_setsockopt(dgram, &v->info); 660*d07d7c3dSDanielle Ratson ASSERT_EQ(err, 0) TH_LOG("Bind failed"); 661*d07d7c3dSDanielle Ratson 662*d07d7c3dSDanielle Ratson raw = socket(v->info.domain, SOCK_RAW, v->info.proto); 663*d07d7c3dSDanielle Ratson ASSERT_GE(raw, 0) TH_LOG("Opening raw socket failed"); 664*d07d7c3dSDanielle Ratson 665*d07d7c3dSDanielle Ratson len = v->info.build_func(pkt, sizeof(pkt), v->with_ext, v->payload_len, 666*d07d7c3dSDanielle Ratson v->bad_csum, v->bad_len, v->smaller_len); 667*d07d7c3dSDanielle Ratson ASSERT_GT(len, 0) TH_LOG("Building packet failed"); 668*d07d7c3dSDanielle Ratson 669*d07d7c3dSDanielle Ratson set_addr(&addr, v->info.domain, 0); 670*d07d7c3dSDanielle Ratson sent = sendto(raw, pkt, len, 0, &addr.sa, addr.len); 671*d07d7c3dSDanielle Ratson ASSERT_EQ(len, sent) TH_LOG("Sending packet failed"); 672*d07d7c3dSDanielle Ratson 673*d07d7c3dSDanielle Ratson check_rfc4884_offset(_metadata, dgram, v); 674*d07d7c3dSDanielle Ratson 675*d07d7c3dSDanielle Ratson close(dgram); 676*d07d7c3dSDanielle Ratson close(raw); 677*d07d7c3dSDanielle Ratson } 678*d07d7c3dSDanielle Ratson 679*d07d7c3dSDanielle Ratson TEST_HARNESS_MAIN 680