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