icmp_rfc4884.c 17 KB

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