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);
64 print_fds(const struct cmsghdr *const cmsg, const size_t cmsg_len)
66 size_t nfd = cmsg_len > CMSG_LEN(0)
67 ? (cmsg_len - CMSG_LEN(0)) / sizeof(int) : 0;
71 printf(", cmsg_data=[");
72 int *fdp = (int *) CMSG_DATA(cmsg);
74 for (i = 0; i < nfd; ++i) {
83 test_scm_rights1(struct msghdr *const mh,
84 const size_t msg_controllen,
86 const void *const src,
87 const size_t cmsg_len)
89 const size_t aligned_cms_len =
90 cmsg_len > CMSG_LEN(0) ? CMSG_ALIGN(cmsg_len) : CMSG_LEN(0);
91 if (cmsg_len >= CMSG_LEN(0)
92 && aligned_cms_len + CMSG_LEN(0) <= msg_controllen)
95 struct cmsghdr *cmsg = get_cmsghdr(page, msg_controllen);
97 if (msg_controllen >= MIN_SIZE_OF(struct cmsghdr, cmsg_len))
98 cmsg->cmsg_len = cmsg_len;
99 if (msg_controllen >= MIN_SIZE_OF(struct cmsghdr, cmsg_level))
100 cmsg->cmsg_level = SOL_SOCKET;
101 if (msg_controllen >= MIN_SIZE_OF(struct cmsghdr, cmsg_type))
102 cmsg->cmsg_type = SCM_RIGHTS;
105 cmsg_len < msg_controllen ? cmsg_len : msg_controllen;
106 if (src_len > CMSG_LEN(0))
107 memcpy(CMSG_DATA(cmsg), src, src_len - CMSG_LEN(0));
109 mh->msg_control = cmsg;
110 mh->msg_controllen = msg_controllen;
112 int rc = sendmsg(-1, mh, 0);
113 int saved_errno = errno;
115 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
117 if (msg_controllen < CMSG_LEN(0)) {
119 printf(", msg_control=%p", cmsg);
121 printf(", msg_control=[{cmsg_len=%lu, cmsg_level=SOL_SOCKET"
122 ", cmsg_type=SCM_RIGHTS", (unsigned long) cmsg_len);
123 print_fds(cmsg, src_len);
125 if (aligned_cms_len < msg_controllen)
126 printf(", %p", (void *) cmsg + aligned_cms_len);
131 printf(", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
132 (unsigned long) msg_controllen, rc, errno2name());
136 test_scm_rights2(struct msghdr *const mh,
137 const size_t msg_controllen,
139 const int *const *const src,
140 const size_t *const cmsg_len)
142 const size_t aligned_cms_len[2] = {
143 cmsg_len[0] > CMSG_LEN(0) ? CMSG_ALIGN(cmsg_len[0]) : CMSG_LEN(0),
144 cmsg_len[1] > CMSG_LEN(0) ? CMSG_ALIGN(cmsg_len[1]) : CMSG_LEN(0)
146 if (cmsg_len[0] < CMSG_LEN(0)
147 || aligned_cms_len[0] + CMSG_LEN(0) > msg_controllen
148 || aligned_cms_len[0] + aligned_cms_len[1] + CMSG_LEN(0) <= msg_controllen)
151 struct cmsghdr *const cmsg[2] = {
152 get_cmsghdr(page, msg_controllen),
153 (void *) get_cmsghdr(page, msg_controllen) + aligned_cms_len[0]
155 cmsg[0]->cmsg_len = cmsg_len[0];
156 cmsg[0]->cmsg_level = SOL_SOCKET;
157 cmsg[0]->cmsg_type = SCM_RIGHTS;
158 if (cmsg_len[0] > CMSG_LEN(0))
159 memcpy(CMSG_DATA(cmsg[0]), src[0], cmsg_len[0] - CMSG_LEN(0));
161 const size_t msg_controllen1 = msg_controllen - aligned_cms_len[0];
162 if (msg_controllen1 >= MIN_SIZE_OF(struct cmsghdr, cmsg_len))
163 cmsg[1]->cmsg_len = cmsg_len[1];
164 if (msg_controllen >= MIN_SIZE_OF(struct cmsghdr, cmsg_level))
165 cmsg[1]->cmsg_level = SOL_SOCKET;
166 if (msg_controllen >= MIN_SIZE_OF(struct cmsghdr, cmsg_type))
167 cmsg[1]->cmsg_type = SCM_RIGHTS;
169 cmsg_len[1] < msg_controllen1 ? cmsg_len[1] : msg_controllen1;
170 if (src1_len > CMSG_LEN(0))
171 memcpy(CMSG_DATA(cmsg[1]), src[1], src1_len - CMSG_LEN(0));
173 mh->msg_control = cmsg[0];
174 mh->msg_controllen = msg_controllen;
176 int rc = sendmsg(-1, mh, 0);
177 int saved_errno = errno;
179 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
180 ", msg_iovlen=0, msg_control=[{cmsg_len=%lu"
181 ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS",
182 (unsigned long) cmsg_len[0]);
183 print_fds(cmsg[0], cmsg_len[0]);
184 printf("}, {cmsg_len=%lu, cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS",
185 (unsigned long) cmsg_len[1]);
186 print_fds(cmsg[1], src1_len);
188 if (aligned_cms_len[1] < msg_controllen1)
189 printf(", %p", (void *) cmsg[1] + aligned_cms_len[1]);
193 printf(", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
194 (unsigned long) msg_controllen, rc, errno2name());
198 print_security(const struct cmsghdr *const cmsg, const size_t cmsg_len)
200 int n = cmsg_len > CMSG_LEN(0) ? cmsg_len - CMSG_LEN(0) : 0;
204 printf(", cmsg_data=\"%.*s\"", n, CMSG_DATA(cmsg));
208 test_scm_security(struct msghdr *const mh,
209 const size_t msg_controllen,
211 const void *const src,
212 const size_t cmsg_len,
213 const int cmsg_level,
214 const char *const cmsg_level_str)
216 const size_t aligned_cms_len =
217 cmsg_len > CMSG_LEN(0) ? CMSG_ALIGN(cmsg_len) : CMSG_LEN(0);
218 if (cmsg_len >= CMSG_LEN(0)
219 && aligned_cms_len + CMSG_LEN(0) <= msg_controllen)
222 struct cmsghdr *cmsg = get_cmsghdr(page, msg_controllen);
224 cmsg->cmsg_len = cmsg_len;
225 cmsg->cmsg_level = cmsg_level;
226 cmsg->cmsg_type = SCM_SECURITY;
229 cmsg_len < msg_controllen ? cmsg_len : msg_controllen;
230 if (src_len > CMSG_LEN(0))
231 memcpy(CMSG_DATA(cmsg), src, src_len - CMSG_LEN(0));
233 mh->msg_control = cmsg;
234 mh->msg_controllen = msg_controllen;
236 int rc = sendmsg(-1, mh, 0);
237 int saved_errno = errno;
239 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
240 ", msg_iovlen=0, msg_control=[{cmsg_len=%lu, cmsg_level=%s"
241 ", cmsg_type=SCM_SECURITY",
242 (unsigned long) cmsg_len, cmsg_level_str);
243 print_security(cmsg, src_len);
245 if (aligned_cms_len < msg_controllen)
246 printf(", %p", (void *) cmsg + aligned_cms_len);
250 printf(", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
251 (unsigned long) msg_controllen, rc, errno2name());
255 test_unknown_type(struct msghdr *const mh,
257 const int cmsg_level,
258 const char *const cmsg_level_str,
259 const char *const cmsg_type_str)
261 struct cmsghdr *cmsg = get_cmsghdr(page, CMSG_LEN(0));
263 cmsg->cmsg_len = CMSG_LEN(0);
264 cmsg->cmsg_level = cmsg_level;
265 cmsg->cmsg_type = 0xfacefeed;
267 mh->msg_control = cmsg;
268 mh->msg_controllen = cmsg->cmsg_len;
270 int rc = sendmsg(-1, mh, 0);
271 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
272 ", msg_iovlen=0, msg_control=[{cmsg_len=%u, cmsg_level=%s"
273 ", cmsg_type=%#x /* %s */}], msg_controllen=%u, msg_flags=0}"
274 ", 0) = %d %s (%m)\n",
275 (unsigned) cmsg->cmsg_len, cmsg_level_str, cmsg->cmsg_type,
276 cmsg_type_str, (unsigned) mh->msg_controllen, rc, errno2name());
280 test_sol_socket(struct msghdr *const mh, void *const page)
282 static const int fds0[] = { -10, -11, -12, -13 };
283 static const int fds1[] = { -15, -16, -17, -18 };
284 size_t msg_controllen, max_msg_controllen;
286 max_msg_controllen = CMSG_SPACE(sizeof(fds0)) + sizeof(*fds0) - 1;
287 for (msg_controllen = 0;
288 msg_controllen <= max_msg_controllen;
293 cmsg_len <= msg_controllen + CMSG_LEN(0);
295 test_scm_rights1(mh, msg_controllen,
296 page, fds0, cmsg_len);
301 CMSG_SPACE(sizeof(fds0)) + CMSG_SPACE(sizeof(fds1)) +
303 for (msg_controllen = CMSG_LEN(0) * 2;
304 msg_controllen <= max_msg_controllen;
306 static const int *const fdps[] = { fds0, fds1 };
309 for (cmsg_len[0] = CMSG_LEN(0);
310 CMSG_ALIGN(cmsg_len[0]) + CMSG_LEN(0) <= msg_controllen
311 && CMSG_ALIGN(cmsg_len[0]) <= CMSG_SPACE(sizeof(fds0));
313 const size_t msg_controllen1 =
314 msg_controllen - CMSG_ALIGN(cmsg_len[0]);
316 for (cmsg_len[1] = 0;
317 cmsg_len[1] <= msg_controllen1 + CMSG_LEN(0);
319 test_scm_rights2(mh, msg_controllen,
320 page, fdps, cmsg_len);
325 static const char text[16] = "0123456789abcdef";
326 max_msg_controllen = CMSG_SPACE(sizeof(text)) + CMSG_LEN(0) - 1;
327 for (msg_controllen = CMSG_LEN(0);
328 msg_controllen <= max_msg_controllen;
333 cmsg_len <= msg_controllen + CMSG_LEN(0)
334 && cmsg_len <= CMSG_LEN(sizeof(text));
336 test_scm_security(mh, msg_controllen,
337 page, text, cmsg_len,
338 VAL_STR(SOL_SOCKET));
342 test_unknown_type(mh, page, VAL_STR(SOL_SOCKET), "SCM_???");
346 test_ip_pktinfo(struct msghdr *const mh, void *const page,
347 const int cmsg_type, const char *const cmsg_type_str)
349 const unsigned int len = CMSG_SPACE(sizeof(struct in_pktinfo));
350 struct cmsghdr *const cmsg = get_cmsghdr(page, len);
352 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
353 cmsg->cmsg_level = SOL_IP;
354 cmsg->cmsg_type = cmsg_type;
356 struct in_pktinfo *const info = (struct in_pktinfo *) CMSG_DATA(cmsg);
357 #ifdef HAVE_IF_INDEXTONAME
358 info->ipi_ifindex = if_nametoindex("lo");
360 info->ipi_ifindex = 1;
362 info->ipi_spec_dst.s_addr = inet_addr("1.2.3.4");
363 info->ipi_addr.s_addr = inet_addr("5.6.7.8");
365 mh->msg_control = cmsg;
366 mh->msg_controllen = len;
368 int rc = sendmsg(-1, mh, 0);
369 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
370 ", msg_iovlen=0, msg_control=[{cmsg_len=%u, cmsg_level=SOL_IP"
371 ", cmsg_type=%s, cmsg_data={ipi_ifindex=%s"
372 ", ipi_spec_dst=inet_addr(\"%s\")"
373 ", ipi_addr=inet_addr(\"%s\")}}]"
374 ", msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n",
375 (unsigned) cmsg->cmsg_len, cmsg_type_str,
376 #ifdef HAVE_IF_INDEXTONAME
377 "if_nametoindex(\"lo\")",
381 "1.2.3.4", "5.6.7.8", len, rc, errno2name());
385 test_ip_uint(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(int));
389 struct cmsghdr *const cmsg = get_cmsghdr(page, len);
391 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
392 cmsg->cmsg_level = SOL_IP;
393 cmsg->cmsg_type = cmsg_type;
395 unsigned int *u = (void *) CMSG_DATA(cmsg);
398 mh->msg_control = cmsg;
399 mh->msg_controllen = len;
401 int rc = sendmsg(-1, mh, 0);
402 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
403 ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
404 ", cmsg_level=SOL_IP, cmsg_type=%s, cmsg_data=[%u]}]"
405 ", msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n",
406 (unsigned) cmsg->cmsg_len, cmsg_type_str, *u, len,
411 test_ip_uint8_t(struct msghdr *const mh, void *const page,
412 const int cmsg_type, const char *const cmsg_type_str)
414 const unsigned int len = CMSG_SPACE(1);
415 struct cmsghdr *const cmsg = get_cmsghdr(page, len);
417 cmsg->cmsg_len = CMSG_LEN(1);
418 cmsg->cmsg_level = SOL_IP;
419 cmsg->cmsg_type = cmsg_type;
420 *CMSG_DATA(cmsg) = 'A';
422 mh->msg_control = cmsg;
423 mh->msg_controllen = len;
425 int rc = sendmsg(-1, mh, 0);
426 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
427 ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
428 ", cmsg_level=SOL_IP, cmsg_type=%s, cmsg_data=[%#x]}]"
429 ", msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n",
430 (unsigned) cmsg->cmsg_len, cmsg_type_str,
431 (unsigned) (uint8_t) 'A', len, rc, errno2name());
435 print_ip_opts(const void *const cmsg_data, const unsigned int data_len)
437 const unsigned char *const opts = cmsg_data;
439 for (i = 0; i < data_len; ++i) {
442 printf("0x%02x", opts[i]);
447 test_ip_opts(struct msghdr *const mh, void *const page,
448 const int cmsg_type, const char *const cmsg_type_str,
449 const unsigned int opts_len)
451 unsigned int len = CMSG_SPACE(opts_len);
452 struct cmsghdr *cmsg = get_cmsghdr(page, len);
454 cmsg->cmsg_len = CMSG_LEN(opts_len);
455 cmsg->cmsg_level = SOL_IP;
456 cmsg->cmsg_type = cmsg_type;
458 for (i = 0; i < opts_len; ++i)
459 CMSG_DATA(cmsg)[i] = 'A' + i;
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=[",
468 (unsigned) cmsg->cmsg_len, cmsg_type_str);
469 print_ip_opts(CMSG_DATA(cmsg), opts_len);
470 printf("]}], msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n",
471 len, rc, errno2name());
483 struct sockaddr_in offender;
487 test_ip_recverr(struct msghdr *const mh, void *const page,
488 const int cmsg_type, const char *const cmsg_type_str)
490 const unsigned int len = CMSG_SPACE(sizeof(struct sock_ee));
491 struct cmsghdr *const cmsg = get_cmsghdr(page, len);
493 cmsg->cmsg_len = CMSG_LEN(sizeof(struct sock_ee));
494 cmsg->cmsg_level = SOL_IP;
495 cmsg->cmsg_type = cmsg_type;
497 struct sock_ee *const e = (struct sock_ee *) CMSG_DATA(cmsg);
498 e->ee_errno = 0xdeadbeef;
502 e->ee_info = 0xfacefeed;
503 e->ee_data = 0xbadc0ded;
504 e->offender.sin_family = AF_INET,
505 e->offender.sin_port = htons(12345),
506 e->offender.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
508 mh->msg_control = cmsg;
509 mh->msg_controllen = len;
511 int rc = sendmsg(-1, mh, 0);
512 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
513 ", msg_iovlen=0, msg_control=[{cmsg_len=%u, cmsg_level=SOL_IP"
514 ", cmsg_type=%s, cmsg_data={ee_errno=%u, ee_origin=%u"
515 ", ee_type=%u, ee_code=%u, ee_info=%u, ee_data=%u"
516 ", offender={sa_family=AF_INET, sin_port=htons(%hu)"
517 ", sin_addr=inet_addr(\"127.0.0.1\")}}}]"
518 ", msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n",
519 (unsigned) cmsg->cmsg_len, cmsg_type_str,
520 e->ee_errno, e->ee_origin, e->ee_type,
521 e->ee_code, e->ee_info, e->ee_data,
522 ntohs(e->offender.sin_port),
523 len, rc, errno2name());
527 #ifdef IP_ORIGDSTADDR
529 test_ip_origdstaddr(struct msghdr *const mh, void *const page,
530 const int cmsg_type, const char *const cmsg_type_str)
532 const unsigned int len = CMSG_SPACE(sizeof(struct sockaddr_in));
533 struct cmsghdr *const cmsg = get_cmsghdr(page, len);
535 cmsg->cmsg_len = CMSG_LEN(sizeof(struct sockaddr_in));
536 cmsg->cmsg_level = SOL_IP;
537 cmsg->cmsg_type = cmsg_type;
539 struct sockaddr_in *const sin = (struct sockaddr_in *) CMSG_DATA(cmsg);
540 sin->sin_family = AF_INET,
541 sin->sin_port = htons(12345),
542 sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
544 mh->msg_control = cmsg;
545 mh->msg_controllen = len;
547 int rc = sendmsg(-1, mh, 0);
548 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
549 ", msg_iovlen=0, msg_control=[{cmsg_len=%u, cmsg_level=SOL_IP"
550 ", cmsg_type=%s, cmsg_data={sa_family=AF_INET"
551 ", sin_port=htons(%hu), sin_addr=inet_addr(\"127.0.0.1\")}}]"
552 ", msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n",
553 (unsigned) cmsg->cmsg_len, cmsg_type_str,
554 ntohs(sin->sin_port), len, rc, errno2name());
559 test_sol_ip(struct msghdr *const mh, void *const page)
561 test_ip_pktinfo(mh, page, VAL_STR(IP_PKTINFO));
562 test_ip_uint(mh, page, VAL_STR(IP_TTL));
563 test_ip_uint8_t(mh, page, VAL_STR(IP_TOS));
564 test_ip_opts(mh, page, VAL_STR(IP_RECVOPTS), 1);
565 test_ip_opts(mh, page, VAL_STR(IP_RECVOPTS), 2);
566 test_ip_opts(mh, page, VAL_STR(IP_RECVOPTS), 3);
567 test_ip_opts(mh, page, VAL_STR(IP_RECVOPTS), 4);
568 test_ip_opts(mh, page, VAL_STR(IP_RETOPTS), 5);
569 test_ip_opts(mh, page, VAL_STR(IP_RETOPTS), 6);
570 test_ip_opts(mh, page, VAL_STR(IP_RETOPTS), 7);
571 test_ip_opts(mh, page, VAL_STR(IP_RETOPTS), 8);
573 test_ip_recverr(mh, page, VAL_STR(IP_RECVERR));
575 #ifdef IP_ORIGDSTADDR
576 test_ip_origdstaddr(mh, page, VAL_STR(IP_ORIGDSTADDR));
579 test_ip_uint(mh, page, VAL_STR(IP_CHECKSUM));
581 test_scm_security(mh, CMSG_LEN(0), page, 0, CMSG_LEN(0),
583 test_unknown_type(mh, page, VAL_STR(SOL_IP), "IP_???");
587 test_unknown_level(struct msghdr *const mh, void *const page)
589 struct cmsghdr *cmsg = get_cmsghdr(page, CMSG_LEN(0));
591 cmsg->cmsg_len = CMSG_LEN(0);
592 cmsg->cmsg_level = SOL_TCP;
593 cmsg->cmsg_type = 0xdeadbeef;
595 mh->msg_control = cmsg;
596 mh->msg_controllen = cmsg->cmsg_len;
598 int rc = sendmsg(-1, mh, 0);
599 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
600 ", msg_iovlen=0, msg_control=[{cmsg_len=%u, cmsg_level=%s"
601 ", cmsg_type=%#x}], msg_controllen=%u, msg_flags=0}"
602 ", 0) = %d %s (%m)\n",
603 (unsigned) cmsg->cmsg_len, "SOL_TCP", cmsg->cmsg_type,
604 (unsigned) mh->msg_controllen, rc, errno2name());
607 int main(int ac, const char **av)
609 int rc = sendmsg(-1, 0, 0);
610 printf("sendmsg(-1, NULL, 0) = %d %s (%m)\n", rc, errno2name());
612 struct msghdr *mh = tail_alloc(sizeof(*mh));
613 memset(mh, 0, sizeof(*mh));
615 rc = sendmsg(-1, mh + 1, 0);
616 printf("sendmsg(-1, %p, 0) = %d %s (%m)\n",
617 mh + 1, rc, errno2name());
619 void *page = tail_alloc(1) + 1;
620 mh->msg_control = page;
621 mh->msg_controllen = CMSG_LEN(0);
622 rc = sendmsg(-1, mh, 0);
623 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
624 ", msg_iovlen=0, msg_control=%p, msg_controllen=%u"
625 ", msg_flags=0}, 0) = %d %s (%m)\n",
626 page, (unsigned) CMSG_LEN(0), rc, errno2name());
628 test_sol_socket(mh, page);
629 test_sol_ip(mh, page);
630 test_unknown_level(mh, page);
632 puts("+++ exited with 0 +++");