(root)/
strace-6.5/
tests/
netlink_protocol.c
       1  /*
       2   * Check decoding of netlink protocol.
       3   *
       4   * Copyright (c) 2014-2017 Dmitry V. Levin <ldv@strace.io>
       5   * Copyright (c) 2016 Fabien Siron <fabien.siron@epita.fr>
       6   * Copyright (c) 2016-2021 The strace developers.
       7   * All rights reserved.
       8   *
       9   * SPDX-License-Identifier: GPL-2.0-or-later
      10   */
      11  
      12  #include "tests.h"
      13  
      14  #ifdef HAVE_SYS_XATTR_H
      15  
      16  # include <stdio.h>
      17  # include <stdlib.h>
      18  # include <string.h>
      19  # include <unistd.h>
      20  # include <sys/xattr.h>
      21  # include <netinet/in.h>
      22  # include "netlink.h"
      23  # include <linux/sock_diag.h>
      24  # include <linux/netlink_diag.h>
      25  # include "xmalloc.h"
      26  
      27  static void
      28  send_query(const int fd)
      29  {
      30  	static const struct req {
      31  		struct nlmsghdr nlh;
      32  		const char magic[4];
      33  	} c_req = {
      34  		.nlh = {
      35  			.nlmsg_len = sizeof(struct req),
      36  			.nlmsg_type = NLMSG_NOOP,
      37  			.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST
      38  		},
      39  		.magic = "abcd"
      40  	};
      41  	struct req *const req = tail_memdup(&c_req, sizeof(c_req));
      42  	long rc;
      43  	const char *errstr;
      44  
      45  	/* zero address */
      46  	rc = sendto(fd, NULL, sizeof(*req), MSG_DONTWAIT, NULL, 0);
      47  	printf("sendto(%d, NULL, %u, MSG_DONTWAIT, NULL, 0) = %s\n",
      48  	       fd, (unsigned) sizeof(*req), sprintrc(rc));
      49  
      50  	/* zero length */
      51  	rc = sendto(fd, req, 0, MSG_DONTWAIT, NULL, 0);
      52  	printf("sendto(%d, \"\", 0, MSG_DONTWAIT, NULL, 0) = %s\n",
      53  	       fd, sprintrc(rc));
      54  
      55  	/* zero address and length */
      56  	rc = sendto(fd, NULL, 0, MSG_DONTWAIT, NULL, 0);
      57  	printf("sendto(%d, NULL, 0, MSG_DONTWAIT, NULL, 0) = %s\n",
      58  	       fd, sprintrc(rc));
      59  
      60  	/* unfetchable struct nlmsghdr */
      61  	const void *const efault = tail_alloc(sizeof(struct nlmsghdr) - 1);
      62  	rc = sendto(fd, efault, sizeof(struct nlmsghdr), MSG_DONTWAIT, NULL, 0);
      63  	printf("sendto(%d, %p, %u, MSG_DONTWAIT, NULL, 0) = %s\n",
      64  	       fd, efault, (unsigned) sizeof(struct nlmsghdr), sprintrc(rc));
      65  
      66  	/* whole message length < sizeof(struct nlmsghdr) */
      67  	rc = sendto(fd, req->magic, sizeof(req->magic), MSG_DONTWAIT, NULL, 0);
      68  	printf("sendto(%d, \"\\x61\\x62\\x63\\x64\""
      69  	       ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
      70  	       fd, (unsigned) sizeof(req->magic), sprintrc(rc));
      71  
      72  	/* a single message with some data */
      73  	rc = sendto(fd, req, sizeof(*req), MSG_DONTWAIT, NULL, 0);
      74  	printf("sendto(%d, [{nlmsg_len=%u, nlmsg_type=NLMSG_NOOP"
      75  	       ", nlmsg_flags=NLM_F_REQUEST|0x%x"
      76  	       ", nlmsg_seq=0, nlmsg_pid=0}, \"\\x61\\x62\\x63\\x64\"]"
      77  	       ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
      78  	       fd, req->nlh.nlmsg_len, NLM_F_DUMP,
      79  	       (unsigned) sizeof(*req), sprintrc(rc));
      80  
      81  	/* a single message without data */
      82  	req->nlh.nlmsg_len = sizeof(req->nlh);
      83  	rc = sendto(fd, &req->nlh, sizeof(req->nlh), MSG_DONTWAIT, NULL, 0);
      84  	printf("sendto(%d, {nlmsg_len=%u, nlmsg_type=NLMSG_NOOP"
      85  	       ", nlmsg_flags=NLM_F_REQUEST|0x%x"
      86  	       ", nlmsg_seq=0, nlmsg_pid=0}, %u, MSG_DONTWAIT, NULL, 0) = %s\n",
      87  	       fd, req->nlh.nlmsg_len, NLM_F_DUMP,
      88  	       (unsigned) sizeof(req->nlh), sprintrc(rc));
      89  
      90  	/* nlmsg_len > whole message length */
      91  	req->nlh.nlmsg_len = sizeof(*req) + 8;
      92  	rc = sendto(fd, req, sizeof(*req), MSG_DONTWAIT, NULL, 0);
      93  	printf("sendto(%d, [{nlmsg_len=%u, nlmsg_type=NLMSG_NOOP"
      94  	       ", nlmsg_flags=NLM_F_REQUEST|0x%x"
      95  	       ", nlmsg_seq=0, nlmsg_pid=0}, \"\\x61\\x62\\x63\\x64\"]"
      96  	       ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
      97  	       fd, req->nlh.nlmsg_len, NLM_F_DUMP,
      98  	       (unsigned) sizeof(*req), sprintrc(rc));
      99  
     100  	/* nlmsg_len < sizeof(struct nlmsghdr) */
     101  	req->nlh.nlmsg_len = 8;
     102  	rc = sendto(fd, req, sizeof(*req), MSG_DONTWAIT, NULL, 0);
     103  	printf("sendto(%d, {nlmsg_len=%u, nlmsg_type=NLMSG_NOOP"
     104  	       ", nlmsg_flags=NLM_F_REQUEST|0x%x"
     105  	       ", nlmsg_seq=0, nlmsg_pid=0}, %u, MSG_DONTWAIT, NULL, 0) = %s\n",
     106  	       fd, req->nlh.nlmsg_len, NLM_F_DUMP,
     107  	       (unsigned) sizeof(*req), sprintrc(rc));
     108  
     109  	/* a sequence of two nlmsg objects */
     110  	struct reqs {
     111  		struct req req1;
     112  		char padding[NLMSG_ALIGN(sizeof(struct req)) - sizeof(struct req)];
     113  		struct req req2;
     114  	};
     115  	TAIL_ALLOC_OBJECT_CONST_PTR(struct reqs, reqs);
     116  	memcpy(&reqs->req1, &c_req, sizeof(c_req));
     117  	memcpy(&reqs->req2, &c_req, sizeof(c_req));
     118  
     119  	rc = sendto(fd, reqs, sizeof(*reqs), MSG_DONTWAIT, NULL, 0);
     120  	printf("sendto(%d, [[{nlmsg_len=%u, nlmsg_type=NLMSG_NOOP"
     121  	       ", nlmsg_flags=NLM_F_REQUEST|0x%x"
     122  	       ", nlmsg_seq=0, nlmsg_pid=0}, \"\\x61\\x62\\x63\\x64\"]"
     123  	       ", [{nlmsg_len=%u, nlmsg_type=NLMSG_NOOP"
     124  	       ", nlmsg_flags=NLM_F_REQUEST|0x%x"
     125  	       ", nlmsg_seq=0, nlmsg_pid=0}, \"\\x61\\x62\\x63\\x64\"]]"
     126  	       ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
     127  	       fd, reqs->req1.nlh.nlmsg_len, NLM_F_DUMP,
     128  	       reqs->req2.nlh.nlmsg_len, NLM_F_DUMP,
     129  	       (unsigned) sizeof(*reqs), sprintrc(rc));
     130  
     131  	/* unfetchable second struct nlmsghdr */
     132  	void *const efault2 = tail_memdup(&reqs->req1, sizeof(reqs->req1));
     133  	rc = sendto(fd, efault2, sizeof(*reqs), MSG_DONTWAIT, NULL, 0);
     134  	printf("sendto(%d, [[{nlmsg_len=%u, nlmsg_type=NLMSG_NOOP"
     135  	       ", nlmsg_flags=NLM_F_REQUEST|0x%x"
     136  	       ", nlmsg_seq=0, nlmsg_pid=0}, \"\\x61\\x62\\x63\\x64\"]"
     137  	       ", ... /* %p */], %u, MSG_DONTWAIT, NULL, 0) = %s\n",
     138  	       fd, reqs->req1.nlh.nlmsg_len, NLM_F_DUMP,
     139  	       &((struct reqs *) efault2)->req2, (unsigned) sizeof(*reqs),
     140  	       sprintrc(rc));
     141  
     142  	/* message length is not enough for the second struct nlmsghdr */
     143  	rc = sendto(fd, reqs, sizeof(*reqs) - sizeof(req->nlh), MSG_DONTWAIT,
     144  		    NULL, 0);
     145  	errstr = sprintrc(rc);
     146  	printf("sendto(%d, [[{nlmsg_len=%u, nlmsg_type=NLMSG_NOOP"
     147  	       ", nlmsg_flags=NLM_F_REQUEST|0x%x"
     148  	       ", nlmsg_seq=0, nlmsg_pid=0}, \"\\x61\\x62\\x63\\x64\"], ",
     149  	       fd, reqs->req1.nlh.nlmsg_len, NLM_F_DUMP);
     150  	print_quoted_hex(&reqs->req2.nlh,
     151  			 sizeof(reqs->req2) - sizeof(req->nlh));
     152  	printf("], %u, MSG_DONTWAIT, NULL, 0) = %s\n",
     153  	       (unsigned) (sizeof(*reqs) - sizeof(req->nlh)), errstr);
     154  
     155  	/* second nlmsg_len < sizeof(struct nlmsghdr) */
     156  	reqs->req2.nlh.nlmsg_len = 4;
     157  	rc = sendto(fd, reqs, sizeof(*reqs), MSG_DONTWAIT, NULL, 0);
     158  	printf("sendto(%d, [[{nlmsg_len=%u, nlmsg_type=NLMSG_NOOP"
     159  	       ", nlmsg_flags=NLM_F_REQUEST|0x%x"
     160  	       ", nlmsg_seq=0, nlmsg_pid=0}, \"\\x61\\x62\\x63\\x64\"]"
     161  	       ", {nlmsg_len=%u, nlmsg_type=NLMSG_NOOP"
     162  	       ", nlmsg_flags=NLM_F_REQUEST|0x%x"
     163  	       ", nlmsg_seq=0, nlmsg_pid=0}], %u, MSG_DONTWAIT, NULL, 0) = %s\n",
     164  	       fd, reqs->req1.nlh.nlmsg_len, NLM_F_DUMP,
     165  	       reqs->req2.nlh.nlmsg_len, NLM_F_DUMP,
     166  	       (unsigned) sizeof(*reqs), sprintrc(rc));
     167  
     168  	/* abbreviated output */
     169  # define ABBREV_LEN (DEFAULT_STRLEN + 1)
     170  	const unsigned int msg_len = sizeof(struct nlmsghdr) * ABBREV_LEN;
     171  	struct nlmsghdr *const msgs = tail_alloc(msg_len);
     172  	for (unsigned int i = 0; i < ABBREV_LEN; ++i) {
     173  		msgs[i].nlmsg_len = sizeof(*msgs);
     174  		msgs[i].nlmsg_type = NLMSG_NOOP;
     175  		msgs[i].nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
     176  		msgs[i].nlmsg_seq = i;
     177  		msgs[i].nlmsg_pid = 0;
     178  	}
     179  
     180  	rc = sendto(fd, msgs, msg_len, MSG_DONTWAIT, NULL, 0);
     181  	errstr = sprintrc(rc);
     182  	printf("sendto(%d, [", fd);
     183  	for (unsigned int i = 0; i < DEFAULT_STRLEN; ++i) {
     184  		if (i)
     185  			printf(", ");
     186  		printf("{nlmsg_len=%u, nlmsg_type=NLMSG_NOOP"
     187  		       ", nlmsg_flags=NLM_F_REQUEST|0x%x"
     188  		       ", nlmsg_seq=%u, nlmsg_pid=0}",
     189  		       msgs[i].nlmsg_len, NLM_F_DUMP, msgs[i].nlmsg_seq);
     190  	}
     191  	printf(", ...], %u, MSG_DONTWAIT, NULL, 0) = %s\n", msg_len, errstr);
     192  }
     193  
     194  static void
     195  test_nlmsgerr(const int fd)
     196  {
     197  	struct nlmsgerr *err;
     198  	struct nlmsghdr *nlh;
     199  	void *const nlh0 = midtail_alloc(NLMSG_HDRLEN, sizeof(*err) + 4);
     200  	long rc;
     201  	const char *rcstr;
     202  
     203  	/* error message with nlmsg_len exceeding the allocated room */
     204  	nlh = nlh0;
     205  	nlh->nlmsg_len = NLMSG_HDRLEN + 4;
     206  	nlh->nlmsg_type = NLMSG_ERROR;
     207  	nlh->nlmsg_flags = NLM_F_REQUEST;
     208  	nlh->nlmsg_seq = 0;
     209  	nlh->nlmsg_pid = 0;
     210  
     211  	rc = sendto(fd, nlh, nlh->nlmsg_len, MSG_DONTWAIT, NULL, 0);
     212  	printf("sendto(%d, [{nlmsg_len=%u, nlmsg_type=NLMSG_ERROR"
     213  	       ", nlmsg_flags=NLM_F_REQUEST, nlmsg_seq=0, nlmsg_pid=0}"
     214  	       ", %p], %u, MSG_DONTWAIT, NULL, 0) = %s\n",
     215  	       fd, nlh->nlmsg_len, nlh0 + NLMSG_HDRLEN,
     216  	       nlh->nlmsg_len, sprintrc(rc));
     217  
     218  	/* error message without enough room for the error code */
     219  	nlh->nlmsg_len = NLMSG_HDRLEN + 2;
     220  	nlh = nlh0 - 2;
     221  	memmove(nlh, nlh0, sizeof(*nlh));
     222  	memcpy(NLMSG_DATA(nlh), "42", 2);
     223  
     224  	rc = sendto(fd, nlh, NLMSG_HDRLEN + 2, MSG_DONTWAIT, NULL, 0);
     225  	printf("sendto(%d, [{nlmsg_len=%u, nlmsg_type=NLMSG_ERROR"
     226  	       ", nlmsg_flags=NLM_F_REQUEST, nlmsg_seq=0, nlmsg_pid=0}"
     227  	       ", \"\\x34\\x32\"], %u, MSG_DONTWAIT, NULL, 0) = %s\n",
     228  	       fd, NLMSG_HDRLEN + 2, NLMSG_HDRLEN + 2, sprintrc(rc));
     229  
     230  	/* error message with room for the error code only */
     231  	nlh = nlh0 - sizeof(err->error);
     232  	nlh->nlmsg_len = NLMSG_HDRLEN + sizeof(err->error);
     233  	nlh->nlmsg_type = NLMSG_ERROR;
     234  	nlh->nlmsg_flags = NLM_F_REQUEST;
     235  	nlh->nlmsg_seq = 0;
     236  	nlh->nlmsg_pid = 0;
     237  	err = NLMSG_DATA(nlh);
     238  	fill_memory(&err->error, sizeof(err->error));
     239  
     240  	rc = sendto(fd, nlh, nlh->nlmsg_len, MSG_DONTWAIT, NULL, 0);
     241  	rcstr = sprintrc(rc);
     242  	printf("sendto(%d, [{nlmsg_len=%u, nlmsg_type=NLMSG_ERROR"
     243  	       ", nlmsg_flags=NLM_F_REQUEST, nlmsg_seq=0, nlmsg_pid=0}, ",
     244  	       fd, nlh->nlmsg_len);
     245  	print_quoted_hex(&err->error, sizeof(err->error));
     246  	printf("], %u, MSG_DONTWAIT, NULL, 0) = %s\n", nlh->nlmsg_len, rcstr);
     247  
     248  	/* error message without enough room for the whole struct nlmsgerr */
     249  	nlh = nlh0 - (sizeof(*err) - 4);
     250  	nlh->nlmsg_len = NLMSG_HDRLEN + (sizeof(*err) - 4);
     251  	nlh->nlmsg_type = NLMSG_ERROR;
     252  	nlh->nlmsg_flags = NLM_F_REQUEST;
     253  	nlh->nlmsg_seq = 0;
     254  	nlh->nlmsg_pid = 0;
     255  	err = NLMSG_DATA(nlh);
     256  	fill_memory(err, sizeof(*err) - 4);
     257  
     258  	rc = sendto(fd, nlh, nlh->nlmsg_len, MSG_DONTWAIT, NULL, 0);
     259  	rcstr = sprintrc(rc);
     260  	printf("sendto(%d, [{nlmsg_len=%u, nlmsg_type=NLMSG_ERROR"
     261  	       ", nlmsg_flags=NLM_F_REQUEST, nlmsg_seq=0, nlmsg_pid=0}, ",
     262  	       fd, nlh->nlmsg_len);
     263  	print_quoted_hex(err, sizeof(*err) - 4);
     264  	printf("], %u, MSG_DONTWAIT, NULL, 0) = %s\n", nlh->nlmsg_len, rcstr);
     265  
     266  	/* error message with nlmsg_len exceeding the allocated room */
     267  	nlh->nlmsg_len = NLMSG_HDRLEN + sizeof(*err);
     268  
     269  	rc = sendto(fd, nlh, nlh->nlmsg_len, MSG_DONTWAIT, NULL, 0);
     270  	printf("sendto(%d, [{nlmsg_len=%u, nlmsg_type=NLMSG_ERROR"
     271  	       ", nlmsg_flags=NLM_F_REQUEST, nlmsg_seq=0, nlmsg_pid=0}"
     272  	       ", %p], %u, MSG_DONTWAIT, NULL, 0) = %s\n",
     273  	       fd, nlh->nlmsg_len, err, nlh->nlmsg_len, sprintrc(rc));
     274  
     275  	/* error message with room for the error code and a header */
     276  	nlh = nlh0 - sizeof(*err);
     277  	nlh->nlmsg_len = NLMSG_HDRLEN + sizeof(*err);
     278  	nlh->nlmsg_type = NLMSG_ERROR;
     279  	nlh->nlmsg_flags = NLM_F_REQUEST;
     280  	nlh->nlmsg_seq = 0;
     281  	nlh->nlmsg_pid = 0;
     282  	err = NLMSG_DATA(nlh);
     283  	err->error = -13;
     284  	err->msg.nlmsg_len = NLMSG_HDRLEN;
     285  	err->msg.nlmsg_type = NLMSG_NOOP;
     286  	err->msg.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
     287  	err->msg.nlmsg_seq = 42;
     288  	err->msg.nlmsg_pid = 1234;
     289  
     290  	rc = sendto(fd, nlh, nlh->nlmsg_len, MSG_DONTWAIT, NULL, 0);
     291  	printf("sendto(%d, [{nlmsg_len=%u, nlmsg_type=NLMSG_ERROR"
     292  	       ", nlmsg_flags=NLM_F_REQUEST, nlmsg_seq=0, nlmsg_pid=0}"
     293  	       ", {error=-EACCES, msg={nlmsg_len=%u, nlmsg_type=NLMSG_NOOP"
     294  	       ", nlmsg_flags=NLM_F_REQUEST|0x%x, nlmsg_seq=%u, nlmsg_pid=%d}}]"
     295  	       ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
     296  	       fd, nlh->nlmsg_len, err->msg.nlmsg_len, NLM_F_DUMP,
     297  	       err->msg.nlmsg_seq, err->msg.nlmsg_pid,
     298  	       nlh->nlmsg_len, sprintrc(rc));
     299  
     300  	/* err->msg.nlmsg_len < sizeof(err->msg) */
     301  	err->msg.nlmsg_len = sizeof(err->msg.nlmsg_len);
     302  
     303  	rc = sendto(fd, nlh, nlh->nlmsg_len, MSG_DONTWAIT, NULL, 0);
     304  	printf("sendto(%d, [{nlmsg_len=%u, nlmsg_type=NLMSG_ERROR"
     305  	       ", nlmsg_flags=NLM_F_REQUEST, nlmsg_seq=0, nlmsg_pid=0}"
     306  	       ", {error=-EACCES, msg={nlmsg_len=%u, nlmsg_type=NLMSG_NOOP"
     307  	       ", nlmsg_flags=NLM_F_REQUEST|0x%x, nlmsg_seq=%u, nlmsg_pid=%d}}]"
     308  	       ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
     309  	       fd, nlh->nlmsg_len, err->msg.nlmsg_len, NLM_F_DUMP,
     310  	       err->msg.nlmsg_seq, err->msg.nlmsg_pid,
     311  	       nlh->nlmsg_len, sprintrc(rc));
     312  
     313  	/* nlh->nlmsg_len < NLMSG_HDRLEN + err->msg.nlmsg_len */
     314  	err->msg.nlmsg_len = NLMSG_HDRLEN + 4;
     315  
     316  	rc = sendto(fd, nlh, nlh->nlmsg_len, MSG_DONTWAIT, NULL, 0);
     317  	printf("sendto(%d, [{nlmsg_len=%u, nlmsg_type=NLMSG_ERROR"
     318  	       ", nlmsg_flags=NLM_F_REQUEST, nlmsg_seq=0, nlmsg_pid=0}"
     319  	       ", {error=-EACCES, msg={nlmsg_len=%u, nlmsg_type=NLMSG_NOOP"
     320  	       ", nlmsg_flags=NLM_F_REQUEST|0x%x, nlmsg_seq=%u, nlmsg_pid=%d}}]"
     321  	       ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
     322  	       fd, nlh->nlmsg_len, err->msg.nlmsg_len, NLM_F_DUMP,
     323  	       err->msg.nlmsg_seq, err->msg.nlmsg_pid,
     324  	       nlh->nlmsg_len, sprintrc(rc));
     325  
     326  	/* error message with room for the error code, a header, and some data */
     327  	nlh = nlh0 - sizeof(*err) - 4;
     328  	nlh->nlmsg_len = NLMSG_HDRLEN + sizeof(*err) + 4;
     329  	nlh->nlmsg_type = NLMSG_ERROR;
     330  	nlh->nlmsg_flags = NLM_F_REQUEST;
     331  	nlh->nlmsg_seq = 0;
     332  	nlh->nlmsg_pid = 0;
     333  	err = NLMSG_DATA(nlh);
     334  	err->error = -13;
     335  	err->msg.nlmsg_len = NLMSG_HDRLEN + 4;
     336  	err->msg.nlmsg_type = NLMSG_NOOP;
     337  	err->msg.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
     338  	err->msg.nlmsg_seq = 421;
     339  	err->msg.nlmsg_pid = 12345;
     340  	memcpy(NLMSG_DATA(&err->msg), "abcd", 4);
     341  
     342  	rc = sendto(fd, nlh, nlh->nlmsg_len, MSG_DONTWAIT, NULL, 0);
     343  	printf("sendto(%d, [{nlmsg_len=%u, nlmsg_type=NLMSG_ERROR"
     344  	       ", nlmsg_flags=NLM_F_REQUEST, nlmsg_seq=0, nlmsg_pid=0}"
     345  	       ", {error=-EACCES, msg=[{nlmsg_len=%u, nlmsg_type=NLMSG_NOOP"
     346  	       ", nlmsg_flags=NLM_F_REQUEST|0x%x, nlmsg_seq=%u, nlmsg_pid=%d}"
     347  	       ", \"\\x61\\x62\\x63\\x64\"]}], %u, MSG_DONTWAIT, NULL, 0)"
     348  	       " = %s\n",
     349  	       fd, nlh->nlmsg_len, err->msg.nlmsg_len, NLM_F_DUMP,
     350  	       err->msg.nlmsg_seq, err->msg.nlmsg_pid,
     351  	       nlh->nlmsg_len, sprintrc(rc));
     352  
     353  	nlh->nlmsg_len = NLMSG_HDRLEN + sizeof(*err) + 1;
     354  	err->msg.nlmsg_len = NLMSG_HDRLEN + 1;
     355  	err->msg.nlmsg_type = SOCK_DIAG_BY_FAMILY;
     356  	err->msg.nlmsg_flags = NLM_F_REQUEST;
     357  	err->msg.nlmsg_seq = 4213;
     358  	err->msg.nlmsg_pid = 123456;
     359  	memcpy(NLMSG_DATA(&err->msg), "", 1);
     360  
     361  	rc = sendto(fd, nlh, nlh->nlmsg_len, MSG_DONTWAIT, NULL, 0);
     362  	printf("sendto(%d, [{nlmsg_len=%u, nlmsg_type=NLMSG_ERROR"
     363  	       ", nlmsg_flags=NLM_F_REQUEST, nlmsg_seq=0, nlmsg_pid=0}"
     364  	       ", {error=-EACCES, msg=[{nlmsg_len=%u"
     365  	       ", nlmsg_type=SOCK_DIAG_BY_FAMILY, nlmsg_flags=NLM_F_REQUEST"
     366  	       ", nlmsg_seq=%u, nlmsg_pid=%d}, {family=AF_UNSPEC}]}]"
     367  	       ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
     368  	       fd, nlh->nlmsg_len, err->msg.nlmsg_len,
     369  	       err->msg.nlmsg_seq, err->msg.nlmsg_pid,
     370  	       nlh->nlmsg_len, sprintrc(rc));
     371  }
     372  
     373  static void
     374  test_nlmsg_done(const int fd)
     375  {
     376  	struct nlmsghdr *nlh;
     377  	const int num = 0xfacefeed;
     378  	void *const nlh0 = midtail_alloc(NLMSG_HDRLEN, sizeof(num));
     379  	long rc;
     380  
     381  	/* NLMSG_DONE message without enough room for an integer payload */
     382  	nlh = nlh0;
     383  	*nlh = (struct nlmsghdr) {
     384  		.nlmsg_len = NLMSG_HDRLEN + sizeof(num),
     385  		.nlmsg_type = NLMSG_DONE,
     386  		.nlmsg_flags = NLM_F_MULTI
     387  	};
     388  
     389  	rc = sendto(fd, nlh, nlh->nlmsg_len, MSG_DONTWAIT, NULL, 0);
     390  	printf("sendto(%d, [{nlmsg_len=%u, nlmsg_type=NLMSG_DONE"
     391  	       ", nlmsg_flags=NLM_F_MULTI, nlmsg_seq=0, nlmsg_pid=0}, %p]"
     392  	       ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
     393  	       fd, nlh->nlmsg_len, nlh0 + NLMSG_HDRLEN,
     394  	       nlh->nlmsg_len, sprintrc(rc));
     395  
     396  	/* NLMSG_DONE message with enough room for an oddly short payload */
     397  	nlh->nlmsg_len = NLMSG_HDRLEN + 2;
     398  	nlh = nlh0 - 2;
     399  	/* Beware of unaligned access to nlh members. */
     400  	memmove(nlh, nlh0, sizeof(*nlh));
     401  	memcpy(NLMSG_DATA(nlh), "42", 2);
     402  
     403  	rc = sendto(fd, nlh, NLMSG_HDRLEN + 2, MSG_DONTWAIT, NULL, 0);
     404  	printf("sendto(%d, [{nlmsg_len=%u, nlmsg_type=NLMSG_DONE"
     405  	       ", nlmsg_flags=NLM_F_MULTI, nlmsg_seq=0, nlmsg_pid=0}"
     406  	       ", \"\\x34\\x32\"], %u, MSG_DONTWAIT, NULL, 0) = %s\n",
     407  	       fd, NLMSG_HDRLEN + 2, NLMSG_HDRLEN + 2, sprintrc(rc));
     408  
     409  	/* NLMSG_DONE message with enough room for an integer payload */
     410  	nlh = nlh0 - sizeof(num);
     411  	*nlh = (struct nlmsghdr) {
     412  		.nlmsg_len = NLMSG_HDRLEN + sizeof(num),
     413  		.nlmsg_type = NLMSG_DONE,
     414  		.nlmsg_flags = NLM_F_MULTI
     415  	};
     416  	memcpy(NLMSG_DATA(nlh), &num, sizeof(num));
     417  
     418  	rc = sendto(fd, nlh, nlh->nlmsg_len, MSG_DONTWAIT, NULL, 0);
     419  	printf("sendto(%d, [{nlmsg_len=%u, nlmsg_type=NLMSG_DONE"
     420  	       ", nlmsg_flags=NLM_F_MULTI, nlmsg_seq=0, nlmsg_pid=0}, %d]"
     421  	       ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
     422  	       fd, nlh->nlmsg_len, num, nlh->nlmsg_len, sprintrc(rc));
     423  }
     424  
     425  static void
     426  test_ack_flags(const int fd)
     427  {
     428  	long rc;
     429  	struct nlmsghdr nlh = {
     430  		.nlmsg_len = sizeof(nlh),
     431  		.nlmsg_type = NLMSG_ERROR,
     432  	};
     433  
     434  	nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CAPPED,
     435  	rc = sendto(fd, &nlh, sizeof(nlh), MSG_DONTWAIT, NULL, 0);
     436  	printf("sendto(%d, {nlmsg_len=%u, nlmsg_type=NLMSG_ERROR"
     437  	       ", nlmsg_flags=NLM_F_REQUEST|NLM_F_CAPPED, nlmsg_seq=0"
     438  	       ", nlmsg_pid=0}, %u, MSG_DONTWAIT, NULL, 0) = %s\n",
     439  	       fd, nlh.nlmsg_len, (unsigned) sizeof(nlh), sprintrc(rc));
     440  
     441  	nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK_TLVS;
     442  	rc = sendto(fd, &nlh, sizeof(nlh), MSG_DONTWAIT, NULL, 0);
     443  	printf("sendto(%d, {nlmsg_len=%u, nlmsg_type=NLMSG_ERROR"
     444  	       ", nlmsg_flags=NLM_F_REQUEST|NLM_F_ACK_TLVS, nlmsg_seq=0"
     445  	       ", nlmsg_pid=0}, %u, MSG_DONTWAIT, NULL, 0) = %s\n",
     446  	       fd, nlh.nlmsg_len, (unsigned) sizeof(nlh), sprintrc(rc));
     447  
     448  	nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_CAPPED | NLM_F_ACK_TLVS;
     449  	rc = sendto(fd, &nlh, sizeof(nlh), MSG_DONTWAIT, NULL, 0);
     450  	printf("sendto(%d, {nlmsg_len=%u, nlmsg_type=NLMSG_ERROR"
     451  	       ", nlmsg_flags=NLM_F_REQUEST|NLM_F_CAPPED|NLM_F_ACK_TLVS"
     452  	       ", nlmsg_seq=0, nlmsg_pid=0}, %u, MSG_DONTWAIT, NULL, 0) = %s\n",
     453  	       fd, nlh.nlmsg_len, (unsigned) sizeof(nlh), sprintrc(rc));
     454  }
     455  
     456  int main(void)
     457  {
     458  	const int fd = create_nl_socket(NETLINK_SOCK_DIAG);
     459  
     460  	char *path = xasprintf("/proc/self/fd/%u", fd);
     461  	char buf[256];
     462  	if (getxattr(path, "system.sockprotoname", buf, sizeof(buf) - 1) < 0)
     463  		perror_msg_and_skip("getxattr");
     464  	free(path);
     465  
     466  	send_query(fd);
     467  	test_nlmsgerr(fd);
     468  	test_nlmsg_done(fd);
     469  	test_ack_flags(fd);
     470  
     471  	puts("+++ exited with 0 +++");
     472  	return 0;
     473  }
     474  
     475  #else
     476  
     477  SKIP_MAIN_UNDEFINED("HAVE_SYS_XATTR_H")
     478  
     479  #endif