17555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin/*
27555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin * Check decoding of struct msghdr ancillary data.
37555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin *
47555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin * Copyright (c) 2016 Dmitry V. Levin <ldv@altlinux.org>
539bac055674d23770b9a724221b728e443196ea7Elliott Hughes * Copyright (c) 2016-2017 The strace developers.
67555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin * All rights reserved.
77555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin *
87555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin * Redistribution and use in source and binary forms, with or without
97555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin * modification, are permitted provided that the following conditions
107555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin * are met:
117555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin * 1. Redistributions of source code must retain the above copyright
127555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin *    notice, this list of conditions and the following disclaimer.
137555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin * 2. Redistributions in binary form must reproduce the above copyright
147555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin *    notice, this list of conditions and the following disclaimer in the
157555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin *    documentation and/or other materials provided with the distribution.
167555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin * 3. The name of the author may not be used to endorse or promote products
177555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin *    derived from this software without specific prior written permission.
187555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin *
197555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
207555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
217555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
227555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
237555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
247555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
257555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
267555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
277555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
287555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
297555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin */
307555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
317555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin#include "tests.h"
327555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin#include <errno.h>
338da9668b1ba68ec71ad4d3dd96f9c73ca38430caDmitry V. Levin#include <limits.h>
347555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin#include <stddef.h>
357555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin#include <stdio.h>
367555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin#include <string.h>
377555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin#include <unistd.h>
387555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin#include <sys/socket.h>
397555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin#include <net/if.h>
407555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin#include <netinet/in.h>
417555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin#include <arpa/inet.h>
427555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
43dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes#include "xlat.h"
44dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes#include "xlat/scmvals.h"
45dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes
467555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin#ifndef SOL_IP
477555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin# define SOL_IP 0
487555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin#endif
497555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin#ifndef SOL_TCP
507555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin# define SOL_TCP 6
517555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin#endif
527555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
537555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin#ifndef SCM_SECURITY
547555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin# define SCM_SECURITY 3
557555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin#endif
567555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
577555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin#define MIN_SIZE_OF(type, member) \
587555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	(offsetof(type, member) + sizeof(((type *) 0)->member))
597555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
607555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levinstatic struct cmsghdr *
617555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levinget_cmsghdr(void *const page, const size_t len)
627555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin{
637555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	return page - CMSG_ALIGN(len);
647555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin}
657555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
667555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levinstatic void
677555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levinprint_fds(const struct cmsghdr *const cmsg, const size_t cmsg_len)
687555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin{
697555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	size_t nfd = cmsg_len > CMSG_LEN(0)
707555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		     ? (cmsg_len - CMSG_LEN(0)) / sizeof(int) : 0;
717555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	if (!nfd)
727555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		return;
737555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
747555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	printf(", cmsg_data=[");
757555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	int *fdp = (int *) CMSG_DATA(cmsg);
767555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	size_t i;
777555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	for (i = 0; i < nfd; ++i) {
787555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		if (i)
797555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin			printf(", ");
80074c630705aa65f0795209a0e8ce954520226e57Dmitry V. Levin#if !VERBOSE
81d35d5ecc4d8ac1bd3617e6f5f85ca738041130ebDmitry V. Levin		if (i >= DEFAULT_STRLEN) {
82d35d5ecc4d8ac1bd3617e6f5f85ca738041130ebDmitry V. Levin			printf("...");
83d35d5ecc4d8ac1bd3617e6f5f85ca738041130ebDmitry V. Levin			break;
84d35d5ecc4d8ac1bd3617e6f5f85ca738041130ebDmitry V. Levin		}
85d35d5ecc4d8ac1bd3617e6f5f85ca738041130ebDmitry V. Levin#endif
867555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		printf("%d", fdp[i]);
877555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	}
887555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	printf("]");
897555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin}
907555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
917555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levinstatic void
927555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levintest_scm_rights1(struct msghdr *const mh,
937555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		 const size_t msg_controllen,
947555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		 void *const page,
957555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		 const void *const src,
967555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		 const size_t cmsg_len)
977555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin{
987555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	const size_t aligned_cms_len =
997555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		cmsg_len > CMSG_LEN(0) ? CMSG_ALIGN(cmsg_len) : CMSG_LEN(0);
1007555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	if (cmsg_len >= CMSG_LEN(0)
1017555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	    && aligned_cms_len + CMSG_LEN(0) <= msg_controllen)
1027555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		return;
1037555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
1047555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	struct cmsghdr *cmsg = get_cmsghdr(page, msg_controllen);
1057555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
1067555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	if (msg_controllen >= MIN_SIZE_OF(struct cmsghdr, cmsg_len))
1077555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		cmsg->cmsg_len = cmsg_len;
1087555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	if (msg_controllen >= MIN_SIZE_OF(struct cmsghdr, cmsg_level))
1097555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		cmsg->cmsg_level = SOL_SOCKET;
1107555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	if (msg_controllen >= MIN_SIZE_OF(struct cmsghdr, cmsg_type))
1117555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		cmsg->cmsg_type = SCM_RIGHTS;
1127555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
1137555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	size_t src_len =
1147555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		cmsg_len < msg_controllen ? cmsg_len : msg_controllen;
1157555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	if (src_len > CMSG_LEN(0))
1167555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		memcpy(CMSG_DATA(cmsg), src, src_len - CMSG_LEN(0));
1177555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
1187555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	mh->msg_control = cmsg;
1197555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	mh->msg_controllen = msg_controllen;
1207555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
1217555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	int rc = sendmsg(-1, mh, 0);
1227555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	int saved_errno = errno;
1237555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
1247555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
1257555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       ", msg_iovlen=0");
1267555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	if (msg_controllen < CMSG_LEN(0)) {
1277555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		if (msg_controllen)
1287555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin			printf(", msg_control=%p", cmsg);
1297555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	} else {
1307555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		printf(", msg_control=[{cmsg_len=%lu, cmsg_level=SOL_SOCKET"
1317555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		       ", cmsg_type=SCM_RIGHTS", (unsigned long) cmsg_len);
1327555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		print_fds(cmsg, src_len);
1337555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		printf("}");
1347555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		if (aligned_cms_len < msg_controllen)
1357555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin			printf(", %p", (void *) cmsg + aligned_cms_len);
1367555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		printf("]");
1377555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	}
1387555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
1397555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	errno = saved_errno;
1407555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	printf(", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
1417555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       (unsigned long) msg_controllen, rc, errno2name());
1427555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin}
1437555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
1447555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levinstatic void
1457555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levintest_scm_rights2(struct msghdr *const mh,
1467555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		 const size_t msg_controllen,
1477555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		 void *const page,
1487555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		 const int *const *const src,
1497555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		 const size_t *const cmsg_len)
1507555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin{
1517555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	const size_t aligned_cms_len[2] = {
1527555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		cmsg_len[0] > CMSG_LEN(0) ? CMSG_ALIGN(cmsg_len[0]) : CMSG_LEN(0),
1537555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		cmsg_len[1] > CMSG_LEN(0) ? CMSG_ALIGN(cmsg_len[1]) : CMSG_LEN(0)
1547555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	};
1557555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	if (cmsg_len[0] < CMSG_LEN(0)
1567555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	    || aligned_cms_len[0] + CMSG_LEN(0) > msg_controllen
1577555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	    || aligned_cms_len[0] + aligned_cms_len[1] + CMSG_LEN(0) <= msg_controllen)
1587555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		return;
1597555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
1607555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	struct cmsghdr *const cmsg[2] = {
1617555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		get_cmsghdr(page, msg_controllen),
1627555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		(void *) get_cmsghdr(page, msg_controllen) + aligned_cms_len[0]
1637555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	};
1647555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	cmsg[0]->cmsg_len = cmsg_len[0];
1657555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	cmsg[0]->cmsg_level = SOL_SOCKET;
1667555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	cmsg[0]->cmsg_type = SCM_RIGHTS;
1677555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	if (cmsg_len[0] > CMSG_LEN(0))
1687555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		memcpy(CMSG_DATA(cmsg[0]), src[0], cmsg_len[0] - CMSG_LEN(0));
1697555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
1707555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	const size_t msg_controllen1 = msg_controllen - aligned_cms_len[0];
1717555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	if (msg_controllen1 >= MIN_SIZE_OF(struct cmsghdr, cmsg_len))
1727555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		cmsg[1]->cmsg_len = cmsg_len[1];
1737555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	if (msg_controllen >= MIN_SIZE_OF(struct cmsghdr, cmsg_level))
1747555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		cmsg[1]->cmsg_level = SOL_SOCKET;
1757555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	if (msg_controllen >= MIN_SIZE_OF(struct cmsghdr, cmsg_type))
1767555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		cmsg[1]->cmsg_type = SCM_RIGHTS;
1777555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	size_t src1_len =
1787555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		cmsg_len[1] < msg_controllen1 ? cmsg_len[1] : msg_controllen1;
1797555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	if (src1_len > CMSG_LEN(0))
1807555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		memcpy(CMSG_DATA(cmsg[1]), src[1], src1_len - CMSG_LEN(0));
1817555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
1827555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	mh->msg_control = cmsg[0];
1837555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	mh->msg_controllen = msg_controllen;
1847555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
1857555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	int rc = sendmsg(-1, mh, 0);
1867555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	int saved_errno = errno;
1877555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
1887555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
1897555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       ", msg_iovlen=0, msg_control=[{cmsg_len=%lu"
1907555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS",
1917555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       (unsigned long) cmsg_len[0]);
1927555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	print_fds(cmsg[0], cmsg_len[0]);
1937555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	printf("}, {cmsg_len=%lu, cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS",
1947555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       (unsigned long) cmsg_len[1]);
1957555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	print_fds(cmsg[1], src1_len);
1967555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	printf("}");
1977555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	if (aligned_cms_len[1] < msg_controllen1)
1987555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		printf(", %p", (void *) cmsg[1] + aligned_cms_len[1]);
1997555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	printf("]");
2007555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
2017555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	errno = saved_errno;
2027555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	printf(", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
2037555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       (unsigned long) msg_controllen, rc, errno2name());
2047555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin}
2057555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
2067555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levinstatic void
207d35d5ecc4d8ac1bd3617e6f5f85ca738041130ebDmitry V. Levintest_scm_rights3(struct msghdr *const mh, void *const page, const size_t nfds)
208d35d5ecc4d8ac1bd3617e6f5f85ca738041130ebDmitry V. Levin{
209d35d5ecc4d8ac1bd3617e6f5f85ca738041130ebDmitry V. Levin	const size_t len = CMSG_SPACE(sizeof(int) * nfds);
210d35d5ecc4d8ac1bd3617e6f5f85ca738041130ebDmitry V. Levin	struct cmsghdr *cmsg = get_cmsghdr(page, len);
211d35d5ecc4d8ac1bd3617e6f5f85ca738041130ebDmitry V. Levin
212d35d5ecc4d8ac1bd3617e6f5f85ca738041130ebDmitry V. Levin	cmsg->cmsg_len = CMSG_LEN(sizeof(int) * nfds);
213d35d5ecc4d8ac1bd3617e6f5f85ca738041130ebDmitry V. Levin	cmsg->cmsg_level = SOL_SOCKET;
214d35d5ecc4d8ac1bd3617e6f5f85ca738041130ebDmitry V. Levin	cmsg->cmsg_type = SCM_RIGHTS;
215d35d5ecc4d8ac1bd3617e6f5f85ca738041130ebDmitry V. Levin	int *fdp = (int *) CMSG_DATA(cmsg);
216d35d5ecc4d8ac1bd3617e6f5f85ca738041130ebDmitry V. Levin	size_t i;
217d35d5ecc4d8ac1bd3617e6f5f85ca738041130ebDmitry V. Levin	for (i = 0; i < nfds; ++i)
218d35d5ecc4d8ac1bd3617e6f5f85ca738041130ebDmitry V. Levin		fdp[i] = i;
219d35d5ecc4d8ac1bd3617e6f5f85ca738041130ebDmitry V. Levin
220d35d5ecc4d8ac1bd3617e6f5f85ca738041130ebDmitry V. Levin	mh->msg_control = cmsg;
221d35d5ecc4d8ac1bd3617e6f5f85ca738041130ebDmitry V. Levin	mh->msg_controllen = len;
222d35d5ecc4d8ac1bd3617e6f5f85ca738041130ebDmitry V. Levin
223d35d5ecc4d8ac1bd3617e6f5f85ca738041130ebDmitry V. Levin	int rc = sendmsg(-1, mh, 0);
224d35d5ecc4d8ac1bd3617e6f5f85ca738041130ebDmitry V. Levin	printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
225d35d5ecc4d8ac1bd3617e6f5f85ca738041130ebDmitry V. Levin	       ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
226d35d5ecc4d8ac1bd3617e6f5f85ca738041130ebDmitry V. Levin	       ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS",
227d35d5ecc4d8ac1bd3617e6f5f85ca738041130ebDmitry V. Levin	       (unsigned) cmsg->cmsg_len);
228d35d5ecc4d8ac1bd3617e6f5f85ca738041130ebDmitry V. Levin	print_fds(cmsg, cmsg->cmsg_len);
229d35d5ecc4d8ac1bd3617e6f5f85ca738041130ebDmitry V. Levin	printf("}], msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
230d35d5ecc4d8ac1bd3617e6f5f85ca738041130ebDmitry V. Levin	       (unsigned long) len, rc, errno2name());
231d35d5ecc4d8ac1bd3617e6f5f85ca738041130ebDmitry V. Levin}
232d35d5ecc4d8ac1bd3617e6f5f85ca738041130ebDmitry V. Levin
233d35d5ecc4d8ac1bd3617e6f5f85ca738041130ebDmitry V. Levinstatic void
234dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughestest_scm_timestamp(struct msghdr *const mh, void *const page)
235dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes{
236dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	size_t len = CMSG_SPACE(sizeof(struct timeval));
237dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	struct cmsghdr *cmsg = get_cmsghdr(page, len);
238dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes
239dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	cmsg->cmsg_len = CMSG_LEN(sizeof(struct timeval));
240dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	cmsg->cmsg_level = SOL_SOCKET;
241dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	cmsg->cmsg_type = SCM_TIMESTAMP;
242dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	struct timeval *tv = (struct timeval *) CMSG_DATA(cmsg);
243dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	tv->tv_sec = 123456789;
244dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	tv->tv_usec = 987654;
245dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes
246dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	mh->msg_control = cmsg;
247dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	mh->msg_controllen = len;
248dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes
249dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	int rc = sendmsg(-1, mh, 0);
250dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
251dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	       ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
252dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	       ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_TIMESTAMP"
253dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	       ", cmsg_data={tv_sec=%lld, tv_usec=%llu}}]"
254dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	       ", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
255dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	       (unsigned) cmsg->cmsg_len,
256dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	       (long long) tv->tv_sec, zero_extend_signed_to_ull(tv->tv_usec),
257dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	       (unsigned long) len, rc, errno2name());
258dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes
259dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	len = CMSG_SPACE(sizeof(struct timeval) - sizeof(long));
260dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	cmsg = get_cmsghdr(page, len);
261dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes
262dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	cmsg->cmsg_len = CMSG_LEN(sizeof(struct timeval) - sizeof(long));
263dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	cmsg->cmsg_level = SOL_SOCKET;
264dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	cmsg->cmsg_type = SCM_TIMESTAMP;
265dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes
266dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	mh->msg_control = cmsg;
267dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	mh->msg_controllen = len;
268dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes
269dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	rc = sendmsg(-1, mh, 0);
270dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
271dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	       ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
272dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	       ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_TIMESTAMP, cmsg_data=?}]"
273dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	       ", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
274dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	       (unsigned) cmsg->cmsg_len,
275dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	       (unsigned long) len, rc, errno2name());
276dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes}
277dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes
278dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughesstatic void
279dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughestest_scm_timestampns(struct msghdr *const mh, void *const page)
280dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes{
281dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	size_t len = CMSG_SPACE(sizeof(struct timespec));
282dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	struct cmsghdr *cmsg = get_cmsghdr(page, len);
283dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes
284dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	cmsg->cmsg_len = CMSG_LEN(sizeof(struct timespec));
285dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	cmsg->cmsg_level = SOL_SOCKET;
286dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	cmsg->cmsg_type = SCM_TIMESTAMPNS;
287dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	struct timespec *ts = (struct timespec *) CMSG_DATA(cmsg);
288dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	ts->tv_sec = 123456789;
289dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	ts->tv_nsec = 987654321;
290dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes
291dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	mh->msg_control = cmsg;
292dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	mh->msg_controllen = len;
293dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes
294dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	int rc = sendmsg(-1, mh, 0);
295dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
296dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	       ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
297dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	       ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_TIMESTAMPNS"
298dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	       ", cmsg_data={tv_sec=%lld, tv_nsec=%llu}}]"
299dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	       ", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
300dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	       (unsigned) cmsg->cmsg_len,
301dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	       (long long) ts->tv_sec, zero_extend_signed_to_ull(ts->tv_nsec),
302dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	       (unsigned long) len, rc, errno2name());
303dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes
304dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	len = CMSG_SPACE(sizeof(struct timespec) - sizeof(long));
305dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	cmsg = get_cmsghdr(page, len);
306dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes
307dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	cmsg->cmsg_len = CMSG_LEN(sizeof(struct timespec) - sizeof(long));
308dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	cmsg->cmsg_level = SOL_SOCKET;
309dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	cmsg->cmsg_type = SCM_TIMESTAMPNS;
310dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes
311dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	mh->msg_control = cmsg;
312dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	mh->msg_controllen = len;
313dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes
314dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	rc = sendmsg(-1, mh, 0);
315dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
316dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	       ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
317dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	       ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_TIMESTAMPNS"
318dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	       ", cmsg_data=?}]"
319dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	       ", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
320dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	       (unsigned) cmsg->cmsg_len,
321dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	       (unsigned long) len, rc, errno2name());
322dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes}
323dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes
324dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughesstatic void
325dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughestest_scm_timestamping(struct msghdr *const mh, void *const page)
326dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes{
327dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	size_t len = CMSG_SPACE(3 * sizeof(struct timespec));
328dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	struct cmsghdr *cmsg = get_cmsghdr(page, len);
329dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes
330dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	cmsg->cmsg_len = CMSG_LEN(3 * sizeof(struct timespec));
331dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	cmsg->cmsg_level = SOL_SOCKET;
332dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	cmsg->cmsg_type = SCM_TIMESTAMPING;
333dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	struct timespec *ts = (struct timespec *) CMSG_DATA(cmsg);
334dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	ts[0].tv_sec = 123456789;
335dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	ts[0].tv_nsec = 987654321;
336dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	ts[1].tv_sec = 123456790;
337dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	ts[1].tv_nsec = 987654320;
338dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	ts[2].tv_sec = 123456791;
339dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	ts[2].tv_nsec = 987654319;
340dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes
341dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	mh->msg_control = cmsg;
342dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	mh->msg_controllen = len;
343dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes
344dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	int rc = sendmsg(-1, mh, 0);
345dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
346dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	       ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
347dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	       ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_TIMESTAMPING"
348dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	       ", cmsg_data=[{tv_sec=%lld, tv_nsec=%llu}"
349dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	       ", {tv_sec=%lld, tv_nsec=%llu}, {tv_sec=%lld, tv_nsec=%llu}]}]"
350dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	       ", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
351dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	       (unsigned) cmsg->cmsg_len, (long long) ts[0].tv_sec,
352dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	       zero_extend_signed_to_ull(ts[0].tv_nsec),
353dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	       (long long) ts[1].tv_sec,
354dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	       zero_extend_signed_to_ull(ts[1].tv_nsec),
355dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	       (long long) ts[2].tv_sec,
356dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	       zero_extend_signed_to_ull(ts[2].tv_nsec),
357dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	       (unsigned long) len, rc, errno2name());
358dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes
359dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	len = CMSG_SPACE(3 * sizeof(struct timespec) - sizeof(long));
360dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	cmsg = get_cmsghdr(page, len);
361dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes
362dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	cmsg->cmsg_len = CMSG_LEN(3 * sizeof(struct timespec) - sizeof(long));
363dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	cmsg->cmsg_level = SOL_SOCKET;
364dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	cmsg->cmsg_type = SCM_TIMESTAMPING;
365dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes
366dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	mh->msg_control = cmsg;
367dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	mh->msg_controllen = len;
368dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes
369dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	rc = sendmsg(-1, mh, 0);
370dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
371dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	       ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
372dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	       ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_TIMESTAMPING"
373dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	       ", cmsg_data=?}]"
374dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	       ", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
375dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	       (unsigned) cmsg->cmsg_len,
376dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	       (unsigned long) len, rc, errno2name());
377dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes}
378dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes
379dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughesstatic void
3807555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levinprint_security(const struct cmsghdr *const cmsg, const size_t cmsg_len)
3817555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin{
3827555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	int n = cmsg_len > CMSG_LEN(0) ? cmsg_len - CMSG_LEN(0) : 0;
3837555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	if (!n)
3847555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		return;
3857555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
3867555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	printf(", cmsg_data=\"%.*s\"", n, CMSG_DATA(cmsg));
3877555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin}
3887555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
3897555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levinstatic void
3907555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levintest_scm_security(struct msghdr *const mh,
3917555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		  const size_t msg_controllen,
3927555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		  void *const page,
3937555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		  const void *const src,
3947555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		  const size_t cmsg_len,
3957555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		  const int cmsg_level,
3967555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		  const char *const cmsg_level_str)
3977555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin{
3987555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	const size_t aligned_cms_len =
3997555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		cmsg_len > CMSG_LEN(0) ? CMSG_ALIGN(cmsg_len) : CMSG_LEN(0);
4007555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	if (cmsg_len >= CMSG_LEN(0)
4017555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	    && aligned_cms_len + CMSG_LEN(0) <= msg_controllen)
4027555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		return;
4037555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
4047555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	struct cmsghdr *cmsg = get_cmsghdr(page, msg_controllen);
4057555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
4067555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	cmsg->cmsg_len = cmsg_len;
4077555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	cmsg->cmsg_level = cmsg_level;
4087555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	cmsg->cmsg_type = SCM_SECURITY;
4097555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
4107555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	size_t src_len =
4117555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		cmsg_len < msg_controllen ? cmsg_len : msg_controllen;
4127555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	if (src_len > CMSG_LEN(0))
4137555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		memcpy(CMSG_DATA(cmsg), src, src_len - CMSG_LEN(0));
4147555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
4157555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	mh->msg_control = cmsg;
4167555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	mh->msg_controllen = msg_controllen;
4177555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
4187555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	int rc = sendmsg(-1, mh, 0);
4197555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	int saved_errno = errno;
4207555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
4217555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
4227555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       ", msg_iovlen=0, msg_control=[{cmsg_len=%lu, cmsg_level=%s"
4237555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       ", cmsg_type=SCM_SECURITY",
4247555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       (unsigned long) cmsg_len, cmsg_level_str);
4257555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	print_security(cmsg, src_len);
4267555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	printf("}");
4277555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	if (aligned_cms_len < msg_controllen)
4287555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		printf(", %p", (void *) cmsg + aligned_cms_len);
4297555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	printf("]");
4307555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
4317555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	errno = saved_errno;
4327555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	printf(", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
4337555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       (unsigned long) msg_controllen, rc, errno2name());
4347555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin}
4357555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
4367555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levinstatic void
4377555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levintest_unknown_type(struct msghdr *const mh,
4387555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		  void *const page,
4397555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		  const int cmsg_level,
4407555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		  const char *const cmsg_level_str,
4417555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		  const char *const cmsg_type_str)
4427555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin{
4437555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	struct cmsghdr *cmsg = get_cmsghdr(page, CMSG_LEN(0));
4447555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
4457555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	cmsg->cmsg_len = CMSG_LEN(0);
4467555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	cmsg->cmsg_level = cmsg_level;
4477555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	cmsg->cmsg_type = 0xfacefeed;
4487555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
4497555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	mh->msg_control = cmsg;
4507555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	mh->msg_controllen = cmsg->cmsg_len;
4517555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
4527555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	int rc = sendmsg(-1, mh, 0);
4537555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
4547555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       ", msg_iovlen=0, msg_control=[{cmsg_len=%u, cmsg_level=%s"
4557555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       ", cmsg_type=%#x /* %s */}], msg_controllen=%u, msg_flags=0}"
4567555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       ", 0) = %d %s (%m)\n",
4577555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       (unsigned) cmsg->cmsg_len, cmsg_level_str, cmsg->cmsg_type,
4587555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       cmsg_type_str, (unsigned) mh->msg_controllen, rc, errno2name());
4597555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin}
4607555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
4617555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levinstatic void
4627555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levintest_sol_socket(struct msghdr *const mh, void *const page)
4637555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin{
4647555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	static const int fds0[] = { -10, -11, -12, -13 };
4657555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	static const int fds1[] = { -15, -16, -17, -18 };
4667555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	size_t msg_controllen, max_msg_controllen;
4677555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
4687555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	max_msg_controllen = CMSG_SPACE(sizeof(fds0)) + sizeof(*fds0) - 1;
4697555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	for (msg_controllen = 0;
4707555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	     msg_controllen <= max_msg_controllen;
4717555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	     msg_controllen++) {
4727555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		size_t cmsg_len;
4737555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
4747555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		for (cmsg_len = 0;
4757555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		     cmsg_len <= msg_controllen + CMSG_LEN(0);
4767555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		     cmsg_len++) {
4777555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin			test_scm_rights1(mh, msg_controllen,
4787555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin					 page, fds0, cmsg_len);
4797555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		}
4807555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	}
4817555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
4827555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	max_msg_controllen =
4837555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		CMSG_SPACE(sizeof(fds0)) + CMSG_SPACE(sizeof(fds1)) +
4847555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		sizeof(*fds0) - 1;
4857555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	for (msg_controllen = CMSG_LEN(0) * 2;
4867555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	     msg_controllen <= max_msg_controllen;
4877555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	     msg_controllen++) {
4887555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		static const int *const fdps[] = { fds0, fds1 };
4897555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		size_t cmsg_len[2];
4907555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
4917555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		for (cmsg_len[0] = CMSG_LEN(0);
4927555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		     CMSG_ALIGN(cmsg_len[0]) + CMSG_LEN(0) <= msg_controllen
4937555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		     && CMSG_ALIGN(cmsg_len[0]) <= CMSG_SPACE(sizeof(fds0));
4947555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		     cmsg_len[0]++) {
4957555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin			const size_t msg_controllen1 =
4967555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin				msg_controllen - CMSG_ALIGN(cmsg_len[0]);
4977555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
4987555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin			for (cmsg_len[1] = 0;
4997555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin			     cmsg_len[1] <= msg_controllen1 + CMSG_LEN(0);
5007555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin			     cmsg_len[1]++) {
5017555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin				test_scm_rights2(mh, msg_controllen,
5027555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin						 page, fdps, cmsg_len);
5037555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin			}
5047555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		}
5057555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	}
5067555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
5077555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	static const char text[16] = "0123456789abcdef";
5087555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	max_msg_controllen = CMSG_SPACE(sizeof(text)) + CMSG_LEN(0) - 1;
5097555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	for (msg_controllen = CMSG_LEN(0);
5107555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	     msg_controllen <= max_msg_controllen;
5117555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	     msg_controllen++) {
5127555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		size_t cmsg_len;
5137555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
5147555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		for (cmsg_len = 0;
5157555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		     cmsg_len <= msg_controllen + CMSG_LEN(0)
5167555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		     && cmsg_len <= CMSG_LEN(sizeof(text));
5177555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		     cmsg_len++) {
5187555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin			test_scm_security(mh, msg_controllen,
5197555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin					  page, text, cmsg_len,
520d35df493b4e7684c50d2d2fa032ee3a7ac228009Elliott Hughes					  ARG_STR(SOL_SOCKET));
5217555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		}
5227555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	}
5237555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
524d35d5ecc4d8ac1bd3617e6f5f85ca738041130ebDmitry V. Levin	test_scm_rights3(mh, page, DEFAULT_STRLEN - 1);
525d35d5ecc4d8ac1bd3617e6f5f85ca738041130ebDmitry V. Levin	test_scm_rights3(mh, page, DEFAULT_STRLEN);
526d35d5ecc4d8ac1bd3617e6f5f85ca738041130ebDmitry V. Levin	test_scm_rights3(mh, page, DEFAULT_STRLEN + 1);
527d35d5ecc4d8ac1bd3617e6f5f85ca738041130ebDmitry V. Levin
528dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	test_scm_timestamp(mh, page);
529dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	test_scm_timestampns(mh, page);
530dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes	test_scm_timestamping(mh, page);
531dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes
532d35df493b4e7684c50d2d2fa032ee3a7ac228009Elliott Hughes	test_unknown_type(mh, page, ARG_STR(SOL_SOCKET), "SCM_???");
5337555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin}
5347555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
5357555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levinstatic void
5367555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levintest_ip_pktinfo(struct msghdr *const mh, void *const page,
537dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes		const int cmsg_type, const char *const cmsg_type_str)
5387555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin{
5397555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	const unsigned int len = CMSG_SPACE(sizeof(struct in_pktinfo));
5407555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	struct cmsghdr *const cmsg = get_cmsghdr(page, len);
5417555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
5427555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
5437555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	cmsg->cmsg_level = SOL_IP;
5447555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	cmsg->cmsg_type = cmsg_type;
5457555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
5467555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	struct in_pktinfo *const info = (struct in_pktinfo *) CMSG_DATA(cmsg);
54777c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	info->ipi_ifindex = ifindex_lo();
5487555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	info->ipi_spec_dst.s_addr = inet_addr("1.2.3.4");
5497555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	info->ipi_addr.s_addr = inet_addr("5.6.7.8");
5507555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
5517555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	mh->msg_control = cmsg;
5527555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	mh->msg_controllen = len;
5537555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
5547555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	int rc = sendmsg(-1, mh, 0);
5557555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
5567555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       ", msg_iovlen=0, msg_control=[{cmsg_len=%u, cmsg_level=SOL_IP"
5577555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       ", cmsg_type=%s, cmsg_data={ipi_ifindex=%s"
5587555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       ", ipi_spec_dst=inet_addr(\"%s\")"
5597555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       ", ipi_addr=inet_addr(\"%s\")}}]"
5607555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       ", msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n",
5617555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       (unsigned) cmsg->cmsg_len, cmsg_type_str,
56277c3ff8e0644f1e120e4b2ebc7222150b0446f3bElliott Hughes	       IFINDEX_LO_STR, "1.2.3.4", "5.6.7.8", len, rc, errno2name());
5637555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin}
5647555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
5657555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levinstatic void
5667555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levintest_ip_uint(struct msghdr *const mh, void *const page,
5677555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	     const int cmsg_type, const char *const cmsg_type_str)
5687555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin{
5697555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	const unsigned int len = CMSG_SPACE(sizeof(int));
5707555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	struct cmsghdr *const cmsg = get_cmsghdr(page, len);
5717555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
5727555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	cmsg->cmsg_len = CMSG_LEN(sizeof(int));
5737555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	cmsg->cmsg_level = SOL_IP;
5747555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	cmsg->cmsg_type = cmsg_type;
5757555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
5767555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	unsigned int *u = (void *) CMSG_DATA(cmsg);
5777555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	*u = 0xfacefeed;
5787555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
5797555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	mh->msg_control = cmsg;
5807555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	mh->msg_controllen = len;
5817555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
5827555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	int rc = sendmsg(-1, mh, 0);
5837555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
5847555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
5857555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       ", cmsg_level=SOL_IP, cmsg_type=%s, cmsg_data=[%u]}]"
5867555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       ", msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n",
5877555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       (unsigned) cmsg->cmsg_len, cmsg_type_str, *u, len,
5887555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       rc, errno2name());
5897555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin}
5907555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
5917555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levinstatic void
5927555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levintest_ip_uint8_t(struct msghdr *const mh, void *const page,
593dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes		const int cmsg_type, const char *const cmsg_type_str)
5947555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin{
5957555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	const unsigned int len = CMSG_SPACE(1);
5967555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	struct cmsghdr *const cmsg = get_cmsghdr(page, len);
5977555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
5987555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	cmsg->cmsg_len = CMSG_LEN(1);
5997555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	cmsg->cmsg_level = SOL_IP;
6007555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	cmsg->cmsg_type = cmsg_type;
6017555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	*CMSG_DATA(cmsg) = 'A';
6027555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
6037555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	mh->msg_control = cmsg;
6047555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	mh->msg_controllen = len;
6057555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
6067555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	int rc = sendmsg(-1, mh, 0);
6077555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
6087555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
6097555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       ", cmsg_level=SOL_IP, cmsg_type=%s, cmsg_data=[%#x]}]"
6107555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       ", msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n",
6117555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       (unsigned) cmsg->cmsg_len, cmsg_type_str,
6127555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       (unsigned) (uint8_t) 'A', len, rc, errno2name());
6137555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin}
6147555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
6157555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levinstatic void
6167555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levinprint_ip_opts(const void *const cmsg_data, const unsigned int data_len)
6177555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin{
6187555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	const unsigned char *const opts = cmsg_data;
6197555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	unsigned int i;
6207555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	for (i = 0; i < data_len; ++i) {
6217555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		if (i)
6227555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin			printf(", ");
623074c630705aa65f0795209a0e8ce954520226e57Dmitry V. Levin#if !VERBOSE
62467135824fe8f1a78349e5297bf0db323925376ecDmitry V. Levin		if (i >= DEFAULT_STRLEN) {
62567135824fe8f1a78349e5297bf0db323925376ecDmitry V. Levin			printf("...");
62667135824fe8f1a78349e5297bf0db323925376ecDmitry V. Levin			break;
62767135824fe8f1a78349e5297bf0db323925376ecDmitry V. Levin		}
62867135824fe8f1a78349e5297bf0db323925376ecDmitry V. Levin#endif
6297555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		printf("0x%02x", opts[i]);
6307555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	}
6317555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin}
6327555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
6337555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levinstatic void
6347555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levintest_ip_opts(struct msghdr *const mh, void *const page,
6357555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	     const int cmsg_type, const char *const cmsg_type_str,
6367555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	     const unsigned int opts_len)
6377555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin{
6387555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	unsigned int len = CMSG_SPACE(opts_len);
6397555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	struct cmsghdr *cmsg = get_cmsghdr(page, len);
6407555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
6417555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	cmsg->cmsg_len = CMSG_LEN(opts_len);
6427555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	cmsg->cmsg_level = SOL_IP;
6437555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	cmsg->cmsg_type = cmsg_type;
6447555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	unsigned int i;
6457555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	for (i = 0; i < opts_len; ++i)
6467555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		CMSG_DATA(cmsg)[i] = 'A' + i;
6477555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
6487555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	mh->msg_control = cmsg;
6497555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	mh->msg_controllen = len;
6507555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
6517555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	int rc = sendmsg(-1, mh, 0);
6527555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
6537555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
6547555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       ", cmsg_level=SOL_IP, cmsg_type=%s, cmsg_data=[",
6557555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       (unsigned) cmsg->cmsg_len, cmsg_type_str);
6567555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	print_ip_opts(CMSG_DATA(cmsg), opts_len);
6577555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	printf("]}], msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n",
6587555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       len, rc, errno2name());
6597555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin}
6607555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
6617555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin#ifdef IP_CHECKSUM
6627555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levinstruct sock_ee {
6637555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	uint32_t ee_errno;
6647555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	uint8_t  ee_origin;
6657555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	uint8_t  ee_type;
6667555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	uint8_t  ee_code;
6677555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	uint8_t  ee_pad;
6687555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	uint32_t ee_info;
6697555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	uint32_t ee_data;
6707555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	struct sockaddr_in offender;
6717555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin};
6727555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
6737555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levinstatic void
6747555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levintest_ip_recverr(struct msghdr *const mh, void *const page,
675dc75b01004a0588c1eb3bc26d7248a6e473b2cddElliott Hughes		const int cmsg_type, const char *const cmsg_type_str)
6767555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin{
6777555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	const unsigned int len = CMSG_SPACE(sizeof(struct sock_ee));
6787555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	struct cmsghdr *const cmsg = get_cmsghdr(page, len);
6797555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
6807555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	cmsg->cmsg_len = CMSG_LEN(sizeof(struct sock_ee));
6817555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	cmsg->cmsg_level = SOL_IP;
6827555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	cmsg->cmsg_type = cmsg_type;
6837555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
6847555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	struct sock_ee *const e = (struct sock_ee *) CMSG_DATA(cmsg);
6857555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	e->ee_errno = 0xdeadbeef;
6867555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	e->ee_origin = 2;
6877555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	e->ee_type = 3;
6887555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	e->ee_code = 4;
6897555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	e->ee_info = 0xfacefeed;
6907555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	e->ee_data = 0xbadc0ded;
6917555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	e->offender.sin_family = AF_INET,
6927555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	e->offender.sin_port = htons(12345),
6937555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	e->offender.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
6947555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
6957555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	mh->msg_control = cmsg;
6967555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	mh->msg_controllen = len;
6977555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
6987555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	int rc = sendmsg(-1, mh, 0);
6997555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
7007555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       ", msg_iovlen=0, msg_control=[{cmsg_len=%u, cmsg_level=SOL_IP"
7017555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       ", cmsg_type=%s, cmsg_data={ee_errno=%u, ee_origin=%u"
7027555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       ", ee_type=%u, ee_code=%u, ee_info=%u, ee_data=%u"
7037555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       ", offender={sa_family=AF_INET, sin_port=htons(%hu)"
7047555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       ", sin_addr=inet_addr(\"127.0.0.1\")}}}]"
7057555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       ", msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n",
7067555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       (unsigned) cmsg->cmsg_len, cmsg_type_str,
7077555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       e->ee_errno, e->ee_origin, e->ee_type,
7087555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       e->ee_code, e->ee_info, e->ee_data,
7097555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       ntohs(e->offender.sin_port),
7107555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       len, rc, errno2name());
7117555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin}
7127555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin#endif
7137555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
7147555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin#ifdef IP_ORIGDSTADDR
7157555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levinstatic void
7167555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levintest_ip_origdstaddr(struct msghdr *const mh, void *const page,
7177555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin		    const int cmsg_type, const char *const cmsg_type_str)
7187555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin{
7197555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	const unsigned int len = CMSG_SPACE(sizeof(struct sockaddr_in));
7207555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	struct cmsghdr *const cmsg = get_cmsghdr(page, len);
7217555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
7227555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	cmsg->cmsg_len = CMSG_LEN(sizeof(struct sockaddr_in));
7237555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	cmsg->cmsg_level = SOL_IP;
7247555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	cmsg->cmsg_type = cmsg_type;
7257555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
7267555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	struct sockaddr_in *const sin = (struct sockaddr_in *) CMSG_DATA(cmsg);
7277555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	sin->sin_family = AF_INET,
7287555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	sin->sin_port = htons(12345),
7297555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
7307555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
7317555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	mh->msg_control = cmsg;
7327555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	mh->msg_controllen = len;
7337555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
7347555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	int rc = sendmsg(-1, mh, 0);
7357555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
7367555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       ", msg_iovlen=0, msg_control=[{cmsg_len=%u, cmsg_level=SOL_IP"
7377555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       ", cmsg_type=%s, cmsg_data={sa_family=AF_INET"
7387555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       ", sin_port=htons(%hu), sin_addr=inet_addr(\"127.0.0.1\")}}]"
7397555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       ", msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n",
7407555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       (unsigned) cmsg->cmsg_len, cmsg_type_str,
7417555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       ntohs(sin->sin_port), len, rc, errno2name());
7427555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin}
7437555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin#endif
7447555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
7457555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levinstatic void
7467555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levintest_sol_ip(struct msghdr *const mh, void *const page)
7477555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin{
748d35df493b4e7684c50d2d2fa032ee3a7ac228009Elliott Hughes	test_ip_pktinfo(mh, page, ARG_STR(IP_PKTINFO));
749d35df493b4e7684c50d2d2fa032ee3a7ac228009Elliott Hughes	test_ip_uint(mh, page, ARG_STR(IP_TTL));
750d35df493b4e7684c50d2d2fa032ee3a7ac228009Elliott Hughes	test_ip_uint8_t(mh, page, ARG_STR(IP_TOS));
751d35df493b4e7684c50d2d2fa032ee3a7ac228009Elliott Hughes	test_ip_opts(mh, page, ARG_STR(IP_RECVOPTS), 1);
752d35df493b4e7684c50d2d2fa032ee3a7ac228009Elliott Hughes	test_ip_opts(mh, page, ARG_STR(IP_RECVOPTS), 2);
753d35df493b4e7684c50d2d2fa032ee3a7ac228009Elliott Hughes	test_ip_opts(mh, page, ARG_STR(IP_RECVOPTS), 3);
754d35df493b4e7684c50d2d2fa032ee3a7ac228009Elliott Hughes	test_ip_opts(mh, page, ARG_STR(IP_RECVOPTS), 4);
755d35df493b4e7684c50d2d2fa032ee3a7ac228009Elliott Hughes	test_ip_opts(mh, page, ARG_STR(IP_RETOPTS), 5);
756d35df493b4e7684c50d2d2fa032ee3a7ac228009Elliott Hughes	test_ip_opts(mh, page, ARG_STR(IP_RETOPTS), 6);
757d35df493b4e7684c50d2d2fa032ee3a7ac228009Elliott Hughes	test_ip_opts(mh, page, ARG_STR(IP_RETOPTS), 7);
758d35df493b4e7684c50d2d2fa032ee3a7ac228009Elliott Hughes	test_ip_opts(mh, page, ARG_STR(IP_RETOPTS), 8);
759d35df493b4e7684c50d2d2fa032ee3a7ac228009Elliott Hughes	test_ip_opts(mh, page, ARG_STR(IP_RETOPTS), DEFAULT_STRLEN - 1);
760d35df493b4e7684c50d2d2fa032ee3a7ac228009Elliott Hughes	test_ip_opts(mh, page, ARG_STR(IP_RETOPTS), DEFAULT_STRLEN);
761d35df493b4e7684c50d2d2fa032ee3a7ac228009Elliott Hughes	test_ip_opts(mh, page, ARG_STR(IP_RETOPTS), DEFAULT_STRLEN + 1);
7627555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin#ifdef IP_CHECKSUM
763d35df493b4e7684c50d2d2fa032ee3a7ac228009Elliott Hughes	test_ip_recverr(mh, page, ARG_STR(IP_RECVERR));
7647555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin#endif
7657555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin#ifdef IP_ORIGDSTADDR
766d35df493b4e7684c50d2d2fa032ee3a7ac228009Elliott Hughes	test_ip_origdstaddr(mh, page, ARG_STR(IP_ORIGDSTADDR));
7677555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin#endif
7687555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin#ifdef IP_CHECKSUM
769d35df493b4e7684c50d2d2fa032ee3a7ac228009Elliott Hughes	test_ip_uint(mh, page, ARG_STR(IP_CHECKSUM));
7707555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin#endif
7717555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	test_scm_security(mh, CMSG_LEN(0), page, 0, CMSG_LEN(0),
772d35df493b4e7684c50d2d2fa032ee3a7ac228009Elliott Hughes			  ARG_STR(SOL_IP));
773d35df493b4e7684c50d2d2fa032ee3a7ac228009Elliott Hughes	test_unknown_type(mh, page, ARG_STR(SOL_IP), "IP_???");
7747555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin}
7757555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
7767555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levinstatic void
7777555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levintest_unknown_level(struct msghdr *const mh, void *const page)
7787555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin{
7797555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	struct cmsghdr *cmsg = get_cmsghdr(page, CMSG_LEN(0));
7807555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
7817555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	cmsg->cmsg_len = CMSG_LEN(0);
7827555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	cmsg->cmsg_level = SOL_TCP;
7837555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	cmsg->cmsg_type = 0xdeadbeef;
7847555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
7857555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	mh->msg_control = cmsg;
7867555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	mh->msg_controllen = cmsg->cmsg_len;
7877555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
7887555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	int rc = sendmsg(-1, mh, 0);
7897555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
7907555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       ", msg_iovlen=0, msg_control=[{cmsg_len=%u, cmsg_level=%s"
7917555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       ", cmsg_type=%#x}], msg_controllen=%u, msg_flags=0}"
7927555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       ", 0) = %d %s (%m)\n",
7937555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       (unsigned) cmsg->cmsg_len, "SOL_TCP", cmsg->cmsg_type,
7947555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       (unsigned) mh->msg_controllen, rc, errno2name());
7957555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin}
7967555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
797bf2698a6b8fa9e78e82ec2acaeef39273e95ab17Dmitry V. Levinstatic void
798bf2698a6b8fa9e78e82ec2acaeef39273e95ab17Dmitry V. Levintest_big_len(struct msghdr *const mh)
799bf2698a6b8fa9e78e82ec2acaeef39273e95ab17Dmitry V. Levin{
800bf2698a6b8fa9e78e82ec2acaeef39273e95ab17Dmitry V. Levin	int optmem_max;
801bf2698a6b8fa9e78e82ec2acaeef39273e95ab17Dmitry V. Levin
802bf2698a6b8fa9e78e82ec2acaeef39273e95ab17Dmitry V. Levin	if (read_int_from_file("/proc/sys/net/core/optmem_max", &optmem_max)
803bf2698a6b8fa9e78e82ec2acaeef39273e95ab17Dmitry V. Levin	    || optmem_max <= 0 || optmem_max > 0x100000)
8048da9668b1ba68ec71ad4d3dd96f9c73ca38430caDmitry V. Levin		optmem_max = sizeof(long long) * (2 * IOV_MAX + 512);
805bf2698a6b8fa9e78e82ec2acaeef39273e95ab17Dmitry V. Levin	optmem_max = (optmem_max + sizeof(long long) - 1)
806bf2698a6b8fa9e78e82ec2acaeef39273e95ab17Dmitry V. Levin		     & ~(sizeof(long long) - 1);
807bf2698a6b8fa9e78e82ec2acaeef39273e95ab17Dmitry V. Levin
808bf2698a6b8fa9e78e82ec2acaeef39273e95ab17Dmitry V. Levin	const size_t len = optmem_max * 2;
809bf2698a6b8fa9e78e82ec2acaeef39273e95ab17Dmitry V. Levin	struct cmsghdr *const cmsg = tail_alloc(len);
810bf2698a6b8fa9e78e82ec2acaeef39273e95ab17Dmitry V. Levin	cmsg->cmsg_len = len;
811bf2698a6b8fa9e78e82ec2acaeef39273e95ab17Dmitry V. Levin	cmsg->cmsg_level = SOL_SOCKET;
812bf2698a6b8fa9e78e82ec2acaeef39273e95ab17Dmitry V. Levin	cmsg->cmsg_type = SCM_RIGHTS;
813bf2698a6b8fa9e78e82ec2acaeef39273e95ab17Dmitry V. Levin
814bf2698a6b8fa9e78e82ec2acaeef39273e95ab17Dmitry V. Levin	mh->msg_control = cmsg;
815bf2698a6b8fa9e78e82ec2acaeef39273e95ab17Dmitry V. Levin	mh->msg_controllen = len;
816bf2698a6b8fa9e78e82ec2acaeef39273e95ab17Dmitry V. Levin
817bf2698a6b8fa9e78e82ec2acaeef39273e95ab17Dmitry V. Levin	int rc = sendmsg(-1, mh, 0);
818bf2698a6b8fa9e78e82ec2acaeef39273e95ab17Dmitry V. Levin	if (EBADF != errno)
819bf2698a6b8fa9e78e82ec2acaeef39273e95ab17Dmitry V. Levin		perror_msg_and_skip("sendmsg");
820bf2698a6b8fa9e78e82ec2acaeef39273e95ab17Dmitry V. Levin
821bf2698a6b8fa9e78e82ec2acaeef39273e95ab17Dmitry V. Levin	printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
822bf2698a6b8fa9e78e82ec2acaeef39273e95ab17Dmitry V. Levin	       ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
823bf2698a6b8fa9e78e82ec2acaeef39273e95ab17Dmitry V. Levin	       ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS",
824bf2698a6b8fa9e78e82ec2acaeef39273e95ab17Dmitry V. Levin	       (unsigned) cmsg->cmsg_len);
825bf2698a6b8fa9e78e82ec2acaeef39273e95ab17Dmitry V. Levin	print_fds(cmsg, optmem_max);
826bf2698a6b8fa9e78e82ec2acaeef39273e95ab17Dmitry V. Levin	printf("}, ...], msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
827bf2698a6b8fa9e78e82ec2acaeef39273e95ab17Dmitry V. Levin	       (unsigned long) len, rc, errno2name());
828bf2698a6b8fa9e78e82ec2acaeef39273e95ab17Dmitry V. Levin}
829bf2698a6b8fa9e78e82ec2acaeef39273e95ab17Dmitry V. Levin
8307555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levinint main(int ac, const char **av)
8317555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin{
8327555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	int rc = sendmsg(-1, 0, 0);
8337555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	printf("sendmsg(-1, NULL, 0) = %d %s (%m)\n", rc, errno2name());
8347555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
83539bac055674d23770b9a724221b728e443196ea7Elliott Hughes	TAIL_ALLOC_OBJECT_CONST_PTR(struct msghdr, mh);
8367555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	memset(mh, 0, sizeof(*mh));
837bf2698a6b8fa9e78e82ec2acaeef39273e95ab17Dmitry V. Levin	test_big_len(mh);
8387555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
8397555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	rc = sendmsg(-1, mh + 1, 0);
8407555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	printf("sendmsg(-1, %p, 0) = %d %s (%m)\n",
8417555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       mh + 1, rc, errno2name());
8427555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
8437555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	void *page = tail_alloc(1) + 1;
8447555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	mh->msg_control = page;
8457555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	mh->msg_controllen = CMSG_LEN(0);
8467555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	rc = sendmsg(-1, mh, 0);
8477555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
8487555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       ", msg_iovlen=0, msg_control=%p, msg_controllen=%u"
8497555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       ", msg_flags=0}, 0) = %d %s (%m)\n",
8507555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	       page, (unsigned) CMSG_LEN(0), rc, errno2name());
8517555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
8527555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	test_sol_socket(mh, page);
8537555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	test_sol_ip(mh, page);
8547555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	test_unknown_level(mh, page);
8557555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin
8567555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	puts("+++ exited with 0 +++");
8577555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin	return 0;
8587555ffc39063b620243d2a1ed367a9d1f4a7203bDmitry V. Levin}
859