2 * Check decoding of struct msghdr ancillary data.
4 * Copyright (c) 2016 Dmitry V. Levin <ldv@altlinux.org>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 #include <sys/socket.h>
38 #include <netinet/in.h>
39 #include <arpa/inet.h>
49 # define SCM_SECURITY 3
52 #define MIN_SIZE_OF(type, member) \
53 (offsetof(type, member) + sizeof(((type *) 0)->member))
55 #define VAL_STR(val) val, #val
57 static struct cmsghdr *
58 get_cmsghdr(void *const page, const size_t len)
60 return page - CMSG_ALIGN(len);
63 #define DEFAULT_STRLEN 32
66 print_fds(const struct cmsghdr *const cmsg, const size_t cmsg_len)
68 size_t nfd = cmsg_len > CMSG_LEN(0)
69 ? (cmsg_len - CMSG_LEN(0)) / sizeof(int) : 0;
73 printf(", cmsg_data=[");
74 int *fdp = (int *) CMSG_DATA(cmsg);
76 for (i = 0; i < nfd; ++i) {
79 #ifndef VERBOSE_MSGHDR
80 if (i >= DEFAULT_STRLEN) {
91 test_scm_rights1(struct msghdr *const mh,
92 const size_t msg_controllen,
94 const void *const src,
95 const size_t cmsg_len)
97 const size_t aligned_cms_len =
98 cmsg_len > CMSG_LEN(0) ? CMSG_ALIGN(cmsg_len) : CMSG_LEN(0);
99 if (cmsg_len >= CMSG_LEN(0)
100 && aligned_cms_len + CMSG_LEN(0) <= msg_controllen)
103 struct cmsghdr *cmsg = get_cmsghdr(page, msg_controllen);
105 if (msg_controllen >= MIN_SIZE_OF(struct cmsghdr, cmsg_len))
106 cmsg->cmsg_len = cmsg_len;
107 if (msg_controllen >= MIN_SIZE_OF(struct cmsghdr, cmsg_level))
108 cmsg->cmsg_level = SOL_SOCKET;
109 if (msg_controllen >= MIN_SIZE_OF(struct cmsghdr, cmsg_type))
110 cmsg->cmsg_type = SCM_RIGHTS;
113 cmsg_len < msg_controllen ? cmsg_len : msg_controllen;
114 if (src_len > CMSG_LEN(0))
115 memcpy(CMSG_DATA(cmsg), src, src_len - CMSG_LEN(0));
117 mh->msg_control = cmsg;
118 mh->msg_controllen = msg_controllen;
120 int rc = sendmsg(-1, mh, 0);
121 int saved_errno = errno;
123 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
125 if (msg_controllen < CMSG_LEN(0)) {
127 printf(", msg_control=%p", cmsg);
129 printf(", msg_control=[{cmsg_len=%lu, cmsg_level=SOL_SOCKET"
130 ", cmsg_type=SCM_RIGHTS", (unsigned long) cmsg_len);
131 print_fds(cmsg, src_len);
133 if (aligned_cms_len < msg_controllen)
134 printf(", %p", (void *) cmsg + aligned_cms_len);
139 printf(", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
140 (unsigned long) msg_controllen, rc, errno2name());
144 test_scm_rights2(struct msghdr *const mh,
145 const size_t msg_controllen,
147 const int *const *const src,
148 const size_t *const cmsg_len)
150 const size_t aligned_cms_len[2] = {
151 cmsg_len[0] > CMSG_LEN(0) ? CMSG_ALIGN(cmsg_len[0]) : CMSG_LEN(0),
152 cmsg_len[1] > CMSG_LEN(0) ? CMSG_ALIGN(cmsg_len[1]) : CMSG_LEN(0)
154 if (cmsg_len[0] < CMSG_LEN(0)
155 || aligned_cms_len[0] + CMSG_LEN(0) > msg_controllen
156 || aligned_cms_len[0] + aligned_cms_len[1] + CMSG_LEN(0) <= msg_controllen)
159 struct cmsghdr *const cmsg[2] = {
160 get_cmsghdr(page, msg_controllen),
161 (void *) get_cmsghdr(page, msg_controllen) + aligned_cms_len[0]
163 cmsg[0]->cmsg_len = cmsg_len[0];
164 cmsg[0]->cmsg_level = SOL_SOCKET;
165 cmsg[0]->cmsg_type = SCM_RIGHTS;
166 if (cmsg_len[0] > CMSG_LEN(0))
167 memcpy(CMSG_DATA(cmsg[0]), src[0], cmsg_len[0] - CMSG_LEN(0));
169 const size_t msg_controllen1 = msg_controllen - aligned_cms_len[0];
170 if (msg_controllen1 >= MIN_SIZE_OF(struct cmsghdr, cmsg_len))
171 cmsg[1]->cmsg_len = cmsg_len[1];
172 if (msg_controllen >= MIN_SIZE_OF(struct cmsghdr, cmsg_level))
173 cmsg[1]->cmsg_level = SOL_SOCKET;
174 if (msg_controllen >= MIN_SIZE_OF(struct cmsghdr, cmsg_type))
175 cmsg[1]->cmsg_type = SCM_RIGHTS;
177 cmsg_len[1] < msg_controllen1 ? cmsg_len[1] : msg_controllen1;
178 if (src1_len > CMSG_LEN(0))
179 memcpy(CMSG_DATA(cmsg[1]), src[1], src1_len - CMSG_LEN(0));
181 mh->msg_control = cmsg[0];
182 mh->msg_controllen = msg_controllen;
184 int rc = sendmsg(-1, mh, 0);
185 int saved_errno = errno;
187 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
188 ", msg_iovlen=0, msg_control=[{cmsg_len=%lu"
189 ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS",
190 (unsigned long) cmsg_len[0]);
191 print_fds(cmsg[0], cmsg_len[0]);
192 printf("}, {cmsg_len=%lu, cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS",
193 (unsigned long) cmsg_len[1]);
194 print_fds(cmsg[1], src1_len);
196 if (aligned_cms_len[1] < msg_controllen1)
197 printf(", %p", (void *) cmsg[1] + aligned_cms_len[1]);
201 printf(", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
202 (unsigned long) msg_controllen, rc, errno2name());
206 test_scm_rights3(struct msghdr *const mh, void *const page, const size_t nfds)
208 const size_t len = CMSG_SPACE(sizeof(int) * nfds);
209 struct cmsghdr *cmsg = get_cmsghdr(page, len);
211 cmsg->cmsg_len = CMSG_LEN(sizeof(int) * nfds);
212 cmsg->cmsg_level = SOL_SOCKET;
213 cmsg->cmsg_type = SCM_RIGHTS;
214 int *fdp = (int *) CMSG_DATA(cmsg);
216 for (i = 0; i < nfds; ++i)
219 mh->msg_control = cmsg;
220 mh->msg_controllen = len;
222 int rc = sendmsg(-1, mh, 0);
223 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
224 ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
225 ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS",
226 (unsigned) cmsg->cmsg_len);
227 print_fds(cmsg, cmsg->cmsg_len);
228 printf("}], msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
229 (unsigned long) len, rc, errno2name());
233 print_security(const struct cmsghdr *const cmsg, const size_t cmsg_len)
235 int n = cmsg_len > CMSG_LEN(0) ? cmsg_len - CMSG_LEN(0) : 0;
239 printf(", cmsg_data=\"%.*s\"", n, CMSG_DATA(cmsg));
243 test_scm_security(struct msghdr *const mh,
244 const size_t msg_controllen,
246 const void *const src,
247 const size_t cmsg_len,
248 const int cmsg_level,
249 const char *const cmsg_level_str)
251 const size_t aligned_cms_len =
252 cmsg_len > CMSG_LEN(0) ? CMSG_ALIGN(cmsg_len) : CMSG_LEN(0);
253 if (cmsg_len >= CMSG_LEN(0)
254 && aligned_cms_len + CMSG_LEN(0) <= msg_controllen)
257 struct cmsghdr *cmsg = get_cmsghdr(page, msg_controllen);
259 cmsg->cmsg_len = cmsg_len;
260 cmsg->cmsg_level = cmsg_level;
261 cmsg->cmsg_type = SCM_SECURITY;
264 cmsg_len < msg_controllen ? cmsg_len : msg_controllen;
265 if (src_len > CMSG_LEN(0))
266 memcpy(CMSG_DATA(cmsg), src, src_len - CMSG_LEN(0));
268 mh->msg_control = cmsg;
269 mh->msg_controllen = msg_controllen;
271 int rc = sendmsg(-1, mh, 0);
272 int saved_errno = errno;
274 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
275 ", msg_iovlen=0, msg_control=[{cmsg_len=%lu, cmsg_level=%s"
276 ", cmsg_type=SCM_SECURITY",
277 (unsigned long) cmsg_len, cmsg_level_str);
278 print_security(cmsg, src_len);
280 if (aligned_cms_len < msg_controllen)
281 printf(", %p", (void *) cmsg + aligned_cms_len);
285 printf(", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
286 (unsigned long) msg_controllen, rc, errno2name());
290 test_unknown_type(struct msghdr *const mh,
292 const int cmsg_level,
293 const char *const cmsg_level_str,
294 const char *const cmsg_type_str)
296 struct cmsghdr *cmsg = get_cmsghdr(page, CMSG_LEN(0));
298 cmsg->cmsg_len = CMSG_LEN(0);
299 cmsg->cmsg_level = cmsg_level;
300 cmsg->cmsg_type = 0xfacefeed;
302 mh->msg_control = cmsg;
303 mh->msg_controllen = cmsg->cmsg_len;
305 int rc = sendmsg(-1, mh, 0);
306 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
307 ", msg_iovlen=0, msg_control=[{cmsg_len=%u, cmsg_level=%s"
308 ", cmsg_type=%#x /* %s */}], msg_controllen=%u, msg_flags=0}"
309 ", 0) = %d %s (%m)\n",
310 (unsigned) cmsg->cmsg_len, cmsg_level_str, cmsg->cmsg_type,
311 cmsg_type_str, (unsigned) mh->msg_controllen, rc, errno2name());
315 test_sol_socket(struct msghdr *const mh, void *const page)
317 static const int fds0[] = { -10, -11, -12, -13 };
318 static const int fds1[] = { -15, -16, -17, -18 };
319 size_t msg_controllen, max_msg_controllen;
321 max_msg_controllen = CMSG_SPACE(sizeof(fds0)) + sizeof(*fds0) - 1;
322 for (msg_controllen = 0;
323 msg_controllen <= max_msg_controllen;
328 cmsg_len <= msg_controllen + CMSG_LEN(0);
330 test_scm_rights1(mh, msg_controllen,
331 page, fds0, cmsg_len);
336 CMSG_SPACE(sizeof(fds0)) + CMSG_SPACE(sizeof(fds1)) +
338 for (msg_controllen = CMSG_LEN(0) * 2;
339 msg_controllen <= max_msg_controllen;
341 static const int *const fdps[] = { fds0, fds1 };
344 for (cmsg_len[0] = CMSG_LEN(0);
345 CMSG_ALIGN(cmsg_len[0]) + CMSG_LEN(0) <= msg_controllen
346 && CMSG_ALIGN(cmsg_len[0]) <= CMSG_SPACE(sizeof(fds0));
348 const size_t msg_controllen1 =
349 msg_controllen - CMSG_ALIGN(cmsg_len[0]);
351 for (cmsg_len[1] = 0;
352 cmsg_len[1] <= msg_controllen1 + CMSG_LEN(0);
354 test_scm_rights2(mh, msg_controllen,
355 page, fdps, cmsg_len);
360 static const char text[16] = "0123456789abcdef";
361 max_msg_controllen = CMSG_SPACE(sizeof(text)) + CMSG_LEN(0) - 1;
362 for (msg_controllen = CMSG_LEN(0);
363 msg_controllen <= max_msg_controllen;
368 cmsg_len <= msg_controllen + CMSG_LEN(0)
369 && cmsg_len <= CMSG_LEN(sizeof(text));
371 test_scm_security(mh, msg_controllen,
372 page, text, cmsg_len,
373 VAL_STR(SOL_SOCKET));
377 test_scm_rights3(mh, page, DEFAULT_STRLEN - 1);
378 test_scm_rights3(mh, page, DEFAULT_STRLEN);
379 test_scm_rights3(mh, page, DEFAULT_STRLEN + 1);
381 test_unknown_type(mh, page, VAL_STR(SOL_SOCKET), "SCM_???");
385 test_ip_pktinfo(struct msghdr *const mh, void *const page,
386 const int cmsg_type, const char *const cmsg_type_str)
388 const unsigned int len = CMSG_SPACE(sizeof(struct in_pktinfo));
389 struct cmsghdr *const cmsg = get_cmsghdr(page, len);
391 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
392 cmsg->cmsg_level = SOL_IP;
393 cmsg->cmsg_type = cmsg_type;
395 struct in_pktinfo *const info = (struct in_pktinfo *) CMSG_DATA(cmsg);
396 #ifdef HAVE_IF_INDEXTONAME
397 info->ipi_ifindex = if_nametoindex("lo");
399 info->ipi_ifindex = 1;
401 info->ipi_spec_dst.s_addr = inet_addr("1.2.3.4");
402 info->ipi_addr.s_addr = inet_addr("5.6.7.8");
404 mh->msg_control = cmsg;
405 mh->msg_controllen = len;
407 int rc = sendmsg(-1, mh, 0);
408 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
409 ", msg_iovlen=0, msg_control=[{cmsg_len=%u, cmsg_level=SOL_IP"
410 ", cmsg_type=%s, cmsg_data={ipi_ifindex=%s"
411 ", ipi_spec_dst=inet_addr(\"%s\")"
412 ", ipi_addr=inet_addr(\"%s\")}}]"
413 ", msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n",
414 (unsigned) cmsg->cmsg_len, cmsg_type_str,
415 #ifdef HAVE_IF_INDEXTONAME
416 "if_nametoindex(\"lo\")",
420 "1.2.3.4", "5.6.7.8", len, rc, errno2name());
424 test_ip_uint(struct msghdr *const mh, void *const page,
425 const int cmsg_type, const char *const cmsg_type_str)
427 const unsigned int len = CMSG_SPACE(sizeof(int));
428 struct cmsghdr *const cmsg = get_cmsghdr(page, len);
430 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
431 cmsg->cmsg_level = SOL_IP;
432 cmsg->cmsg_type = cmsg_type;
434 unsigned int *u = (void *) CMSG_DATA(cmsg);
437 mh->msg_control = cmsg;
438 mh->msg_controllen = len;
440 int rc = sendmsg(-1, mh, 0);
441 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
442 ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
443 ", cmsg_level=SOL_IP, cmsg_type=%s, cmsg_data=[%u]}]"
444 ", msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n",
445 (unsigned) cmsg->cmsg_len, cmsg_type_str, *u, len,
450 test_ip_uint8_t(struct msghdr *const mh, void *const page,
451 const int cmsg_type, const char *const cmsg_type_str)
453 const unsigned int len = CMSG_SPACE(1);
454 struct cmsghdr *const cmsg = get_cmsghdr(page, len);
456 cmsg->cmsg_len = CMSG_LEN(1);
457 cmsg->cmsg_level = SOL_IP;
458 cmsg->cmsg_type = cmsg_type;
459 *CMSG_DATA(cmsg) = 'A';
461 mh->msg_control = cmsg;
462 mh->msg_controllen = len;
464 int rc = sendmsg(-1, mh, 0);
465 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
466 ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
467 ", cmsg_level=SOL_IP, cmsg_type=%s, cmsg_data=[%#x]}]"
468 ", msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n",
469 (unsigned) cmsg->cmsg_len, cmsg_type_str,
470 (unsigned) (uint8_t) 'A', len, rc, errno2name());
474 print_ip_opts(const void *const cmsg_data, const unsigned int data_len)
476 const unsigned char *const opts = cmsg_data;
478 for (i = 0; i < data_len; ++i) {
481 printf("0x%02x", opts[i]);
486 test_ip_opts(struct msghdr *const mh, void *const page,
487 const int cmsg_type, const char *const cmsg_type_str,
488 const unsigned int opts_len)
490 unsigned int len = CMSG_SPACE(opts_len);
491 struct cmsghdr *cmsg = get_cmsghdr(page, len);
493 cmsg->cmsg_len = CMSG_LEN(opts_len);
494 cmsg->cmsg_level = SOL_IP;
495 cmsg->cmsg_type = cmsg_type;
497 for (i = 0; i < opts_len; ++i)
498 CMSG_DATA(cmsg)[i] = 'A' + i;
500 mh->msg_control = cmsg;
501 mh->msg_controllen = len;
503 int rc = sendmsg(-1, mh, 0);
504 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
505 ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
506 ", cmsg_level=SOL_IP, cmsg_type=%s, cmsg_data=[",
507 (unsigned) cmsg->cmsg_len, cmsg_type_str);
508 print_ip_opts(CMSG_DATA(cmsg), opts_len);
509 printf("]}], msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n",
510 len, rc, errno2name());
522 struct sockaddr_in offender;
526 test_ip_recverr(struct msghdr *const mh, void *const page,
527 const int cmsg_type, const char *const cmsg_type_str)
529 const unsigned int len = CMSG_SPACE(sizeof(struct sock_ee));
530 struct cmsghdr *const cmsg = get_cmsghdr(page, len);
532 cmsg->cmsg_len = CMSG_LEN(sizeof(struct sock_ee));
533 cmsg->cmsg_level = SOL_IP;
534 cmsg->cmsg_type = cmsg_type;
536 struct sock_ee *const e = (struct sock_ee *) CMSG_DATA(cmsg);
537 e->ee_errno = 0xdeadbeef;
541 e->ee_info = 0xfacefeed;
542 e->ee_data = 0xbadc0ded;
543 e->offender.sin_family = AF_INET,
544 e->offender.sin_port = htons(12345),
545 e->offender.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
547 mh->msg_control = cmsg;
548 mh->msg_controllen = len;
550 int rc = sendmsg(-1, mh, 0);
551 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
552 ", msg_iovlen=0, msg_control=[{cmsg_len=%u, cmsg_level=SOL_IP"
553 ", cmsg_type=%s, cmsg_data={ee_errno=%u, ee_origin=%u"
554 ", ee_type=%u, ee_code=%u, ee_info=%u, ee_data=%u"
555 ", offender={sa_family=AF_INET, sin_port=htons(%hu)"
556 ", sin_addr=inet_addr(\"127.0.0.1\")}}}]"
557 ", msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n",
558 (unsigned) cmsg->cmsg_len, cmsg_type_str,
559 e->ee_errno, e->ee_origin, e->ee_type,
560 e->ee_code, e->ee_info, e->ee_data,
561 ntohs(e->offender.sin_port),
562 len, rc, errno2name());
566 #ifdef IP_ORIGDSTADDR
568 test_ip_origdstaddr(struct msghdr *const mh, void *const page,
569 const int cmsg_type, const char *const cmsg_type_str)
571 const unsigned int len = CMSG_SPACE(sizeof(struct sockaddr_in));
572 struct cmsghdr *const cmsg = get_cmsghdr(page, len);
574 cmsg->cmsg_len = CMSG_LEN(sizeof(struct sockaddr_in));
575 cmsg->cmsg_level = SOL_IP;
576 cmsg->cmsg_type = cmsg_type;
578 struct sockaddr_in *const sin = (struct sockaddr_in *) CMSG_DATA(cmsg);
579 sin->sin_family = AF_INET,
580 sin->sin_port = htons(12345),
581 sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
583 mh->msg_control = cmsg;
584 mh->msg_controllen = len;
586 int rc = sendmsg(-1, mh, 0);
587 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
588 ", msg_iovlen=0, msg_control=[{cmsg_len=%u, cmsg_level=SOL_IP"
589 ", cmsg_type=%s, cmsg_data={sa_family=AF_INET"
590 ", sin_port=htons(%hu), sin_addr=inet_addr(\"127.0.0.1\")}}]"
591 ", msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n",
592 (unsigned) cmsg->cmsg_len, cmsg_type_str,
593 ntohs(sin->sin_port), len, rc, errno2name());
598 test_sol_ip(struct msghdr *const mh, void *const page)
600 test_ip_pktinfo(mh, page, VAL_STR(IP_PKTINFO));
601 test_ip_uint(mh, page, VAL_STR(IP_TTL));
602 test_ip_uint8_t(mh, page, VAL_STR(IP_TOS));
603 test_ip_opts(mh, page, VAL_STR(IP_RECVOPTS), 1);
604 test_ip_opts(mh, page, VAL_STR(IP_RECVOPTS), 2);
605 test_ip_opts(mh, page, VAL_STR(IP_RECVOPTS), 3);
606 test_ip_opts(mh, page, VAL_STR(IP_RECVOPTS), 4);
607 test_ip_opts(mh, page, VAL_STR(IP_RETOPTS), 5);
608 test_ip_opts(mh, page, VAL_STR(IP_RETOPTS), 6);
609 test_ip_opts(mh, page, VAL_STR(IP_RETOPTS), 7);
610 test_ip_opts(mh, page, VAL_STR(IP_RETOPTS), 8);
612 test_ip_recverr(mh, page, VAL_STR(IP_RECVERR));
614 #ifdef IP_ORIGDSTADDR
615 test_ip_origdstaddr(mh, page, VAL_STR(IP_ORIGDSTADDR));
618 test_ip_uint(mh, page, VAL_STR(IP_CHECKSUM));
620 test_scm_security(mh, CMSG_LEN(0), page, 0, CMSG_LEN(0),
622 test_unknown_type(mh, page, VAL_STR(SOL_IP), "IP_???");
626 test_unknown_level(struct msghdr *const mh, void *const page)
628 struct cmsghdr *cmsg = get_cmsghdr(page, CMSG_LEN(0));
630 cmsg->cmsg_len = CMSG_LEN(0);
631 cmsg->cmsg_level = SOL_TCP;
632 cmsg->cmsg_type = 0xdeadbeef;
634 mh->msg_control = cmsg;
635 mh->msg_controllen = cmsg->cmsg_len;
637 int rc = sendmsg(-1, mh, 0);
638 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
639 ", msg_iovlen=0, msg_control=[{cmsg_len=%u, cmsg_level=%s"
640 ", cmsg_type=%#x}], msg_controllen=%u, msg_flags=0}"
641 ", 0) = %d %s (%m)\n",
642 (unsigned) cmsg->cmsg_len, "SOL_TCP", cmsg->cmsg_type,
643 (unsigned) mh->msg_controllen, rc, errno2name());
646 int main(int ac, const char **av)
648 int rc = sendmsg(-1, 0, 0);
649 printf("sendmsg(-1, NULL, 0) = %d %s (%m)\n", rc, errno2name());
651 struct msghdr *mh = tail_alloc(sizeof(*mh));
652 memset(mh, 0, sizeof(*mh));
654 rc = sendmsg(-1, mh + 1, 0);
655 printf("sendmsg(-1, %p, 0) = %d %s (%m)\n",
656 mh + 1, rc, errno2name());
658 void *page = tail_alloc(1) + 1;
659 mh->msg_control = page;
660 mh->msg_controllen = CMSG_LEN(0);
661 rc = sendmsg(-1, mh, 0);
662 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
663 ", msg_iovlen=0, msg_control=%p, msg_controllen=%u"
664 ", msg_flags=0}, 0) = %d %s (%m)\n",
665 page, (unsigned) CMSG_LEN(0), rc, errno2name());
667 test_sol_socket(mh, page);
668 test_sol_ip(mh, page);
669 test_unknown_level(mh, page);
671 puts("+++ exited with 0 +++");